UNPKG

4.11 MBJavaScriptView Raw
1/*
2 * Power BI Visualizations
3 *
4 * Copyright (c) Microsoft Corporation
5 * All rights reserved.
6 * MIT License
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the ""Software""), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26///<reference path="../../Typedefs/jquery/jquery.d.ts"/>
27/*
28 * Power BI Visualizations
29 *
30 * Copyright (c) Microsoft Corporation
31 * All rights reserved.
32 * MIT License
33 *
34 * Permission is hereby granted, free of charge, to any person obtaining a copy
35 * of this software and associated documentation files (the ""Software""), to deal
36 * in the Software without restriction, including without limitation the rights
37 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 * copies of the Software, and to permit persons to whom the Software is
39 * furnished to do so, subject to the following conditions:
40 *
41 * The above copyright notice and this permission notice shall be included in
42 * all copies or substantial portions of the Software.
43 *
44 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50 * THE SOFTWARE.
51 */
52var powerbi;
53(function (powerbi) {
54 (function (VisualDataRoleKind) {
55 /** Indicates that the role should be bound to something that evaluates to a grouping of values. */
56 VisualDataRoleKind[VisualDataRoleKind["Grouping"] = 0] = "Grouping";
57 /** Indicates that the role should be bound to something that evaluates to a single value in a scope. */
58 VisualDataRoleKind[VisualDataRoleKind["Measure"] = 1] = "Measure";
59 /** Indicates that the role can be bound to either Grouping or Measure. */
60 VisualDataRoleKind[VisualDataRoleKind["GroupingOrMeasure"] = 2] = "GroupingOrMeasure";
61 })(powerbi.VisualDataRoleKind || (powerbi.VisualDataRoleKind = {}));
62 var VisualDataRoleKind = powerbi.VisualDataRoleKind;
63 (function (VisualDataChangeOperationKind) {
64 VisualDataChangeOperationKind[VisualDataChangeOperationKind["Create"] = 0] = "Create";
65 VisualDataChangeOperationKind[VisualDataChangeOperationKind["Append"] = 1] = "Append";
66 })(powerbi.VisualDataChangeOperationKind || (powerbi.VisualDataChangeOperationKind = {}));
67 var VisualDataChangeOperationKind = powerbi.VisualDataChangeOperationKind;
68 (function (VisualUpdateType) {
69 VisualUpdateType[VisualUpdateType["Data"] = 2] = "Data";
70 VisualUpdateType[VisualUpdateType["Resize"] = 4] = "Resize";
71 VisualUpdateType[VisualUpdateType["ViewMode"] = 8] = "ViewMode";
72 VisualUpdateType[VisualUpdateType["Style"] = 16] = "Style";
73 VisualUpdateType[VisualUpdateType["ResizeEnd"] = 32] = "ResizeEnd";
74 })(powerbi.VisualUpdateType || (powerbi.VisualUpdateType = {}));
75 var VisualUpdateType = powerbi.VisualUpdateType;
76 (function (VisualPermissions) {
77 })(powerbi.VisualPermissions || (powerbi.VisualPermissions = {}));
78 var VisualPermissions = powerbi.VisualPermissions;
79 var visuals;
80 (function (visuals) {
81 var telemetry;
82 (function (telemetry) {
83 (function (ErrorSource) {
84 ErrorSource[ErrorSource["PowerBI"] = 0] = "PowerBI";
85 ErrorSource[ErrorSource["External"] = 1] = "External";
86 ErrorSource[ErrorSource["User"] = 2] = "User";
87 })(telemetry.ErrorSource || (telemetry.ErrorSource = {}));
88 var ErrorSource = telemetry.ErrorSource;
89 })(telemetry = visuals.telemetry || (visuals.telemetry = {}));
90 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
91})(powerbi || (powerbi = {}));
92
93
94;/*
95 * Power BI Visualizations
96 *
97 * Copyright (c) Microsoft Corporation
98 * All rights reserved.
99 * MIT License
100 *
101 * Permission is hereby granted, free of charge, to any person obtaining a copy
102 * of this software and associated documentation files (the ""Software""), to deal
103 * in the Software without restriction, including without limitation the rights
104 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105 * copies of the Software, and to permit persons to whom the Software is
106 * furnished to do so, subject to the following conditions:
107 *
108 * The above copyright notice and this permission notice shall be included in
109 * all copies or substantial portions of the Software.
110 *
111 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
112 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
113 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
114 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
115 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
116 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
117 * THE SOFTWARE.
118 */
119///<reference path="../../Typedefs/jquery/jquery.d.ts"/>
120///<reference path="../../Typedefs/globalize/globalize.d.ts"/>
121///<reference path="../../Typedefs/lodash/lodash.d.ts"/>
122/*
123 * Power BI Visualizations
124 *
125 * Copyright (c) Microsoft Corporation
126 * All rights reserved.
127 * MIT License
128 *
129 * Permission is hereby granted, free of charge, to any person obtaining a copy
130 * of this software and associated documentation files (the ""Software""), to deal
131 * in the Software without restriction, including without limitation the rights
132 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
133 * copies of the Software, and to permit persons to whom the Software is
134 * furnished to do so, subject to the following conditions:
135 *
136 * The above copyright notice and this permission notice shall be included in
137 * all copies or substantial portions of the Software.
138 *
139 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
140 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
141 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
142 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
144 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
145 * THE SOFTWARE.
146 */
147var powerbi;
148(function (powerbi) {
149 var visuals;
150 (function (visuals) {
151 var telemetry;
152 (function (telemetry) {
153 /**
154 * Creates a client-side Guid string.
155 * @returns A string representation of a Guid.
156 */
157 function generateGuid() {
158 var guid = "", idx = 0;
159 for (idx = 0; idx < 32; idx += 1) {
160 var guidDigitsItem = Math.random() * 16 | 0;
161 switch (idx) {
162 case 8:
163 case 12:
164 case 16:
165 case 20:
166 guid += "-";
167 break;
168 }
169 guid += guidDigitsItem.toString(16);
170 }
171 return guid;
172 }
173 telemetry.generateGuid = generateGuid;
174 })(telemetry = visuals.telemetry || (visuals.telemetry = {}));
175 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
176})(powerbi || (powerbi = {}));
177/*
178 * Power BI Visualizations
179 *
180 * Copyright (c) Microsoft Corporation
181 * All rights reserved.
182 * MIT License
183 *
184 * Permission is hereby granted, free of charge, to any person obtaining a copy
185 * of this software and associated documentation files (the ""Software""), to deal
186 * in the Software without restriction, including without limitation the rights
187 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
188 * copies of the Software, and to permit persons to whom the Software is
189 * furnished to do so, subject to the following conditions:
190 *
191 * The above copyright notice and this permission notice shall be included in
192 * all copies or substantial portions of the Software.
193 *
194 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
195 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
196 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
197 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
199 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
200 * THE SOFTWARE.
201 */
202var powerbi;
203(function (powerbi) {
204 var visuals;
205 (function (visuals) {
206 var telemetry;
207 (function (telemetry) {
208 telemetry.ExtensibilityVisualApiUsage = function (name, apiVersion, custom, parentId, isError, errorSource, errorCode) {
209 if (isError === void 0) { isError = false; }
210 if (errorSource === void 0) { errorSource = undefined; }
211 if (errorCode === void 0) { errorCode = undefined; }
212 var info = {
213 name: name,
214 apiVersion: apiVersion,
215 custom: custom,
216 parentId: parentId,
217 isError: isError,
218 errorSource: errorSource,
219 errorCode: errorCode,
220 };
221 var event = {
222 name: 'PBI.Extensibility.VisualApiUsage',
223 category: 1 /* CustomerAction */,
224 time: Date.now(),
225 id: telemetry.generateGuid(),
226 getFormattedInfoObject: function () {
227 var formattedObject = {
228 name: info.name,
229 apiVersion: info.apiVersion,
230 custom: info.custom,
231 parentId: info.parentId,
232 isError: info.isError,
233 };
234 if (typeof info.errorSource !== 'undefined') {
235 formattedObject['errorSource'] = telemetry.ErrorSource[info.errorSource];
236 }
237 if (typeof info.errorCode !== 'undefined') {
238 formattedObject['errorCode'] = info.errorCode;
239 }
240 return formattedObject;
241 },
242 info: info,
243 privateFields: [],
244 orgInfoFields: []
245 };
246 if (typeof telemetry.ExtensibilityVisualApiUsageLoggers !== 'undefined') {
247 event.loggers = telemetry.ExtensibilityVisualApiUsageLoggers;
248 }
249 return event;
250 };
251 telemetry.VisualException = function (visualType, isCustom, apiVersion, source, lineNumber, columnNumber, stack, message) {
252 var info = {
253 visualType: visualType,
254 isCustom: isCustom,
255 apiVersion: apiVersion,
256 source: source,
257 lineNumber: lineNumber,
258 columnNumber: columnNumber,
259 stack: stack,
260 message: message,
261 };
262 var event = {
263 name: 'PBI.VisualException',
264 category: 2 /* CriticalError */,
265 time: Date.now(),
266 id: telemetry.generateGuid(),
267 getFormattedInfoObject: function () {
268 var formattedObject = {
269 visualType: info.visualType,
270 isCustom: info.isCustom,
271 apiVersion: info.apiVersion,
272 source: info.source,
273 lineNumber: info.lineNumber,
274 columnNumber: info.columnNumber,
275 stack: info.stack,
276 message: info.message,
277 };
278 return formattedObject;
279 },
280 info: info,
281 privateFields: [],
282 orgInfoFields: []
283 };
284 if (typeof telemetry.VisualExceptionLoggers !== 'undefined') {
285 event.loggers = telemetry.VisualExceptionLoggers;
286 }
287 return event;
288 };
289 })(telemetry = visuals.telemetry || (visuals.telemetry = {}));
290 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
291})(powerbi || (powerbi = {}));
292/*
293 * Power BI Visualizations
294 *
295 * Copyright (c) Microsoft Corporation
296 * All rights reserved.
297 * MIT License
298 *
299 * Permission is hereby granted, free of charge, to any person obtaining a copy
300 * of this software and associated documentation files (the ""Software""), to deal
301 * in the Software without restriction, including without limitation the rights
302 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
303 * copies of the Software, and to permit persons to whom the Software is
304 * furnished to do so, subject to the following conditions:
305 *
306 * The above copyright notice and this permission notice shall be included in
307 * all copies or substantial portions of the Software.
308 *
309 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
310 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
311 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
312 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
313 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
314 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
315 * THE SOFTWARE.
316 */
317var powerbi;
318(function (powerbi) {
319 var extensibility;
320 (function (extensibility) {
321 function VisualPlugin(options) {
322 return function (constructor) {
323 constructor.__capabilities__ = options.capabilities;
324 };
325 }
326 extensibility.VisualPlugin = VisualPlugin;
327 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
328})(powerbi || (powerbi = {}));
329/*
330* Power BI Visualizations
331*
332* Copyright (c) Microsoft Corporation
333* All rights reserved.
334* MIT License
335*
336* Permission is hereby granted, free of charge, to any person obtaining a copy
337* of this software and associated documentation files (the ""Software""), to deal
338* in the Software without restriction, including without limitation the rights
339* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
340* copies of the Software, and to permit persons to whom the Software is
341* furnished to do so, subject to the following conditions:
342*
343* The above copyright notice and this permission notice shall be included in
344* all copies or substantial portions of the Software.
345*
346* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
347* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
348* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
349* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
350* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
351* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
352* THE SOFTWARE.
353*/
354var powerbi;
355(function (powerbi) {
356 var extensibility;
357 (function (extensibility) {
358 ;
359 var SelectionManager = (function () {
360 function SelectionManager(options) {
361 this.hostServices = options.hostServices;
362 this.selectedIds = [];
363 this.promiseFactory = this.hostServices.promiseFactory();
364 }
365 SelectionManager.prototype.select = function (selectionId, multiSelect) {
366 if (multiSelect === void 0) { multiSelect = false; }
367 var deferred = this.promiseFactory.defer();
368 if (this.hostServices.shouldRetainSelection()) {
369 this.sendSelectionToHost([selectionId]);
370 }
371 else {
372 this.selectInternal(selectionId, multiSelect);
373 this.sendSelectionToHost(this.selectedIds);
374 }
375 deferred.resolve(this.selectedIds);
376 return deferred.promise;
377 };
378 SelectionManager.prototype.showContextMenu = function (selectionId, position) {
379 var deferred = this.promiseFactory.defer();
380 this.sendContextMenuToHost(selectionId, position);
381 deferred.resolve(null);
382 return deferred.promise;
383 };
384 SelectionManager.prototype.hasSelection = function () {
385 return this.selectedIds.length > 0;
386 };
387 SelectionManager.prototype.clear = function () {
388 var deferred = this.promiseFactory.defer();
389 this.selectedIds = [];
390 this.sendSelectionToHost([]);
391 deferred.resolve(null);
392 return deferred.promise;
393 };
394 SelectionManager.prototype.getSelectionIds = function () {
395 return this.selectedIds;
396 };
397 SelectionManager.prototype.sendSelectionToHost = function (ids) {
398 var selectArgs = {
399 data: ids
400 .filter(function (value) { return value.hasIdentity(); })
401 .map(function (value) { return value.getSelector(); })
402 };
403 var data2 = this.getSelectorsByColumn(ids);
404 if (!_.isEmpty(data2))
405 selectArgs.data2 = data2;
406 this.hostServices.onSelect(selectArgs);
407 };
408 SelectionManager.prototype.sendContextMenuToHost = function (selectionId, position) {
409 var selectors = this.getSelectorsByColumn([selectionId]);
410 if (_.isEmpty(selectors))
411 return;
412 var args = {
413 data: selectors,
414 position: position
415 };
416 this.hostServices.onContextMenu(args);
417 };
418 SelectionManager.prototype.getSelectorsByColumn = function (selectionIds) {
419 return _(selectionIds)
420 .filter(function (value) { return value.hasIdentity; })
421 .map(function (value) { return value.getSelectorsByColumn(); })
422 .compact()
423 .value();
424 };
425 SelectionManager.prototype.selectInternal = function (selectionId, multiSelect) {
426 if (SelectionManager.containsSelection(this.selectedIds, selectionId)) {
427 this.selectedIds = multiSelect
428 ? this.selectedIds.filter(function (d) { return !selectionId.equals(d); })
429 : this.selectedIds.length > 1
430 ? [selectionId] : [];
431 }
432 else {
433 if (multiSelect)
434 this.selectedIds.push(selectionId);
435 else
436 this.selectedIds = [selectionId];
437 }
438 };
439 SelectionManager.containsSelection = function (list, id) {
440 return list.some(function (d) { return id.equals(d); });
441 };
442 return SelectionManager;
443 }());
444 extensibility.SelectionManager = SelectionManager;
445 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
446})(powerbi || (powerbi = {}));
447/*
448 * Power BI Visualizations
449 *
450 * Copyright (c) Microsoft Corporation
451 * All rights reserved.
452 * MIT License
453 *
454 * Permission is hereby granted, free of charge, to any person obtaining a copy
455 * of this software and associated documentation files (the ""Software""), to deal
456 * in the Software without restriction, including without limitation the rights
457 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
458 * copies of the Software, and to permit persons to whom the Software is
459 * furnished to do so, subject to the following conditions:
460 *
461 * The above copyright notice and this permission notice shall be included in
462 * all copies or substantial portions of the Software.
463 *
464 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
465 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
466 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
467 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
468 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
469 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
470 * THE SOFTWARE.
471 */
472var powerbi;
473(function (powerbi) {
474 var extensibility;
475 (function (extensibility) {
476 /**
477 * This class is designed to simplify the creation of SelectionId objects
478 * It allows chaining to build up an object before calling 'create' to build a SelectionId
479 */
480 var SelectionIdBuilder = (function () {
481 function SelectionIdBuilder() {
482 }
483 SelectionIdBuilder.prototype.withCategory = function (categoryColumn, index) {
484 if (categoryColumn && categoryColumn.source && categoryColumn.source.queryName && categoryColumn.identity)
485 this.ensureDataMap()[categoryColumn.source.queryName] = categoryColumn.identity[index];
486 return this;
487 };
488 SelectionIdBuilder.prototype.withSeries = function (seriesColumn, valueColumn) {
489 if (seriesColumn && seriesColumn.source && seriesColumn.source.queryName && valueColumn)
490 this.ensureDataMap()[seriesColumn.source.queryName] = valueColumn.identity;
491 return this;
492 };
493 SelectionIdBuilder.prototype.withMeasure = function (measureId) {
494 this.measure = measureId;
495 return this;
496 };
497 SelectionIdBuilder.prototype.createSelectionId = function () {
498 return powerbi.visuals.SelectionId.createWithSelectorForColumnAndMeasure(this.ensureDataMap(), this.measure);
499 };
500 SelectionIdBuilder.prototype.ensureDataMap = function () {
501 if (!this.dataMap)
502 this.dataMap = {};
503 return this.dataMap;
504 };
505 return SelectionIdBuilder;
506 }());
507 extensibility.SelectionIdBuilder = SelectionIdBuilder;
508 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
509})(powerbi || (powerbi = {}));
510/*
511 * Power BI Visualizations
512 *
513 * Copyright (c) Microsoft Corporation
514 * All rights reserved.
515 * MIT License
516 *
517 * Permission is hereby granted, free of charge, to any person obtaining a copy
518 * of this software and associated documentation files (the ""Software""), to deal
519 * in the Software without restriction, including without limitation the rights
520 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
521 * copies of the Software, and to permit persons to whom the Software is
522 * furnished to do so, subject to the following conditions:
523 *
524 * The above copyright notice and this permission notice shall be included in
525 * all copies or substantial portions of the Software.
526 *
527 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
528 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
529 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
530 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
531 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
532 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
533 * THE SOFTWARE.
534 */
535var powerbi;
536(function (powerbi) {
537 var extensibility;
538 (function (extensibility) {
539 var ExtensibilityVisualApiUsage = powerbi.visuals.telemetry.ExtensibilityVisualApiUsage;
540 //TODO: refactor this into a service
541 extensibility.visualApiVersions = [];
542 function createVisualAdapter(visualPlugin, telemetryService) {
543 var visualTelemetryInfo = {
544 name: visualPlugin.name,
545 apiVersion: visualPlugin.apiVersion,
546 custom: !!visualPlugin.custom
547 };
548 return new extensibility.VisualSafeExecutionWrapper(new VisualAdapter(visualPlugin, telemetryService), visualTelemetryInfo, telemetryService);
549 }
550 extensibility.createVisualAdapter = createVisualAdapter;
551 var VisualAdapter = (function () {
552 function VisualAdapter(visualPlugin, telemetryService) {
553 this.telemetryService = telemetryService;
554 this.plugin = visualPlugin;
555 var version = visualPlugin.apiVersion;
556 var versionIndex = this.getVersionIndex(version);
557 var isError = false;
558 if (!version) {
559 this.legacy = true;
560 }
561 else if (versionIndex > -1) {
562 this.apiVersionIndex = versionIndex;
563 this.legacy = false;
564 }
565 else {
566 debug.assertFail("The API version '" + version + "' is invalid.");
567 isError = true;
568 }
569 if (this.telemetryService) {
570 this.telemetryService.logEvent(ExtensibilityVisualApiUsage, this.plugin.name, this.plugin.apiVersion, !!this.plugin.custom, undefined, isError, powerbi.visuals.telemetry.ErrorSource.User);
571 }
572 }
573 VisualAdapter.prototype.init = function (options) {
574 debug.assertValue(options.element, "options.element");
575 debug.assertValue(options.host, "options.host");
576 options.element.empty();
577 if (this.legacy) {
578 this.visual = this.plugin.create();
579 this.visualLegacy.init(options);
580 }
581 else {
582 var host = extensibility.visualApiVersions[this.apiVersionIndex].hostAdapter(options.host);
583 this.visual = this.plugin.create({
584 element: options.element.get(0),
585 host: host
586 });
587 this.overloadMethods();
588 }
589 };
590 VisualAdapter.prototype.update = function (options) {
591 if (options.type & powerbi.VisualUpdateType.Resize && this.visualHasMethod('onResizing')) {
592 this.onResizing(options.viewport, options.resizeMode);
593 }
594 else if (this.visualHasMethod('update')) {
595 this.visualLegacy.update(options);
596 }
597 else {
598 if (!options.type || options.type & powerbi.VisualUpdateType.Data) {
599 this.onDataChanged(_.pick(options, ['dataViews', 'operationKind']));
600 }
601 if (options.type & powerbi.VisualUpdateType.ViewMode) {
602 this.onViewModeChanged(options.viewMode);
603 }
604 }
605 };
606 VisualAdapter.prototype.destroy = function () {
607 if (this.visualHasMethod('destroy')) {
608 this.visualLegacy.destroy();
609 }
610 };
611 VisualAdapter.prototype.enumerateObjectInstances = function (options) {
612 if (!this.visualHasMethod('enumerateObjectInstances')) {
613 return;
614 }
615 return this.visualLegacy.enumerateObjectInstances(options);
616 };
617 VisualAdapter.prototype.enumerateObjectRepetition = function () {
618 if (!this.visualHasMethod('enumerateObjectRepetition')) {
619 return;
620 }
621 return this.visualLegacy.enumerateObjectRepetition();
622 };
623 VisualAdapter.prototype.onResizing = function (finalViewport, resizeMode) {
624 if (this.visualHasMethod('onResizing')) {
625 this.visualLegacy.onResizing(finalViewport, resizeMode);
626 }
627 };
628 VisualAdapter.prototype.onDataChanged = function (options) {
629 if (this.visualHasMethod('onDataChanged')) {
630 this.visualLegacy.onDataChanged(options);
631 }
632 };
633 VisualAdapter.prototype.onViewModeChanged = function (viewMode) {
634 if (this.visualHasMethod('onViewModeChanged')) {
635 this.visualLegacy.onViewModeChanged(viewMode);
636 }
637 };
638 VisualAdapter.prototype.onClearSelection = function () {
639 if (this.visualHasMethod('onClearSelection')) {
640 this.visualLegacy.onClearSelection();
641 }
642 };
643 VisualAdapter.prototype.canResizeTo = function (viewport) {
644 if (this.visualHasMethod('canResizeTo')) {
645 return this.visualLegacy.canResizeTo(viewport);
646 }
647 };
648 VisualAdapter.prototype.unwrap = function () {
649 return this.visual;
650 };
651 Object.defineProperty(VisualAdapter.prototype, "visualNew", {
652 get: function () {
653 if (this.legacy)
654 return;
655 return this.visual;
656 },
657 enumerable: true,
658 configurable: true
659 });
660 Object.defineProperty(VisualAdapter.prototype, "visualLegacy", {
661 get: function () {
662 if (!this.legacy)
663 return;
664 return this.visual;
665 },
666 enumerable: true,
667 configurable: true
668 });
669 VisualAdapter.prototype.visualHasMethod = function (methodName) {
670 var visual = this.legacy ? this.visualLegacy : this.visualNew;
671 return visual && _.isFunction(visual[methodName]);
672 };
673 VisualAdapter.prototype.getVersionIndex = function (version) {
674 if (version) {
675 var versionCount = extensibility.visualApiVersions.length;
676 for (var i = 0; i < versionCount; i++) {
677 if (extensibility.visualApiVersions[i].version === version) {
678 return i;
679 }
680 }
681 }
682 return -1;
683 };
684 VisualAdapter.prototype.overloadMethods = function () {
685 var overloads = this.getCompiledOverloads();
686 for (var key in overloads) {
687 this[key] = overloads[key];
688 }
689 };
690 VisualAdapter.prototype.getCompiledOverloads = function () {
691 var overloads = {};
692 var versionIndex = this.apiVersionIndex;
693 var visualNew = this.visualNew;
694 for (var i = 0; i <= versionIndex; i++) {
695 var overloadFactory = extensibility.visualApiVersions[i].overloads;
696 if (_.isFunction(overloadFactory)) {
697 _.assign(overloads, overloadFactory(visualNew));
698 }
699 }
700 return overloads;
701 };
702 return VisualAdapter;
703 }());
704 extensibility.VisualAdapter = VisualAdapter;
705 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
706})(powerbi || (powerbi = {}));
707/*
708 * Power BI Visualizations
709 *
710 * Copyright (c) Microsoft Corporation
711 * All rights reserved.
712 * MIT License
713 *
714 * Permission is hereby granted, free of charge, to any person obtaining a copy
715 * of this software and associated documentation files (the ""Software""), to deal
716 * in the Software without restriction, including without limitation the rights
717 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
718 * copies of the Software, and to permit persons to whom the Software is
719 * furnished to do so, subject to the following conditions:
720 *
721 * The above copyright notice and this permission notice shall be included in
722 * all copies or substantial portions of the Software.
723 *
724 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
725 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
726 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
727 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
728 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
729 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
730 * THE SOFTWARE.
731 */
732var powerbi;
733(function (powerbi) {
734 var extensibility;
735 (function (extensibility) {
736 var VisualException = powerbi.visuals.telemetry.VisualException;
737 var VisualSafeExecutionWrapper = (function () {
738 function VisualSafeExecutionWrapper(wrappedVisual, visualInfo, telemetryService, silent) {
739 this.wrappedVisual = wrappedVisual;
740 this.visualInfo = visualInfo;
741 this.telemetryService = telemetryService;
742 this.silent = silent;
743 }
744 VisualSafeExecutionWrapper.prototype.init = function (options) {
745 var _this = this;
746 if (this.wrappedVisual.init) {
747 this.executeSafely(function () { return _this.wrappedVisual.init(options); });
748 }
749 };
750 VisualSafeExecutionWrapper.prototype.destroy = function () {
751 var _this = this;
752 if (this.wrappedVisual.destroy)
753 this.executeSafely(function () { return _this.wrappedVisual.destroy(); });
754 };
755 VisualSafeExecutionWrapper.prototype.update = function (options) {
756 var _this = this;
757 if (this.wrappedVisual.update)
758 this.executeSafely(function () { return _this.wrappedVisual.update(options); });
759 };
760 VisualSafeExecutionWrapper.prototype.onResizing = function (finalViewport, resizeMode) {
761 var _this = this;
762 if (this.wrappedVisual.onResizing)
763 this.executeSafely(function () { return _this.wrappedVisual.onResizing(finalViewport, resizeMode); });
764 };
765 VisualSafeExecutionWrapper.prototype.onDataChanged = function (options) {
766 var _this = this;
767 if (this.wrappedVisual.onDataChanged)
768 this.executeSafely(function () { return _this.wrappedVisual.onDataChanged(options); });
769 };
770 VisualSafeExecutionWrapper.prototype.onViewModeChanged = function (viewMode) {
771 var _this = this;
772 if (this.wrappedVisual.onViewModeChanged)
773 this.executeSafely(function () { return _this.wrappedVisual.onViewModeChanged(viewMode); });
774 };
775 VisualSafeExecutionWrapper.prototype.onClearSelection = function () {
776 var _this = this;
777 if (this.wrappedVisual.onClearSelection)
778 this.executeSafely(function () { return _this.wrappedVisual.onClearSelection(); });
779 };
780 VisualSafeExecutionWrapper.prototype.canResizeTo = function (viewport) {
781 var _this = this;
782 if (this.wrappedVisual.canResizeTo)
783 return this.executeSafely(function () { return _this.wrappedVisual.canResizeTo(viewport); });
784 };
785 VisualSafeExecutionWrapper.prototype.enumerateObjectInstances = function (options) {
786 var _this = this;
787 if (this.wrappedVisual.enumerateObjectInstances)
788 return this.executeSafely(function () { return _this.wrappedVisual.enumerateObjectInstances(options); });
789 };
790 VisualSafeExecutionWrapper.prototype.enumerateObjectRepetition = function () {
791 var _this = this;
792 if (this.wrappedVisual.enumerateObjectRepetition)
793 return this.executeSafely(function () { return _this.wrappedVisual.enumerateObjectRepetition(); });
794 };
795 VisualSafeExecutionWrapper.prototype.unwrap = function () {
796 var visual = this.wrappedVisual;
797 return visual.unwrap ? visual.unwrap() : visual;
798 };
799 VisualSafeExecutionWrapper.prototype.isCustomVisual = function () {
800 return this.visualInfo.custom;
801 };
802 VisualSafeExecutionWrapper.prototype.executeSafely = function (callback) {
803 try {
804 return callback();
805 }
806 catch (exception) {
807 if (!this.silent) {
808 console.error("Visual exception", exception.stack || exception);
809 }
810 if (this.telemetryService) {
811 this.telemetryService.logEvent(VisualException, this.visualInfo.name, this.visualInfo.custom, this.visualInfo.apiVersion, exception.fileName, exception.lineNumber, exception.columnNumber, exception.stack, exception.message);
812 }
813 }
814 };
815 return VisualSafeExecutionWrapper;
816 }());
817 extensibility.VisualSafeExecutionWrapper = VisualSafeExecutionWrapper;
818 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
819})(powerbi || (powerbi = {}));
820/*
821 * Power BI Visualizations
822 *
823 * Copyright (c) Microsoft Corporation
824 * All rights reserved.
825 * MIT License
826 *
827 * Permission is hereby granted, free of charge, to any person obtaining a copy
828 * of this software and associated documentation files (the ""Software""), to deal
829 * in the Software without restriction, including without limitation the rights
830 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
831 * copies of the Software, and to permit persons to whom the Software is
832 * furnished to do so, subject to the following conditions:
833 *
834 * The above copyright notice and this permission notice shall be included in
835 * all copies or substantial portions of the Software.
836 *
837 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
838 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
839 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
840 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
841 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
842 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
843 * THE SOFTWARE.
844 */
845var powerbi;
846(function (powerbi) {
847 var extensibility;
848 (function (extensibility) {
849 var v100;
850 (function (v100) {
851 var overloadFactory = function (visual) {
852 return {
853 update: function (options) {
854 if (visual.update) {
855 var type = options.type || powerbi.VisualUpdateType.Data;
856 if (type & powerbi.VisualUpdateType.Resize && options.resizeMode === 2 /* Resized */) {
857 type |= powerbi.VisualUpdateType.ResizeEnd;
858 }
859 visual.update({
860 viewport: options.viewport,
861 dataViews: options.dataViews,
862 type: type
863 });
864 }
865 },
866 destroy: function () {
867 if (visual.destroy) {
868 visual.destroy();
869 }
870 },
871 enumerateObjectInstances: function (options) {
872 if (visual.enumerateObjectInstances) {
873 return visual.enumerateObjectInstances(options);
874 }
875 }
876 };
877 };
878 var hostAdapter = function (host) {
879 return {};
880 };
881 extensibility.visualApiVersions.push({
882 version: '1.0.0',
883 overloads: overloadFactory,
884 hostAdapter: hostAdapter
885 });
886 })(v100 = extensibility.v100 || (extensibility.v100 = {}));
887 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
888})(powerbi || (powerbi = {}));
889/*
890 * Power BI Visualizations
891 *
892 * Copyright (c) Microsoft Corporation
893 * All rights reserved.
894 * MIT License
895 *
896 * Permission is hereby granted, free of charge, to any person obtaining a copy
897 * of this software and associated documentation files (the ""Software""), to deal
898 * in the Software without restriction, including without limitation the rights
899 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
900 * copies of the Software, and to permit persons to whom the Software is
901 * furnished to do so, subject to the following conditions:
902 *
903 * The above copyright notice and this permission notice shall be included in
904 * all copies or substantial portions of the Software.
905 *
906 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
907 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
908 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
909 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
910 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
911 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
912 * THE SOFTWARE.
913 */
914var powerbi;
915(function (powerbi) {
916 var extensibility;
917 (function (extensibility) {
918 var v110;
919 (function (v110) {
920 var hostAdapter = function (host) {
921 return {
922 createSelectionIdBuilder: function () { return new powerbi.visuals.SelectionIdBuilder(); },
923 createSelectionManager: function () { return new extensibility.SelectionManager({ hostServices: host }); }
924 };
925 };
926 extensibility.visualApiVersions.push({
927 version: '1.1.0',
928 hostAdapter: hostAdapter
929 });
930 })(v110 = extensibility.v110 || (extensibility.v110 = {}));
931 })(extensibility = powerbi.extensibility || (powerbi.extensibility = {}));
932})(powerbi || (powerbi = {}));
933
934
935;/*
936 * Power BI Visualizations
937 *
938 * Copyright (c) Microsoft Corporation
939 * All rights reserved.
940 * MIT License
941 *
942 * Permission is hereby granted, free of charge, to any person obtaining a copy
943 * of this software and associated documentation files (the ""Software""), to deal
944 * in the Software without restriction, including without limitation the rights
945 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
946 * copies of the Software, and to permit persons to whom the Software is
947 * furnished to do so, subject to the following conditions:
948 *
949 * The above copyright notice and this permission notice shall be included in
950 * all copies or substantial portions of the Software.
951 *
952 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
953 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
954 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
955 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
956 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
957 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
958 * THE SOFTWARE.
959 */
960///<reference path="../../Typedefs/jquery/jquery.d.ts"/>
961///<reference path="../../Typedefs/d3/d3.d.ts"/>
962///<reference path="../../Typedefs/lodash/lodash.d.ts"/>
963/*
964 * Power BI Visualizations
965 *
966 * Copyright (c) Microsoft Corporation
967 * All rights reserved.
968 * MIT License
969 *
970 * Permission is hereby granted, free of charge, to any person obtaining a copy
971 * of this software and associated documentation files (the ""Software""), to deal
972 * in the Software without restriction, including without limitation the rights
973 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
974 * copies of the Software, and to permit persons to whom the Software is
975 * furnished to do so, subject to the following conditions:
976 *
977 * The above copyright notice and this permission notice shall be included in
978 * all copies or substantial portions of the Software.
979 *
980 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
981 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
982 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
983 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
984 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
985 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
986 * THE SOFTWARE.
987 */
988var jsCommon;
989(function (jsCommon) {
990 /**
991 * DOM constants.
992 */
993 var DOMConstants;
994 (function (DOMConstants) {
995 /**
996 * Integer codes corresponding to individual keys on the keyboard.
997 */
998 DOMConstants.escKeyCode = 27;
999 DOMConstants.enterKeyCode = 13;
1000 DOMConstants.tabKeyCode = 9;
1001 DOMConstants.upArrowKeyCode = 38;
1002 DOMConstants.downArrowKeyCode = 40;
1003 DOMConstants.leftArrowKeyCode = 37;
1004 DOMConstants.rightArrowKeyCode = 39;
1005 DOMConstants.homeKeyCode = 36;
1006 DOMConstants.endKeyCode = 35;
1007 DOMConstants.backSpaceKeyCode = 8;
1008 DOMConstants.deleteKeyCode = 46;
1009 DOMConstants.spaceKeyCode = 32;
1010 DOMConstants.shiftKeyCode = 16;
1011 DOMConstants.ctrlKeyCode = 17;
1012 DOMConstants.altKeyCode = 18;
1013 DOMConstants.aKeyCode = 65;
1014 DOMConstants.cKeyCode = 67;
1015 DOMConstants.sKeyCode = 83;
1016 DOMConstants.vKeyCode = 86;
1017 DOMConstants.wKeyCode = 87;
1018 DOMConstants.xKeyCode = 88;
1019 DOMConstants.yKeyCode = 89;
1020 DOMConstants.zKeyCode = 90;
1021 /**
1022 * DOM Elements.
1023 */
1024 DOMConstants.DocumentBody = 'body';
1025 DOMConstants.Anchor = 'a';
1026 DOMConstants.EditableTextElements = ':text, textarea';
1027 DOMConstants.EditableNumericElements = '[type="number"]';
1028 /**
1029 * DOM Attributes and values.
1030 */
1031 DOMConstants.disabledAttributeOrValue = 'disabled';
1032 DOMConstants.readonlyAttributeOrValue = 'readonly';
1033 DOMConstants.idAttribute = 'id';
1034 DOMConstants.styleAttribute = 'style';
1035 DOMConstants.hrefAttribute = 'href';
1036 DOMConstants.targetAttribute = 'target';
1037 DOMConstants.blankValue = '_blank';
1038 DOMConstants.selfValue = '_self';
1039 DOMConstants.classAttribute = 'class';
1040 DOMConstants.titleAttribute = 'title';
1041 DOMConstants.srcAttribute = 'src';
1042 /**
1043 * DOM event names.
1044 */
1045 DOMConstants.contextmenuEventName = 'contextmenu';
1046 DOMConstants.blurEventName = 'blur';
1047 DOMConstants.keyUpEventName = 'keyup';
1048 DOMConstants.inputEventName = 'input';
1049 DOMConstants.changeEventName = 'change';
1050 DOMConstants.cutEventName = 'cut';
1051 DOMConstants.keyDownEventName = 'keydown';
1052 DOMConstants.mouseMoveEventName = 'mousemove';
1053 DOMConstants.mouseDownEventName = 'mousedown';
1054 DOMConstants.mouseEnterEventName = 'mouseenter';
1055 DOMConstants.mouseLeaveEventName = 'mouseleave';
1056 DOMConstants.mouseOverEventName = 'mouseover';
1057 DOMConstants.mouseOutEventName = 'mouseout';
1058 DOMConstants.mouseClickEventName = 'click';
1059 DOMConstants.pasteEventName = 'paste';
1060 DOMConstants.scrollEventName = 'scroll';
1061 DOMConstants.dropEventName = 'drop';
1062 DOMConstants.focusEventName = 'focus';
1063 DOMConstants.focusInEventName = 'focusin';
1064 DOMConstants.focusOutEventName = 'focusout';
1065 DOMConstants.selectEventName = 'select';
1066 DOMConstants.messageEventName = 'message';
1067 DOMConstants.loadEventName = 'load';
1068 DOMConstants.beforeUnload = 'beforeunload';
1069 /**
1070 * Common DOM event combination names.
1071 */
1072 DOMConstants.inputAndSelectEventNames = 'input, select';
1073 })(DOMConstants = jsCommon.DOMConstants || (jsCommon.DOMConstants = {}));
1074})(jsCommon || (jsCommon = {}));
1075/*
1076 * Power BI Visualizations
1077 *
1078 * Copyright (c) Microsoft Corporation
1079 * All rights reserved.
1080 * MIT License
1081 *
1082 * Permission is hereby granted, free of charge, to any person obtaining a copy
1083 * of this software and associated documentation files (the ""Software""), to deal
1084 * in the Software without restriction, including without limitation the rights
1085 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1086 * copies of the Software, and to permit persons to whom the Software is
1087 * furnished to do so, subject to the following conditions:
1088 *
1089 * The above copyright notice and this permission notice shall be included in
1090 * all copies or substantial portions of the Software.
1091 *
1092 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1093 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1094 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1095 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1096 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1097 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1098 * THE SOFTWARE.
1099 */
1100var powerbi;
1101(function (powerbi) {
1102 (function (PowerBIErrorResourceType) {
1103 PowerBIErrorResourceType[PowerBIErrorResourceType["ResourceCodeReference"] = 0] = "ResourceCodeReference";
1104 PowerBIErrorResourceType[PowerBIErrorResourceType["EmbeddedString"] = 1] = "EmbeddedString";
1105 })(powerbi.PowerBIErrorResourceType || (powerbi.PowerBIErrorResourceType = {}));
1106 var PowerBIErrorResourceType = powerbi.PowerBIErrorResourceType;
1107 var ServiceErrorToClientError = (function () {
1108 function ServiceErrorToClientError(serviceError) {
1109 this.m_serviceError = serviceError;
1110 }
1111 Object.defineProperty(ServiceErrorToClientError.prototype, "code", {
1112 get: function () {
1113 return ServiceErrorToClientError.codeName;
1114 },
1115 enumerable: true,
1116 configurable: true
1117 });
1118 Object.defineProperty(ServiceErrorToClientError.prototype, "ignorable", {
1119 get: function () {
1120 return false;
1121 },
1122 enumerable: true,
1123 configurable: true
1124 });
1125 Object.defineProperty(ServiceErrorToClientError.prototype, "requestId", {
1126 get: function () {
1127 return this.httpRequestId;
1128 },
1129 set: function (value) {
1130 this.httpRequestId = value;
1131 },
1132 enumerable: true,
1133 configurable: true
1134 });
1135 ServiceErrorToClientError.prototype.getDetails = function (resourceProvider) {
1136 var errorDetails;
1137 if (this.m_serviceError.statusCode === 6 /* ExecuteSemanticQueryTransformError */) {
1138 errorDetails = PowerBIErrorDetailHelper.GetDetailsFromTransformError(resourceProvider, this.m_serviceError);
1139 }
1140 else {
1141 errorDetails = PowerBIErrorDetailHelper.GetDetailsFromServerErrorStatusCode(resourceProvider, this.m_serviceError.statusCode);
1142 }
1143 PowerBIErrorDetailHelper.addAdditionalInfo(errorDetails, this.m_serviceError.errorDetails, resourceProvider);
1144 PowerBIErrorDetailHelper.addMessageAndStackTrace(errorDetails, this.m_serviceError.message || null, this.m_serviceError.stackTrace || null, resourceProvider);
1145 return errorDetails;
1146 };
1147 ServiceErrorToClientError.codeName = 'ServiceErrorToClientError';
1148 return ServiceErrorToClientError;
1149 }());
1150 powerbi.ServiceErrorToClientError = ServiceErrorToClientError;
1151 var PowerBIErrorDetailHelper = (function () {
1152 function PowerBIErrorDetailHelper() {
1153 }
1154 PowerBIErrorDetailHelper.addAdditionalInfo = function (errorDetails, pbiErrorDetails, localize) {
1155 if (pbiErrorDetails) {
1156 for (var i = 0; i < pbiErrorDetails.length; i++) {
1157 var element = pbiErrorDetails[i];
1158 var localizedCode = localize.getOptional(PowerBIErrorDetailHelper.serverErrorPrefix + element.code);
1159 var additionErrorInfoKeyValuePair = {
1160 errorInfoKey: localizedCode ? localizedCode : element.code,
1161 errorInfoValue: element.detail.type === PowerBIErrorResourceType.ResourceCodeReference ? localize.get(PowerBIErrorDetailHelper.serverErrorPrefix + element.detail.value) : element.detail.value
1162 };
1163 errorDetails.additionalErrorInfo.push(additionErrorInfoKeyValuePair);
1164 }
1165 }
1166 return errorDetails;
1167 };
1168 PowerBIErrorDetailHelper.addMessageAndStackTrace = function (errorDetails, message, stackTrace, localize) {
1169 if (message) {
1170 var additionErrorInfoKeyValuePair = {
1171 errorInfoKey: localize.get("AdditionalErrorInfo_ErrorDetailsText"),
1172 errorInfoValue: message
1173 };
1174 errorDetails.additionalErrorInfo.push(additionErrorInfoKeyValuePair);
1175 }
1176 if (stackTrace) {
1177 var additionErrorInfoKeyValuePair = {
1178 errorInfoKey: localize.get("AdditionalErrorInfo_StackTraceText"),
1179 errorInfoValue: stackTrace
1180 };
1181 errorDetails.additionalErrorInfo.push(additionErrorInfoKeyValuePair);
1182 }
1183 return errorDetails;
1184 };
1185 PowerBIErrorDetailHelper.GetDetailsFromTransformError = function (localize, serviceError) {
1186 var message = localize.get('ServiceError_CannotLoadVisual');
1187 var key = localize.get('ServiceError_CannotLoadVisual');
1188 var val = serviceError.message;
1189 var additionalInfo = [];
1190 additionalInfo.push({ errorInfoKey: key, errorInfoValue: val, });
1191 var errorDetails = {
1192 message: message,
1193 additionalErrorInfo: additionalInfo,
1194 };
1195 return errorDetails;
1196 };
1197 PowerBIErrorDetailHelper.GetDetailsFromServerErrorStatusCode = function (localize, statusCode) {
1198 // TODO: Localize
1199 var message = "";
1200 var key = "";
1201 var val = "";
1202 switch (statusCode) {
1203 case 2 /* CsdlConvertXmlToConceptualSchema */:
1204 message = localize.get('ServiceError_ModelCannotLoad');
1205 key = localize.get('ServiceError_ModelConvertFailureKey');
1206 val = localize.get('ServiceError_ModelConvertFailureValue');
1207 break;
1208 case 3 /* CsdlCreateClientSchema */:
1209 message = localize.get('ServiceError_ModelCannotLoad');
1210 key = localize.get('ServiceError_ModelCreationFailureKey');
1211 val = localize.get('ServiceError_ModelCreationFailureValue');
1212 break;
1213 case 1 /* CsdlFetching */:
1214 message = localize.get('ServiceError_ModelCannotLoad');
1215 key = localize.get('ServiceError_ModelFetchingFailureKey');
1216 val = localize.get('ServiceError_ModelFetchingFailureValue');
1217 break;
1218 case 4 /* ExecuteSemanticQueryError */:
1219 message = localize.get('ServiceError_CannotLoadVisual');
1220 key = localize.get('ServiceError_ExecuteSemanticQueryErrorKey');
1221 val = localize.get('ServiceError_ExecuteSemanticQueryErrorValue');
1222 break;
1223 case 5 /* ExecuteSemanticQueryInvalidStreamFormat */:
1224 message = localize.get('ServiceError_CannotLoadVisual');
1225 key = localize.get('ServiceError_ExecuteSemanticQueryInvalidStreamFormatKey');
1226 val = localize.get('ServiceError_ExecuteSemanticQueryInvalidStreamFormatValue');
1227 break;
1228 case 0 /* GeneralError */:
1229 default:
1230 message = localize.get('ServiceError_GeneralError');
1231 key = localize.get('ServiceError_GeneralErrorKey');
1232 val = localize.get('ServiceError_GeneralErrorValue');
1233 break;
1234 }
1235 var additionalInfo = [];
1236 additionalInfo.push({ errorInfoKey: key, errorInfoValue: val, });
1237 var errorDetails = {
1238 message: message,
1239 additionalErrorInfo: additionalInfo,
1240 };
1241 return errorDetails;
1242 };
1243 PowerBIErrorDetailHelper.serverErrorPrefix = "ServerError_";
1244 return PowerBIErrorDetailHelper;
1245 }());
1246 powerbi.PowerBIErrorDetailHelper = PowerBIErrorDetailHelper;
1247})(powerbi || (powerbi = {}));
1248/*
1249 * Power BI Visualizations
1250 *
1251 * Copyright (c) Microsoft Corporation
1252 * All rights reserved.
1253 * MIT License
1254 *
1255 * Permission is hereby granted, free of charge, to any person obtaining a copy
1256 * of this software and associated documentation files (the ""Software""), to deal
1257 * in the Software without restriction, including without limitation the rights
1258 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1259 * copies of the Software, and to permit persons to whom the Software is
1260 * furnished to do so, subject to the following conditions:
1261 *
1262 * The above copyright notice and this permission notice shall be included in
1263 * all copies or substantial portions of the Software.
1264 *
1265 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1266 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1267 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1268 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1269 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1270 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1271 * THE SOFTWARE.
1272 */
1273var powerbi;
1274(function (powerbi) {
1275})(powerbi || (powerbi = {}));
1276/*
1277 * Power BI Visualizations
1278 *
1279 * Copyright (c) Microsoft Corporation
1280 * All rights reserved.
1281 * MIT License
1282 *
1283 * Permission is hereby granted, free of charge, to any person obtaining a copy
1284 * of this software and associated documentation files (the ""Software""), to deal
1285 * in the Software without restriction, including without limitation the rights
1286 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1287 * copies of the Software, and to permit persons to whom the Software is
1288 * furnished to do so, subject to the following conditions:
1289 *
1290 * The above copyright notice and this permission notice shall be included in
1291 * all copies or substantial portions of the Software.
1292 *
1293 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1294 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1295 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1296 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1297 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1298 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1299 * THE SOFTWARE.
1300 */
1301var powerbi;
1302(function (powerbi) {
1303 powerbi.CategoryTypes = {
1304 Address: "Address",
1305 City: "City",
1306 Continent: "Continent",
1307 CountryRegion: "Country",
1308 County: "County",
1309 Longitude: "Longitude",
1310 Latitude: "Latitude",
1311 Place: "Place",
1312 PostalCode: "PostalCode",
1313 StateOrProvince: "StateOrProvince"
1314 };
1315 function createGeoTaggingAnalyzerService(getLocalized) {
1316 return new GeoTaggingAnalyzerService(getLocalized);
1317 }
1318 powerbi.createGeoTaggingAnalyzerService = createGeoTaggingAnalyzerService;
1319 var EnglishBackup = {
1320 GeotaggingString_Continent: "continent",
1321 GeotaggingString_Continents: "continents",
1322 GeotaggingString_Country: "country",
1323 GeotaggingString_Countries: "countries",
1324 GeotaggingString_State: "state",
1325 GeotaggingString_States: "states",
1326 GeotaggingString_City: "city",
1327 GeotaggingString_Cities: "cities",
1328 GeotaggingString_Town: "town",
1329 GeotaggingString_Towns: "towns",
1330 GeotaggingString_Province: "province",
1331 GeotaggingString_Provinces: "provinces",
1332 GeotaggingString_County: "county",
1333 GeotaggingString_Counties: "counties",
1334 GeotaggingString_Village: "village",
1335 GeotaggingString_Villages: "villages",
1336 GeotaggingString_Post: "post",
1337 GeotaggingString_Zip: "zip",
1338 GeotaggingString_Code: "code",
1339 GeotaggingString_Place: "place",
1340 GeotaggingString_Places: "places",
1341 GeotaggingString_Address: "address",
1342 GeotaggingString_Addresses: "addresses",
1343 GeotaggingString_Street: "street",
1344 GeotaggingString_Streets: "streets",
1345 GeotaggingString_Longitude: "longitude",
1346 GeotaggingString_Longitude_Short: "lon",
1347 GeotaggingString_Latitude: "latitude",
1348 GeotaggingString_Latitude_Short: "lat",
1349 GeotaggingString_PostalCode: "postal code",
1350 GeotaggingString_PostalCodes: "postal codes",
1351 GeotaggingString_ZipCode: "zip code",
1352 GeotaggingString_ZipCodes: "zip codes",
1353 GeotaggingString_Territory: "territory",
1354 GeotaggingString_Territories: "territories",
1355 GeotaggingString_VRMBackCompat_CountryRegion: "CountryRegion",
1356 GeotaggingString_VRMBackCompat_StateOrProvince: "StateOrProvince",
1357 };
1358 var GeoTaggingAnalyzerService = (function () {
1359 function GeoTaggingAnalyzerService(getLocalized) {
1360 this.GeotaggingString_VRMBackCompat_CountryRegion = "CountryRegion";
1361 this.GeotaggingString_VRMBackCompat_StateOrProvince = "StateOrProvince";
1362 this.GeotaggingString_Continent = getLocalized("GeotaggingString_Continent").toLowerCase();
1363 this.GeotaggingString_Continents = getLocalized("GeotaggingString_Continents").toLowerCase();
1364 this.GeotaggingString_Country = getLocalized("GeotaggingString_Country").toLowerCase();
1365 this.GeotaggingString_Countries = getLocalized("GeotaggingString_Countries").toLowerCase();
1366 this.GeotaggingString_State = getLocalized("GeotaggingString_State").toLowerCase();
1367 this.GeotaggingString_States = getLocalized("GeotaggingString_States").toLowerCase();
1368 this.GeotaggingString_City = getLocalized("GeotaggingString_City").toLowerCase();
1369 this.GeotaggingString_Cities = getLocalized("GeotaggingString_Cities").toLowerCase();
1370 this.GeotaggingString_Town = getLocalized("GeotaggingString_Town").toLowerCase();
1371 this.GeotaggingString_Towns = getLocalized("GeotaggingString_Towns").toLowerCase();
1372 this.GeotaggingString_Province = getLocalized("GeotaggingString_Province").toLowerCase();
1373 this.GeotaggingString_Provinces = getLocalized("GeotaggingString_Provinces").toLowerCase();
1374 this.GeotaggingString_County = getLocalized("GeotaggingString_County").toLowerCase();
1375 this.GeotaggingString_Counties = getLocalized("GeotaggingString_Counties").toLowerCase();
1376 this.GeotaggingString_Village = getLocalized("GeotaggingString_Village").toLowerCase();
1377 this.GeotaggingString_Villages = getLocalized("GeotaggingString_Villages").toLowerCase();
1378 this.GeotaggingString_Post = getLocalized("GeotaggingString_Post").toLowerCase();
1379 this.GeotaggingString_Zip = getLocalized("GeotaggingString_Zip").toLowerCase();
1380 this.GeotaggingString_Code = getLocalized("GeotaggingString_Code").toLowerCase();
1381 this.GeotaggingString_Place = getLocalized("GeotaggingString_Place").toLowerCase();
1382 this.GeotaggingString_Places = getLocalized("GeotaggingString_Places").toLowerCase();
1383 this.GeotaggingString_Address = getLocalized("GeotaggingString_Address").toLowerCase();
1384 this.GeotaggingString_Addresses = getLocalized("GeotaggingString_Addresses").toLowerCase();
1385 this.GeotaggingString_Street = getLocalized("GeotaggingString_Street").toLowerCase();
1386 this.GeotaggingString_Streets = getLocalized("GeotaggingString_Streets").toLowerCase();
1387 this.GeotaggingString_Longitude = getLocalized("GeotaggingString_Longitude").toLowerCase();
1388 this.GeotaggingString_Longitude_Short = getLocalized("GeotaggingString_Longitude_Short").toLowerCase();
1389 this.GeotaggingString_Latitude = getLocalized("GeotaggingString_Latitude").toLowerCase();
1390 this.GeotaggingString_Latitude_Short = getLocalized("GeotaggingString_Latitude_Short").toLowerCase();
1391 this.GeotaggingString_PostalCode = getLocalized("GeotaggingString_PostalCode").toLowerCase();
1392 this.GeotaggingString_PostalCodes = getLocalized("GeotaggingString_PostalCodes").toLowerCase();
1393 this.GeotaggingString_ZipCode = getLocalized("GeotaggingString_ZipCode").toLowerCase();
1394 this.GeotaggingString_ZipCodes = getLocalized("GeotaggingString_ZipCodes").toLowerCase();
1395 this.GeotaggingString_Territory = getLocalized("GeotaggingString_Territory").toLowerCase();
1396 this.GeotaggingString_Territories = getLocalized("GeotaggingString_Territories").toLowerCase();
1397 }
1398 GeoTaggingAnalyzerService.prototype.isLongitudeOrLatitude = function (fieldRefName) {
1399 return this.isLongitude(fieldRefName) ||
1400 this.isLatitude(fieldRefName);
1401 };
1402 GeoTaggingAnalyzerService.prototype.isGeographic = function (fieldRefName) {
1403 return this.isLongitudeOrLatitude(fieldRefName) ||
1404 this.isGeocodable(fieldRefName);
1405 };
1406 GeoTaggingAnalyzerService.prototype.isGeocodable = function (fieldRefName) {
1407 return this.isAddress(fieldRefName) ||
1408 this.isCity(fieldRefName) ||
1409 this.isContinent(fieldRefName) ||
1410 this.isCountry(fieldRefName) ||
1411 this.isCounty(fieldRefName) ||
1412 this.isStateOrProvince(fieldRefName) ||
1413 this.isPlace(fieldRefName) ||
1414 this.isPostalCode(fieldRefName) ||
1415 this.isTerritory(fieldRefName);
1416 };
1417 GeoTaggingAnalyzerService.prototype.isGeoshapable = function (fieldRefName) {
1418 return this.isCity(fieldRefName) ||
1419 this.isCountry(fieldRefName) ||
1420 this.isCounty(fieldRefName) ||
1421 this.isStateOrProvince(fieldRefName) ||
1422 this.isPostalCode(fieldRefName) ||
1423 this.isTerritory(fieldRefName) ||
1424 this.isGeoshapableEnglish(fieldRefName);
1425 };
1426 GeoTaggingAnalyzerService.prototype.isGeoshapableEnglish = function (fieldRefName) {
1427 return this.isEnglishCity(fieldRefName) ||
1428 this.isEnglishCountry(fieldRefName) ||
1429 this.isEnglishCounty(fieldRefName) ||
1430 this.isEnglishStateOrProvince(fieldRefName) ||
1431 this.isEnglishPostalCode(fieldRefName) ||
1432 this.isEnglishTerritory(fieldRefName);
1433 };
1434 GeoTaggingAnalyzerService.prototype.isAddress = function (fieldRefName) {
1435 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1436 this.GeotaggingString_Address,
1437 this.GeotaggingString_Addresses,
1438 this.GeotaggingString_Street,
1439 this.GeotaggingString_Streets
1440 ]);
1441 };
1442 GeoTaggingAnalyzerService.prototype.isPlace = function (fieldRefName) {
1443 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1444 this.GeotaggingString_Place,
1445 this.GeotaggingString_Places
1446 ]);
1447 };
1448 GeoTaggingAnalyzerService.prototype.isCity = function (fieldRefName) {
1449 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1450 this.GeotaggingString_City,
1451 this.GeotaggingString_Cities,
1452 this.GeotaggingString_Town,
1453 this.GeotaggingString_Towns,
1454 this.GeotaggingString_Village,
1455 this.GeotaggingString_Villages
1456 ]);
1457 };
1458 GeoTaggingAnalyzerService.prototype.isStateOrProvince = function (fieldRefName) {
1459 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1460 this.GeotaggingString_State,
1461 this.GeotaggingString_States,
1462 this.GeotaggingString_Province,
1463 this.GeotaggingString_Provinces,
1464 this.GeotaggingString_VRMBackCompat_StateOrProvince,
1465 ]);
1466 };
1467 GeoTaggingAnalyzerService.prototype.isCountry = function (fieldRefName) {
1468 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1469 this.GeotaggingString_Country,
1470 this.GeotaggingString_Countries,
1471 this.GeotaggingString_VRMBackCompat_CountryRegion
1472 ]);
1473 };
1474 GeoTaggingAnalyzerService.prototype.isCounty = function (fieldRefName) {
1475 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1476 this.GeotaggingString_County,
1477 this.GeotaggingString_Counties
1478 ]);
1479 };
1480 GeoTaggingAnalyzerService.prototype.isContinent = function (fieldRefName) {
1481 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1482 this.GeotaggingString_Continent,
1483 this.GeotaggingString_Continents
1484 ]);
1485 };
1486 GeoTaggingAnalyzerService.prototype.isPostalCode = function (fieldRefName) {
1487 var result = (GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1488 this.GeotaggingString_Post,
1489 this.GeotaggingString_Zip])
1490 && GeoTaggingAnalyzerService.hasMatches(fieldRefName, [this.GeotaggingString_Code])) ||
1491 GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1492 this.GeotaggingString_PostalCode,
1493 this.GeotaggingString_PostalCodes,
1494 this.GeotaggingString_ZipCode,
1495 this.GeotaggingString_ZipCodes
1496 ]);
1497 //Check again for strings without whitespace
1498 if (!result) {
1499 var whiteSpaceRegex = /\s+/;
1500 var fieldNameWithoutWhitespace = fieldRefName.replace(whiteSpaceRegex, "");
1501 result = GeoTaggingAnalyzerService.hasMatches(fieldNameWithoutWhitespace, [
1502 this.GeotaggingString_PostalCode.replace(whiteSpaceRegex, ''),
1503 this.GeotaggingString_PostalCodes.replace(whiteSpaceRegex, ''),
1504 this.GeotaggingString_ZipCode.replace(whiteSpaceRegex, ''),
1505 this.GeotaggingString_ZipCodes.replace(whiteSpaceRegex, '')
1506 ]);
1507 }
1508 return result;
1509 };
1510 GeoTaggingAnalyzerService.prototype.isLongitude = function (fieldRefName) {
1511 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [this.GeotaggingString_Longitude])
1512 || GeoTaggingAnalyzerService.hasMatches(fieldRefName, [this.GeotaggingString_Longitude_Short], true /* useStrict */);
1513 };
1514 GeoTaggingAnalyzerService.prototype.isLatitude = function (fieldRefName) {
1515 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [this.GeotaggingString_Latitude])
1516 || GeoTaggingAnalyzerService.hasMatches(fieldRefName, [this.GeotaggingString_Latitude_Short], true /* useStrict */);
1517 };
1518 GeoTaggingAnalyzerService.prototype.isTerritory = function (fieldRefName) {
1519 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1520 this.GeotaggingString_Territory,
1521 this.GeotaggingString_Territories
1522 ]);
1523 };
1524 GeoTaggingAnalyzerService.hasMatches = function (fieldName, possibleMatches, useStrict) {
1525 var nonWordRegex = /\W/;
1526 var value = fieldName.toLowerCase();
1527 for (var i = 0, len = possibleMatches.length; i < len; i++) {
1528 var possibleMatch = possibleMatches[i].toLowerCase();
1529 if (!useStrict) {
1530 if (value.indexOf(possibleMatch) > -1)
1531 return true;
1532 }
1533 else {
1534 var indexofpossibleMatch = value.indexOf(possibleMatch);
1535 if (indexofpossibleMatch > -1) {
1536 var wordEndFlag = void 0, wordBeginFlag = void 0;
1537 wordEndFlag = wordBeginFlag = true;
1538 if (indexofpossibleMatch - 1 > 0)
1539 wordBeginFlag = nonWordRegex.test(value[indexofpossibleMatch - 1]);
1540 if (indexofpossibleMatch + possibleMatch.length < value.length)
1541 wordEndFlag = nonWordRegex.test(value[indexofpossibleMatch + possibleMatch.length]);
1542 if (wordBeginFlag && wordEndFlag)
1543 return true;
1544 }
1545 }
1546 }
1547 return false;
1548 };
1549 GeoTaggingAnalyzerService.prototype.getFieldType = function (fieldName) {
1550 if (fieldName == null)
1551 return undefined;
1552 if (this.isLatitude(fieldName))
1553 return powerbi.CategoryTypes.Latitude;
1554 if (this.isLongitude(fieldName))
1555 return powerbi.CategoryTypes.Longitude;
1556 if (this.isPostalCode(fieldName))
1557 return powerbi.CategoryTypes.PostalCode;
1558 if (this.isAddress(fieldName))
1559 return powerbi.CategoryTypes.Address;
1560 if (this.isPlace(fieldName))
1561 return powerbi.CategoryTypes.Place;
1562 if (this.isCity(fieldName))
1563 return powerbi.CategoryTypes.City;
1564 if (this.isCountry(fieldName))
1565 return powerbi.CategoryTypes.CountryRegion;
1566 if (this.isCounty(fieldName))
1567 return powerbi.CategoryTypes.County;
1568 if (this.isStateOrProvince(fieldName))
1569 return powerbi.CategoryTypes.StateOrProvince;
1570 if (this.isContinent(fieldName))
1571 return powerbi.CategoryTypes.Continent;
1572 return this.getEnglishFieldType(fieldName);
1573 };
1574 GeoTaggingAnalyzerService.prototype.isEnglishAddress = function (fieldRefName) {
1575 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1576 EnglishBackup.GeotaggingString_Address,
1577 EnglishBackup.GeotaggingString_Addresses,
1578 EnglishBackup.GeotaggingString_Street,
1579 EnglishBackup.GeotaggingString_Streets
1580 ]);
1581 };
1582 GeoTaggingAnalyzerService.prototype.isEnglishPlace = function (fieldRefName) {
1583 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1584 EnglishBackup.GeotaggingString_Place,
1585 EnglishBackup.GeotaggingString_Places
1586 ]);
1587 };
1588 GeoTaggingAnalyzerService.prototype.isEnglishCity = function (fieldRefName) {
1589 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1590 EnglishBackup.GeotaggingString_City,
1591 EnglishBackup.GeotaggingString_Cities,
1592 EnglishBackup.GeotaggingString_Town,
1593 EnglishBackup.GeotaggingString_Towns,
1594 EnglishBackup.GeotaggingString_Village,
1595 EnglishBackup.GeotaggingString_Villages
1596 ]);
1597 };
1598 GeoTaggingAnalyzerService.prototype.isEnglishStateOrProvince = function (fieldRefName) {
1599 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1600 EnglishBackup.GeotaggingString_State,
1601 EnglishBackup.GeotaggingString_States,
1602 EnglishBackup.GeotaggingString_Province,
1603 EnglishBackup.GeotaggingString_Provinces,
1604 EnglishBackup.GeotaggingString_VRMBackCompat_StateOrProvince,
1605 ]);
1606 };
1607 GeoTaggingAnalyzerService.prototype.isEnglishCountry = function (fieldRefName) {
1608 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1609 EnglishBackup.GeotaggingString_Country,
1610 EnglishBackup.GeotaggingString_Countries,
1611 EnglishBackup.GeotaggingString_VRMBackCompat_CountryRegion
1612 ]);
1613 };
1614 GeoTaggingAnalyzerService.prototype.isEnglishCounty = function (fieldRefName) {
1615 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1616 EnglishBackup.GeotaggingString_County,
1617 EnglishBackup.GeotaggingString_Counties
1618 ]);
1619 };
1620 GeoTaggingAnalyzerService.prototype.isEnglishContinent = function (fieldRefName) {
1621 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1622 EnglishBackup.GeotaggingString_Continent,
1623 EnglishBackup.GeotaggingString_Continents
1624 ]);
1625 };
1626 GeoTaggingAnalyzerService.prototype.isEnglishPostalCode = function (fieldRefName) {
1627 var result = (GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1628 EnglishBackup.GeotaggingString_Post,
1629 EnglishBackup.GeotaggingString_Zip])
1630 && GeoTaggingAnalyzerService.hasMatches(fieldRefName, [this.GeotaggingString_Code])) ||
1631 GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1632 EnglishBackup.GeotaggingString_PostalCode,
1633 EnglishBackup.GeotaggingString_PostalCodes,
1634 EnglishBackup.GeotaggingString_ZipCode,
1635 EnglishBackup.GeotaggingString_ZipCodes
1636 ]);
1637 //Check again for strings without whitespace
1638 if (!result) {
1639 var whiteSpaceRegexPattern = new RegExp('\s');
1640 result = GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1641 EnglishBackup.GeotaggingString_PostalCode.replace(whiteSpaceRegexPattern, ''),
1642 EnglishBackup.GeotaggingString_PostalCodes.replace(whiteSpaceRegexPattern, ''),
1643 EnglishBackup.GeotaggingString_ZipCode.replace(whiteSpaceRegexPattern, ''),
1644 EnglishBackup.GeotaggingString_ZipCodes.replace(whiteSpaceRegexPattern, '')
1645 ]);
1646 }
1647 return result;
1648 };
1649 GeoTaggingAnalyzerService.prototype.isEnglishLongitude = function (fieldRefName) {
1650 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [EnglishBackup.GeotaggingString_Longitude])
1651 || GeoTaggingAnalyzerService.hasMatches(fieldRefName, [EnglishBackup.GeotaggingString_Longitude_Short], true /* useStrict */);
1652 };
1653 GeoTaggingAnalyzerService.prototype.isEnglishLatitude = function (fieldRefName) {
1654 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [EnglishBackup.GeotaggingString_Latitude])
1655 || GeoTaggingAnalyzerService.hasMatches(fieldRefName, [EnglishBackup.GeotaggingString_Latitude_Short], true /* useStrict */);
1656 };
1657 GeoTaggingAnalyzerService.prototype.isEnglishTerritory = function (fieldRefName) {
1658 return GeoTaggingAnalyzerService.hasMatches(fieldRefName, [
1659 EnglishBackup.GeotaggingString_Territory,
1660 EnglishBackup.GeotaggingString_Territories
1661 ]);
1662 };
1663 GeoTaggingAnalyzerService.prototype.getEnglishFieldType = function (fieldName) {
1664 if (fieldName == null)
1665 return undefined;
1666 if (this.isEnglishLatitude(fieldName))
1667 return powerbi.CategoryTypes.Latitude;
1668 if (this.isEnglishLongitude(fieldName))
1669 return powerbi.CategoryTypes.Longitude;
1670 if (this.isEnglishPostalCode(fieldName))
1671 return powerbi.CategoryTypes.PostalCode;
1672 if (this.isEnglishAddress(fieldName))
1673 return powerbi.CategoryTypes.Address;
1674 if (this.isEnglishPlace(fieldName))
1675 return powerbi.CategoryTypes.Place;
1676 if (this.isEnglishCity(fieldName))
1677 return powerbi.CategoryTypes.City;
1678 if (this.isEnglishCountry(fieldName))
1679 return powerbi.CategoryTypes.CountryRegion;
1680 if (this.isEnglishCounty(fieldName))
1681 return powerbi.CategoryTypes.County;
1682 if (this.isEnglishStateOrProvince(fieldName))
1683 return powerbi.CategoryTypes.StateOrProvince;
1684 if (this.isEnglishContinent(fieldName))
1685 return powerbi.CategoryTypes.Continent;
1686 return undefined;
1687 };
1688 return GeoTaggingAnalyzerService;
1689 }());
1690 powerbi.GeoTaggingAnalyzerService = GeoTaggingAnalyzerService;
1691})(powerbi || (powerbi = {}));
1692/*
1693 * Power BI Visualizations
1694 *
1695 * Copyright (c) Microsoft Corporation
1696 * All rights reserved.
1697 * MIT License
1698 *
1699 * Permission is hereby granted, free of charge, to any person obtaining a copy
1700 * of this software and associated documentation files (the ""Software""), to deal
1701 * in the Software without restriction, including without limitation the rights
1702 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1703 * copies of the Software, and to permit persons to whom the Software is
1704 * furnished to do so, subject to the following conditions:
1705 *
1706 * The above copyright notice and this permission notice shall be included in
1707 * all copies or substantial portions of the Software.
1708 *
1709 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1710 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1711 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1712 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1713 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1714 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1715 * THE SOFTWARE.
1716 */
1717if (typeof DEBUG === 'undefined')
1718 var DEBUG = true;
1719/*
1720 * Power BI Visualizations
1721 *
1722 * Copyright (c) Microsoft Corporation
1723 * All rights reserved.
1724 * MIT License
1725 *
1726 * Permission is hereby granted, free of charge, to any person obtaining a copy
1727 * of this software and associated documentation files (the ""Software""), to deal
1728 * in the Software without restriction, including without limitation the rights
1729 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1730 * copies of the Software, and to permit persons to whom the Software is
1731 * furnished to do so, subject to the following conditions:
1732 *
1733 * The above copyright notice and this permission notice shall be included in
1734 * all copies or substantial portions of the Software.
1735 *
1736 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1737 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1738 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1739 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1740 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1741 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1742 * THE SOFTWARE.
1743 */
1744var powerbi;
1745(function (powerbi) {
1746 /**
1747 this base class should be derived to give a generic error message but with a unique error code.
1748 */
1749 var UnknownClientError = (function () {
1750 function UnknownClientError(code) {
1751 debug.assertValue(code, 'code');
1752 this.errorCode = code;
1753 }
1754 Object.defineProperty(UnknownClientError.prototype, "code", {
1755 get: function () {
1756 return this.errorCode;
1757 },
1758 enumerable: true,
1759 configurable: true
1760 });
1761 Object.defineProperty(UnknownClientError.prototype, "ignorable", {
1762 get: function () {
1763 return false;
1764 },
1765 enumerable: true,
1766 configurable: true
1767 });
1768 UnknownClientError.prototype.getDetails = function (resourceProvider) {
1769 var details = {
1770 message: resourceProvider.get('ClientError_UnknownClientErrorValue'),
1771 additionalErrorInfo: [{ errorInfoKey: resourceProvider.get('ClientError_UnknownClientErrorKey'), errorInfoValue: resourceProvider.get('ClientError_UnknownClientErrorValue'), }],
1772 };
1773 return details;
1774 };
1775 return UnknownClientError;
1776 }());
1777 powerbi.UnknownClientError = UnknownClientError;
1778 var HttpClientError = (function () {
1779 function HttpClientError(httpStatusCode, requestId) {
1780 debug.assertValue(httpStatusCode, 'httpStatusCode');
1781 debug.assertValue(requestId, 'requestId');
1782 this.httpStatusCode = httpStatusCode;
1783 this.httpRequestId = requestId;
1784 }
1785 Object.defineProperty(HttpClientError.prototype, "code", {
1786 get: function () {
1787 return 'HttpClientError';
1788 },
1789 enumerable: true,
1790 configurable: true
1791 });
1792 Object.defineProperty(HttpClientError.prototype, "ignorable", {
1793 get: function () {
1794 return false;
1795 },
1796 enumerable: true,
1797 configurable: true
1798 });
1799 Object.defineProperty(HttpClientError.prototype, "requestId", {
1800 get: function () {
1801 return this.httpRequestId;
1802 },
1803 enumerable: true,
1804 configurable: true
1805 });
1806 HttpClientError.prototype.getDetails = function (resourceProvider) {
1807 // Use a general error message for a HTTP request failure, since we currently do not know of any specifc error cases at this point in time.
1808 var details = {
1809 message: null,
1810 additionalErrorInfo: [
1811 { errorInfoKey: resourceProvider.get('DsrError_Key'), errorInfoValue: resourceProvider.get('DsrError_UnknownErrorValue') },
1812 { errorInfoKey: resourceProvider.get('ClientError_HttpResponseStatusCodeKey'), errorInfoValue: this.httpStatusCode.toString() }],
1813 };
1814 return details;
1815 };
1816 return HttpClientError;
1817 }());
1818 powerbi.HttpClientError = HttpClientError;
1819 var IgnorableClientError = (function () {
1820 function IgnorableClientError() {
1821 }
1822 Object.defineProperty(IgnorableClientError.prototype, "code", {
1823 get: function () {
1824 return 'IgnorableClientError';
1825 },
1826 enumerable: true,
1827 configurable: true
1828 });
1829 Object.defineProperty(IgnorableClientError.prototype, "ignorable", {
1830 get: function () {
1831 return true;
1832 },
1833 enumerable: true,
1834 configurable: true
1835 });
1836 IgnorableClientError.prototype.getDetails = function (resourceProvider) {
1837 var details = {
1838 message: '',
1839 additionalErrorInfo: [],
1840 };
1841 return details;
1842 };
1843 return IgnorableClientError;
1844 }());
1845 powerbi.IgnorableClientError = IgnorableClientError;
1846})(powerbi || (powerbi = {}));
1847/*
1848 * Power BI Visualizations
1849 *
1850 * Copyright (c) Microsoft Corporation
1851 * All rights reserved.
1852 * MIT License
1853 *
1854 * Permission is hereby granted, free of charge, to any person obtaining a copy
1855 * of this software and associated documentation files (the ""Software""), to deal
1856 * in the Software without restriction, including without limitation the rights
1857 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1858 * copies of the Software, and to permit persons to whom the Software is
1859 * furnished to do so, subject to the following conditions:
1860 *
1861 * The above copyright notice and this permission notice shall be included in
1862 * all copies or substantial portions of the Software.
1863 *
1864 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1865 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1866 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1867 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1868 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1869 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1870 * THE SOFTWARE.
1871 */
1872var jsCommon;
1873(function (jsCommon) {
1874 var ArrayExtensions;
1875 (function (ArrayExtensions) {
1876 /**
1877 * Returns items that exist in target and other.
1878 */
1879 function intersect(target, other) {
1880 var result = [];
1881 for (var i = target.length - 1; i >= 0; --i) {
1882 if (other.indexOf(target[i]) !== -1) {
1883 result.push(target[i]);
1884 }
1885 }
1886 return result;
1887 }
1888 ArrayExtensions.intersect = intersect;
1889 /**
1890 * Return elements exists in target but not exists in other.
1891 */
1892 function diff(target, other) {
1893 var result = [];
1894 for (var i = target.length - 1; i >= 0; --i) {
1895 var value = target[i];
1896 if (other.indexOf(value) === -1) {
1897 result.push(value);
1898 }
1899 }
1900 return result;
1901 }
1902 ArrayExtensions.diff = diff;
1903 /**
1904 * Return an array with only the distinct items in the source.
1905 */
1906 function distinct(source) {
1907 var result = [];
1908 for (var i = 0, len = source.length; i < len; i++) {
1909 var value = source[i];
1910 if (result.indexOf(value) === -1) {
1911 result.push(value);
1912 }
1913 }
1914 return result;
1915 }
1916 ArrayExtensions.distinct = distinct;
1917 /**
1918 * Pushes content of source onto target,
1919 * for parts of course that do not already exist in target.
1920 */
1921 function union(target, source) {
1922 for (var i = 0, len = source.length; i < len; ++i) {
1923 unionSingle(target, source[i]);
1924 }
1925 }
1926 ArrayExtensions.union = union;
1927 /**
1928 * Pushes value onto target, if value does not already exist in target.
1929 */
1930 function unionSingle(target, value) {
1931 if (target.indexOf(value) < 0) {
1932 target.push(value);
1933 }
1934 }
1935 ArrayExtensions.unionSingle = unionSingle;
1936 /**
1937 * Returns an array with a range of items from source,
1938 * including the startIndex & endIndex.
1939 */
1940 function range(source, startIndex, endIndex) {
1941 debug.assert(startIndex >= 0 && startIndex < source.length, 'startIndex is out of range.');
1942 debug.assert(endIndex >= 0 && endIndex < source.length, 'endIndex is out of range.');
1943 var result = [];
1944 for (var i = startIndex; i <= endIndex; ++i) {
1945 result.push(source[i]);
1946 }
1947 return result;
1948 }
1949 ArrayExtensions.range = range;
1950 /**
1951 * Returns an array that includes items from source, up to the specified count.
1952 */
1953 function take(source, count) {
1954 debug.assert(count >= 0, 'Count is negative.');
1955 debug.assert(count <= source.length, 'Count is too large.');
1956 var result = [];
1957 for (var i = 0; i < count; ++i) {
1958 result.push(source[i]);
1959 }
1960 return result;
1961 }
1962 ArrayExtensions.take = take;
1963 function copy(source) {
1964 debug.assertValue(source, 'source');
1965 return take(source, source.length);
1966 }
1967 ArrayExtensions.copy = copy;
1968 /**
1969 * Returns a value indicating whether the arrays have the same values in the same sequence.
1970 */
1971 function sequenceEqual(left, right, comparison) {
1972 debug.assertValue(comparison, 'comparison');
1973 if (left === right) {
1974 return true;
1975 }
1976 if (!!left !== !!right) {
1977 return false;
1978 }
1979 var len = left.length;
1980 if (len !== right.length) {
1981 return false;
1982 }
1983 var i = 0;
1984 while (i < len && comparison(left[i], right[i])) {
1985 ++i;
1986 }
1987 return i === len;
1988 }
1989 ArrayExtensions.sequenceEqual = sequenceEqual;
1990 /**
1991 * Returns null if the specified array is empty.
1992 * Otherwise returns the specified array.
1993 */
1994 function emptyToNull(array) {
1995 if (array && array.length === 0) {
1996 return null;
1997 }
1998 return array;
1999 }
2000 ArrayExtensions.emptyToNull = emptyToNull;
2001 function indexOf(array, predicate) {
2002 debug.assertValue(array, 'array');
2003 debug.assertValue(predicate, 'predicate');
2004 for (var i = 0, len = array.length; i < len; ++i) {
2005 if (predicate(array[i])) {
2006 return i;
2007 }
2008 }
2009 return -1;
2010 }
2011 ArrayExtensions.indexOf = indexOf;
2012 /**
2013 * Returns a copy of the array rotated by the specified offset.
2014 */
2015 function rotate(array, offset) {
2016 if (offset === 0)
2017 return array.slice();
2018 var rotated = array.slice(offset);
2019 Array.prototype.push.apply(rotated, array.slice(0, offset));
2020 return rotated;
2021 }
2022 ArrayExtensions.rotate = rotate;
2023 function createWithId() {
2024 return extendWithId([]);
2025 }
2026 ArrayExtensions.createWithId = createWithId;
2027 function extendWithId(array) {
2028 debug.assertValue(array, 'array');
2029 var extended = array;
2030 extended.withId = withId;
2031 return extended;
2032 }
2033 ArrayExtensions.extendWithId = extendWithId;
2034 /**
2035 * Finds and returns the first item with a matching ID.
2036 */
2037 function findWithId(array, id) {
2038 for (var i = 0, len = array.length; i < len; i++) {
2039 var item = array[i];
2040 if (item.id === id)
2041 return item;
2042 }
2043 }
2044 ArrayExtensions.findWithId = findWithId;
2045 function withId(id) {
2046 return ArrayExtensions.findWithId(this, id);
2047 }
2048 function createWithName() {
2049 return extendWithName([]);
2050 }
2051 ArrayExtensions.createWithName = createWithName;
2052 function extendWithName(array) {
2053 debug.assertValue(array, 'array');
2054 var extended = array;
2055 extended.withName = withName;
2056 return extended;
2057 }
2058 ArrayExtensions.extendWithName = extendWithName;
2059 function findItemWithName(array, name) {
2060 var index = indexWithName(array, name);
2061 if (index >= 0)
2062 return array[index];
2063 }
2064 ArrayExtensions.findItemWithName = findItemWithName;
2065 function indexWithName(array, name) {
2066 for (var i = 0, len = array.length; i < len; i++) {
2067 var item = array[i];
2068 if (item.name === name)
2069 return i;
2070 }
2071 return -1;
2072 }
2073 ArrayExtensions.indexWithName = indexWithName;
2074 /**
2075 * Inserts a number in sorted order into a list of numbers already in sorted order.
2076 * @returns True if the item was added, false if it already existed.
2077 */
2078 function insertSorted(list, value) {
2079 debug.assertValue(list, 'list');
2080 debug.assertValue(value, 'value');
2081 var len = list.length;
2082 // NOTE: iterate backwards because incoming values tend to be sorted already.
2083 for (var i = len - 1; i >= 0; i--) {
2084 var diff_1 = list[i] - value;
2085 if (diff_1 === 0)
2086 return false;
2087 if (diff_1 > 0)
2088 continue;
2089 // diff < 0
2090 list.splice(i + 1, 0, value);
2091 return true;
2092 }
2093 list.unshift(value);
2094 return true;
2095 }
2096 ArrayExtensions.insertSorted = insertSorted;
2097 /**
2098 * Removes the first occurrence of a value from a list if it exists.
2099 * @returns True if the value was removed, false if it did not exist in the list.
2100 */
2101 function removeFirst(list, value) {
2102 var index = list.indexOf(value);
2103 if (index < 0)
2104 return false;
2105 list.splice(index, 1);
2106 return true;
2107 }
2108 ArrayExtensions.removeFirst = removeFirst;
2109 /**
2110 * Finds and returns the first item with a matching name.
2111 */
2112 function withName(name) {
2113 var array = this;
2114 return findItemWithName(array, name);
2115 }
2116 /**
2117 * Deletes all items from the array.
2118 */
2119 function clear(array) {
2120 if (!array)
2121 return;
2122 while (array.length > 0)
2123 array.pop();
2124 }
2125 ArrayExtensions.clear = clear;
2126 function isUndefinedOrEmpty(array) {
2127 if (!array || array.length === 0) {
2128 return true;
2129 }
2130 return false;
2131 }
2132 ArrayExtensions.isUndefinedOrEmpty = isUndefinedOrEmpty;
2133 function swap(array, firstIndex, secondIndex) {
2134 var temp = array[firstIndex];
2135 array[firstIndex] = array[secondIndex];
2136 array[secondIndex] = temp;
2137 }
2138 ArrayExtensions.swap = swap;
2139 function isInArray(array, lookupItem, compareCallback) {
2140 return _.any(array, function (item) { return compareCallback(item, lookupItem); });
2141 }
2142 ArrayExtensions.isInArray = isInArray;
2143 /** Checks if the given object is an Array, and looking all the way up the prototype chain. */
2144 function isArrayOrInheritedArray(obj) {
2145 debug.assertValue(obj, 'obj');
2146 var nextPrototype = obj;
2147 while (nextPrototype != null) {
2148 if (_.isArray(nextPrototype))
2149 return true;
2150 nextPrototype = Object.getPrototypeOf(nextPrototype);
2151 }
2152 return false;
2153 }
2154 ArrayExtensions.isArrayOrInheritedArray = isArrayOrInheritedArray;
2155 })(ArrayExtensions = jsCommon.ArrayExtensions || (jsCommon.ArrayExtensions = {}));
2156})(jsCommon || (jsCommon = {}));
2157/*
2158 * Power BI Visualizations
2159 *
2160 * Copyright (c) Microsoft Corporation
2161 * All rights reserved.
2162 * MIT License
2163 *
2164 * Permission is hereby granted, free of charge, to any person obtaining a copy
2165 * of this software and associated documentation files (the ""Software""), to deal
2166 * in the Software without restriction, including without limitation the rights
2167 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2168 * copies of the Software, and to permit persons to whom the Software is
2169 * furnished to do so, subject to the following conditions:
2170 *
2171 * The above copyright notice and this permission notice shall be included in
2172 * all copies or substantial portions of the Software.
2173 *
2174 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2175 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2176 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2177 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2178 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2179 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2180 * THE SOFTWARE.
2181 */
2182var InJs;
2183(function (InJs) {
2184 var DomFactory;
2185 (function (DomFactory) {
2186 function div() {
2187 return $('<div/>');
2188 }
2189 DomFactory.div = div;
2190 function span() {
2191 return $('<span/>');
2192 }
2193 DomFactory.span = span;
2194 function checkbox() {
2195 return $('<input type="checkbox"/>');
2196 }
2197 DomFactory.checkbox = checkbox;
2198 function ul() {
2199 return $('<ul/>');
2200 }
2201 DomFactory.ul = ul;
2202 function li() {
2203 return $('<li/>');
2204 }
2205 DomFactory.li = li;
2206 function button() {
2207 return $('<input type="button"/>');
2208 }
2209 DomFactory.button = button;
2210 function select() {
2211 return $('<select/>');
2212 }
2213 DomFactory.select = select;
2214 function textBox() {
2215 return $('<input type="text"/>');
2216 }
2217 DomFactory.textBox = textBox;
2218 function img() {
2219 return $('<img/>');
2220 }
2221 DomFactory.img = img;
2222 function iframe() {
2223 return $('<iframe/>');
2224 }
2225 DomFactory.iframe = iframe;
2226 })(DomFactory = InJs.DomFactory || (InJs.DomFactory = {}));
2227})(InJs || (InJs = {}));
2228/*
2229 * Power BI Visualizations
2230 *
2231 * Copyright (c) Microsoft Corporation
2232 * All rights reserved.
2233 * MIT License
2234 *
2235 * Permission is hereby granted, free of charge, to any person obtaining a copy
2236 * of this software and associated documentation files (the ""Software""), to deal
2237 * in the Software without restriction, including without limitation the rights
2238 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2239 * copies of the Software, and to permit persons to whom the Software is
2240 * furnished to do so, subject to the following conditions:
2241 *
2242 * The above copyright notice and this permission notice shall be included in
2243 * all copies or substantial portions of the Software.
2244 *
2245 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2246 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2247 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2248 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2249 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2250 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2251 * THE SOFTWARE.
2252 */
2253var powerbi;
2254(function (powerbi) {
2255 /**
2256 * Module Double contains a set of constants and precision based utility methods
2257 * for dealing with doubles and their decimal garbage in the javascript.
2258 */
2259 var Double;
2260 (function (Double) {
2261 // Constants.
2262 Double.MIN_VALUE = -Number.MAX_VALUE;
2263 Double.MAX_VALUE = Number.MAX_VALUE;
2264 Double.MIN_EXP = -308;
2265 Double.MAX_EXP = 308;
2266 Double.EPSILON = 1E-323;
2267 Double.DEFAULT_PRECISION = 0.0001;
2268 Double.DEFAULT_PRECISION_IN_DECIMAL_DIGITS = 12;
2269 Double.LOG_E_10 = Math.log(10);
2270 Double.POSITIVE_POWERS = [
2271 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15, 1E16, 1E17, 1E18, 1E19, 1E20, 1E21, 1E22, 1E23, 1E24, 1E25, 1E26, 1E27, 1E28, 1E29, 1E30, 1E31, 1E32, 1E33, 1E34, 1E35, 1E36, 1E37, 1E38, 1E39, 1E40, 1E41, 1E42, 1E43, 1E44, 1E45, 1E46, 1E47, 1E48, 1E49, 1E50, 1E51, 1E52, 1E53, 1E54, 1E55, 1E56, 1E57, 1E58, 1E59, 1E60, 1E61, 1E62, 1E63, 1E64, 1E65, 1E66, 1E67, 1E68, 1E69, 1E70, 1E71, 1E72, 1E73, 1E74, 1E75, 1E76, 1E77, 1E78, 1E79, 1E80, 1E81, 1E82, 1E83, 1E84, 1E85, 1E86, 1E87, 1E88, 1E89, 1E90, 1E91, 1E92, 1E93, 1E94, 1E95, 1E96, 1E97, 1E98, 1E99,
2272 1E100, 1E101, 1E102, 1E103, 1E104, 1E105, 1E106, 1E107, 1E108, 1E109, 1E110, 1E111, 1E112, 1E113, 1E114, 1E115, 1E116, 1E117, 1E118, 1E119, 1E120, 1E121, 1E122, 1E123, 1E124, 1E125, 1E126, 1E127, 1E128, 1E129, 1E130, 1E131, 1E132, 1E133, 1E134, 1E135, 1E136, 1E137, 1E138, 1E139, 1E140, 1E141, 1E142, 1E143, 1E144, 1E145, 1E146, 1E147, 1E148, 1E149, 1E150, 1E151, 1E152, 1E153, 1E154, 1E155, 1E156, 1E157, 1E158, 1E159, 1E160, 1E161, 1E162, 1E163, 1E164, 1E165, 1E166, 1E167, 1E168, 1E169, 1E170, 1E171, 1E172, 1E173, 1E174, 1E175, 1E176, 1E177, 1E178, 1E179, 1E180, 1E181, 1E182, 1E183, 1E184, 1E185, 1E186, 1E187, 1E188, 1E189, 1E190, 1E191, 1E192, 1E193, 1E194, 1E195, 1E196, 1E197, 1E198, 1E199,
2273 1E200, 1E201, 1E202, 1E203, 1E204, 1E205, 1E206, 1E207, 1E208, 1E209, 1E210, 1E211, 1E212, 1E213, 1E214, 1E215, 1E216, 1E217, 1E218, 1E219, 1E220, 1E221, 1E222, 1E223, 1E224, 1E225, 1E226, 1E227, 1E228, 1E229, 1E230, 1E231, 1E232, 1E233, 1E234, 1E235, 1E236, 1E237, 1E238, 1E239, 1E240, 1E241, 1E242, 1E243, 1E244, 1E245, 1E246, 1E247, 1E248, 1E249, 1E250, 1E251, 1E252, 1E253, 1E254, 1E255, 1E256, 1E257, 1E258, 1E259, 1E260, 1E261, 1E262, 1E263, 1E264, 1E265, 1E266, 1E267, 1E268, 1E269, 1E270, 1E271, 1E272, 1E273, 1E274, 1E275, 1E276, 1E277, 1E278, 1E279, 1E280, 1E281, 1E282, 1E283, 1E284, 1E285, 1E286, 1E287, 1E288, 1E289, 1E290, 1E291, 1E292, 1E293, 1E294, 1E295, 1E296, 1E297, 1E298, 1E299,
2274 1E300, 1E301, 1E302, 1E303, 1E304, 1E305, 1E306, 1E307, 1E308];
2275 Double.NEGATIVE_POWERS = [
2276 1E0, 1E-1, 1E-2, 1E-3, 1E-4, 1E-5, 1E-6, 1E-7, 1E-8, 1E-9, 1E-10, 1E-11, 1E-12, 1E-13, 1E-14, 1E-15, 1E-16, 1E-17, 1E-18, 1E-19, 1E-20, 1E-21, 1E-22, 1E-23, 1E-24, 1E-25, 1E-26, 1E-27, 1E-28, 1E-29, 1E-30, 1E-31, 1E-32, 1E-33, 1E-34, 1E-35, 1E-36, 1E-37, 1E-38, 1E-39, 1E-40, 1E-41, 1E-42, 1E-43, 1E-44, 1E-45, 1E-46, 1E-47, 1E-48, 1E-49, 1E-50, 1E-51, 1E-52, 1E-53, 1E-54, 1E-55, 1E-56, 1E-57, 1E-58, 1E-59, 1E-60, 1E-61, 1E-62, 1E-63, 1E-64, 1E-65, 1E-66, 1E-67, 1E-68, 1E-69, 1E-70, 1E-71, 1E-72, 1E-73, 1E-74, 1E-75, 1E-76, 1E-77, 1E-78, 1E-79, 1E-80, 1E-81, 1E-82, 1E-83, 1E-84, 1E-85, 1E-86, 1E-87, 1E-88, 1E-89, 1E-90, 1E-91, 1E-92, 1E-93, 1E-94, 1E-95, 1E-96, 1E-97, 1E-98, 1E-99,
2277 1E-100, 1E-101, 1E-102, 1E-103, 1E-104, 1E-105, 1E-106, 1E-107, 1E-108, 1E-109, 1E-110, 1E-111, 1E-112, 1E-113, 1E-114, 1E-115, 1E-116, 1E-117, 1E-118, 1E-119, 1E-120, 1E-121, 1E-122, 1E-123, 1E-124, 1E-125, 1E-126, 1E-127, 1E-128, 1E-129, 1E-130, 1E-131, 1E-132, 1E-133, 1E-134, 1E-135, 1E-136, 1E-137, 1E-138, 1E-139, 1E-140, 1E-141, 1E-142, 1E-143, 1E-144, 1E-145, 1E-146, 1E-147, 1E-148, 1E-149, 1E-150, 1E-151, 1E-152, 1E-153, 1E-154, 1E-155, 1E-156, 1E-157, 1E-158, 1E-159, 1E-160, 1E-161, 1E-162, 1E-163, 1E-164, 1E-165, 1E-166, 1E-167, 1E-168, 1E-169, 1E-170, 1E-171, 1E-172, 1E-173, 1E-174, 1E-175, 1E-176, 1E-177, 1E-178, 1E-179, 1E-180, 1E-181, 1E-182, 1E-183, 1E-184, 1E-185, 1E-186, 1E-187, 1E-188, 1E-189, 1E-190, 1E-191, 1E-192, 1E-193, 1E-194, 1E-195, 1E-196, 1E-197, 1E-198, 1E-199,
2278 1E-200, 1E-201, 1E-202, 1E-203, 1E-204, 1E-205, 1E-206, 1E-207, 1E-208, 1E-209, 1E-210, 1E-211, 1E-212, 1E-213, 1E-214, 1E-215, 1E-216, 1E-217, 1E-218, 1E-219, 1E-220, 1E-221, 1E-222, 1E-223, 1E-224, 1E-225, 1E-226, 1E-227, 1E-228, 1E-229, 1E-230, 1E-231, 1E-232, 1E-233, 1E-234, 1E-235, 1E-236, 1E-237, 1E-238, 1E-239, 1E-240, 1E-241, 1E-242, 1E-243, 1E-244, 1E-245, 1E-246, 1E-247, 1E-248, 1E-249, 1E-250, 1E-251, 1E-252, 1E-253, 1E-254, 1E-255, 1E-256, 1E-257, 1E-258, 1E-259, 1E-260, 1E-261, 1E-262, 1E-263, 1E-264, 1E-265, 1E-266, 1E-267, 1E-268, 1E-269, 1E-270, 1E-271, 1E-272, 1E-273, 1E-274, 1E-275, 1E-276, 1E-277, 1E-278, 1E-279, 1E-280, 1E-281, 1E-282, 1E-283, 1E-284, 1E-285, 1E-286, 1E-287, 1E-288, 1E-289, 1E-290, 1E-291, 1E-292, 1E-293, 1E-294, 1E-295, 1E-296, 1E-297, 1E-298, 1E-299,
2279 1E-300, 1E-301, 1E-302, 1E-303, 1E-304, 1E-305, 1E-306, 1E-307, 1E-308, 1E-309, 1E-310, 1E-311, 1E-312, 1E-313, 1E-314, 1E-315, 1E-316, 1E-317, 1E-318, 1E-319, 1E-320, 1E-321, 1E-322, 1E-323, 1E-324];
2280 /**
2281 * Returns powers of 10.
2282 * Unlike the Math.pow this function produces no decimal garbage.
2283 * @param exp Exponent.
2284 */
2285 function pow10(exp) {
2286 debug.assertValue(exp, "exp");
2287 // Positive & zero
2288 if (exp >= 0) {
2289 if (exp < Double.POSITIVE_POWERS.length) {
2290 return Double.POSITIVE_POWERS[exp];
2291 }
2292 else {
2293 return Infinity;
2294 }
2295 }
2296 // Negative
2297 exp = -exp;
2298 if (exp > 0 && exp < Double.NEGATIVE_POWERS.length) {
2299 return Double.NEGATIVE_POWERS[exp];
2300 }
2301 else {
2302 return 0;
2303 }
2304 }
2305 Double.pow10 = pow10;
2306 /**
2307 * Returns the 10 base logarithm of the number.
2308 * Unlike Math.log function this produces integer results with no decimal garbage.
2309 * @param val Positive value or zero.
2310 */
2311 function log10(val) {
2312 debug.assert(val >= 0, "val");
2313 // Fast Log10() algorithm
2314 if (val > 1 && val < 1E16) {
2315 if (val < 1E8) {
2316 if (val < 1E4) {
2317 if (val < 1E2) {
2318 if (val < 1E1) {
2319 return 0;
2320 }
2321 else {
2322 return 1;
2323 }
2324 }
2325 else {
2326 if (val < 1E3) {
2327 return 2;
2328 }
2329 else {
2330 return 3;
2331 }
2332 }
2333 }
2334 else {
2335 if (val < 1E6) {
2336 if (val < 1E5) {
2337 return 4;
2338 }
2339 else {
2340 return 5;
2341 }
2342 }
2343 else {
2344 if (val < 1E7) {
2345 return 6;
2346 }
2347 else {
2348 return 7;
2349 }
2350 }
2351 }
2352 }
2353 else {
2354 if (val < 1E12) {
2355 if (val < 1E10) {
2356 if (val < 1E9) {
2357 return 8;
2358 }
2359 else {
2360 return 9;
2361 }
2362 }
2363 else {
2364 if (val < 1E11) {
2365 return 10;
2366 }
2367 else {
2368 return 11;
2369 }
2370 }
2371 }
2372 else {
2373 if (val < 1E14) {
2374 if (val < 1E13) {
2375 return 12;
2376 }
2377 else {
2378 return 13;
2379 }
2380 }
2381 else {
2382 if (val < 1E15) {
2383 return 14;
2384 }
2385 else {
2386 return 15;
2387 }
2388 }
2389 }
2390 }
2391 }
2392 if (val > 1E-16 && val < 1) {
2393 if (val < 1E-8) {
2394 if (val < 1E-12) {
2395 if (val < 1E-14) {
2396 if (val < 1E-15) {
2397 return -16;
2398 }
2399 else {
2400 return -15;
2401 }
2402 }
2403 else {
2404 if (val < 1E-13) {
2405 return -14;
2406 }
2407 else {
2408 return -13;
2409 }
2410 }
2411 }
2412 else {
2413 if (val < 1E-10) {
2414 if (val < 1E-11) {
2415 return -12;
2416 }
2417 else {
2418 return -11;
2419 }
2420 }
2421 else {
2422 if (val < 1E-9) {
2423 return -10;
2424 }
2425 else {
2426 return -9;
2427 }
2428 }
2429 }
2430 }
2431 else {
2432 if (val < 1E-4) {
2433 if (val < 1E-6) {
2434 if (val < 1E-7) {
2435 return -8;
2436 }
2437 else {
2438 return -7;
2439 }
2440 }
2441 else {
2442 if (val < 1E-5) {
2443 return -6;
2444 }
2445 else {
2446 return -5;
2447 }
2448 }
2449 }
2450 else {
2451 if (val < 1E-2) {
2452 if (val < 1E-3) {
2453 return -4;
2454 }
2455 else {
2456 return -3;
2457 }
2458 }
2459 else {
2460 if (val < 1E-1) {
2461 return -2;
2462 }
2463 else {
2464 return -1;
2465 }
2466 }
2467 }
2468 }
2469 }
2470 // JS Math provides only natural log function so we need to calc the 10 base logarithm:
2471 // logb(x) = logk(x)/logk(b);
2472 var log10 = Math.log(val) / Double.LOG_E_10;
2473 return Double.floorWithPrecision(log10);
2474 }
2475 Double.log10 = log10;
2476 /**
2477 * Returns a power of 10 representing precision of the number based on the number of meaningful decimal digits.
2478 * For example the precision of 56,263.3767 with the 6 meaningful decimal digit is 0.1.
2479 * @param x Value.
2480 * @param decimalDigits How many decimal digits are meaningfull.
2481 */
2482 function getPrecision(x, decimalDigits) {
2483 if (decimalDigits === undefined) {
2484 decimalDigits = Double.DEFAULT_PRECISION_IN_DECIMAL_DIGITS;
2485 }
2486 else {
2487 debug.assert(decimalDigits >= 0, "decimalDigits");
2488 }
2489 if (!x) {
2490 return undefined;
2491 }
2492 var exp = Double.log10(Math.abs(x));
2493 if (exp < Double.MIN_EXP) {
2494 return 0;
2495 }
2496 var precisionExp = Math.max(exp - decimalDigits, -Double.NEGATIVE_POWERS.length + 1);
2497 return Double.pow10(precisionExp);
2498 }
2499 Double.getPrecision = getPrecision;
2500 /**
2501 * Checks if a delta between 2 numbers is less than provided precision.
2502 * @param x One value.
2503 * @param y Another value.
2504 * @param precision Precision value.
2505 */
2506 function equalWithPrecision(x, y, precision) {
2507 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2508 debug.assert(precision >= 0, "precision");
2509 return x === y || Math.abs(x - y) < precision;
2510 }
2511 Double.equalWithPrecision = equalWithPrecision;
2512 /**
2513 * Checks if a first value is less than another taking
2514 * into account the loose precision based equality.
2515 * @param x One value.
2516 * @param y Another value.
2517 * @param precision Precision value.
2518 */
2519 function lessWithPrecision(x, y, precision) {
2520 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2521 debug.assert(precision >= 0, "precision");
2522 return x < y && Math.abs(x - y) > precision;
2523 }
2524 Double.lessWithPrecision = lessWithPrecision;
2525 /**
2526 * Checks if a first value is less or equal than another taking
2527 * into account the loose precision based equality.
2528 * @param x One value.
2529 * @param y Another value.
2530 * @param precision Precision value.
2531 */
2532 function lessOrEqualWithPrecision(x, y, precision) {
2533 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2534 debug.assert(precision >= 0, "precision");
2535 return x < y || Math.abs(x - y) < precision;
2536 }
2537 Double.lessOrEqualWithPrecision = lessOrEqualWithPrecision;
2538 /**
2539 * Checks if a first value is greater than another taking
2540 * into account the loose precision based equality.
2541 * @param x One value.
2542 * @param y Another value.
2543 * @param precision Precision value.
2544 */
2545 function greaterWithPrecision(x, y, precision) {
2546 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2547 debug.assert(precision >= 0, "precision");
2548 return x > y && Math.abs(x - y) > precision;
2549 }
2550 Double.greaterWithPrecision = greaterWithPrecision;
2551 /**
2552 * Checks if a first value is greater or equal to another taking
2553 * into account the loose precision based equality.
2554 * @param x One value.
2555 * @param y Another value.
2556 * @param precision Precision value.
2557 */
2558 function greaterOrEqualWithPrecision(x, y, precision) {
2559 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2560 debug.assert(precision >= 0, "precision");
2561 return x > y || Math.abs(x - y) < precision;
2562 }
2563 Double.greaterOrEqualWithPrecision = greaterOrEqualWithPrecision;
2564 /**
2565 * Floors the number unless it's withing the precision distance from the higher int.
2566 * @param x One value.
2567 * @param precision Precision value.
2568 */
2569 function floorWithPrecision(x, precision) {
2570 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2571 debug.assert(precision >= 0, "precision");
2572 var roundX = Math.round(x);
2573 if (Math.abs(x - roundX) < precision) {
2574 return roundX;
2575 }
2576 else {
2577 return Math.floor(x);
2578 }
2579 }
2580 Double.floorWithPrecision = floorWithPrecision;
2581 /**
2582 * Ceils the number unless it's withing the precision distance from the lower int.
2583 * @param x One value.
2584 * @param precision Precision value.
2585 */
2586 function ceilWithPrecision(x, precision) {
2587 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2588 debug.assert(precision >= 0, "precision");
2589 var roundX = Math.round(x);
2590 if (Math.abs(x - roundX) < precision) {
2591 return roundX;
2592 }
2593 else {
2594 return Math.ceil(x);
2595 }
2596 }
2597 Double.ceilWithPrecision = ceilWithPrecision;
2598 /**
2599 * Floors the number to the provided precision.
2600 * For example 234,578 floored to 1,000 precision is 234,000.
2601 * @param x One value.
2602 * @param precision Precision value.
2603 */
2604 function floorToPrecision(x, precision) {
2605 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2606 debug.assert(precision >= 0, "precision");
2607 if (precision === 0 || x === 0) {
2608 return x;
2609 }
2610 //Precision must be a Power of 10
2611 return Math.floor(x / precision) * precision;
2612 }
2613 Double.floorToPrecision = floorToPrecision;
2614 /**
2615 * Ceils the number to the provided precision.
2616 * For example 234,578 floored to 1,000 precision is 235,000.
2617 * @param x One value.
2618 * @param precision Precision value.
2619 */
2620 function ceilToPrecision(x, precision) {
2621 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2622 debug.assert(precision >= 0, "precision");
2623 if (precision === 0 || x === 0) {
2624 return x;
2625 }
2626 //Precision must be a Power of 10
2627 return Math.ceil(x / precision) * precision;
2628 }
2629 Double.ceilToPrecision = ceilToPrecision;
2630 /**
2631 * Rounds the number to the provided precision.
2632 * For example 234,578 floored to 1,000 precision is 235,000.
2633 * @param x One value.
2634 * @param precision Precision value.
2635 */
2636 function roundToPrecision(x, precision) {
2637 precision = applyDefault(precision, Double.DEFAULT_PRECISION);
2638 debug.assert(precision >= 0, "precision");
2639 if (precision === 0 || x === 0) {
2640 return x;
2641 }
2642 //Precision must be a Power of 10
2643 var result = Math.round(x / precision) * precision;
2644 var decimalDigits = Math.round(Double.log10(Math.abs(x)) - Double.log10(precision)) + 1;
2645 if (decimalDigits > 0 && decimalDigits < 16) {
2646 result = parseFloat(result.toPrecision(decimalDigits));
2647 }
2648 return result;
2649 }
2650 Double.roundToPrecision = roundToPrecision;
2651 /**
2652 * Returns the value making sure that it's restricted to the provided range.
2653 * @param x One value.
2654 * @param min Range min boundary.
2655 * @param max Range max boundary.
2656 */
2657 function ensureInRange(x, min, max) {
2658 debug.assert(min <= max, "min must be less or equal to max");
2659 if (x === undefined || x === null) {
2660 return x;
2661 }
2662 if (x < min) {
2663 return min;
2664 }
2665 if (x > max) {
2666 return max;
2667 }
2668 return x;
2669 }
2670 Double.ensureInRange = ensureInRange;
2671 /**
2672 * Rounds the value - this method is actually faster than Math.round - used in the graphics utils.
2673 * @param x Value to round.
2674 */
2675 function round(x) {
2676 debug.assert(x >= 0, "x must be greater or equal to 0");
2677 return (0.5 + x) << 0;
2678 }
2679 Double.round = round;
2680 /**
2681 * Projects the value from the source range into the target range.
2682 * @param value Value to project.
2683 * @param fromMin Minimum of the source range.
2684 * @param toMin Minimum of the target range.
2685 * @param toMax Maximum of the target range.
2686 */
2687 function project(value, fromMin, fromSize, toMin, toSize) {
2688 if (fromSize === 0 || toSize === 0) {
2689 if (fromMin <= value && value <= fromMin + fromSize) {
2690 return toMin;
2691 }
2692 else {
2693 return NaN;
2694 }
2695 }
2696 var relativeX = (value - fromMin) / fromSize;
2697 var projectedX = toMin + relativeX * toSize;
2698 return projectedX;
2699 }
2700 Double.project = project;
2701 /**
2702 * Removes decimal noise.
2703 * @param value Value to be processed.
2704 */
2705 function removeDecimalNoise(value) {
2706 return roundToPrecision(value, getPrecision(value));
2707 }
2708 Double.removeDecimalNoise = removeDecimalNoise;
2709 /**
2710 * Checks whether the number is integer.
2711 * @param value Value to be checked.
2712 */
2713 function isInteger(value) {
2714 return value !== null && value % 1 === 0;
2715 }
2716 Double.isInteger = isInteger;
2717 /**
2718 * Dividing by increment will give us count of increments
2719 * Round out the rough edges into even integer
2720 * Multiply back by increment to get rounded value
2721 * e.g. Rounder.toIncrement(0.647291, 0.05) => 0.65
2722 * @param value - value to round to nearest increment
2723 * @param increment - smallest increment to round toward
2724 */
2725 function toIncrement(value, increment) {
2726 return Math.round(value / increment) * increment;
2727 }
2728 Double.toIncrement = toIncrement;
2729 })(Double = powerbi.Double || (powerbi.Double = {}));
2730 function applyDefault(value, defaultValue) {
2731 return value !== undefined ? value : defaultValue;
2732 }
2733})(powerbi || (powerbi = {}));
2734/*
2735 * Power BI Visualizations
2736 *
2737 * Copyright (c) Microsoft Corporation
2738 * All rights reserved.
2739 * MIT License
2740 *
2741 * Permission is hereby granted, free of charge, to any person obtaining a copy
2742 * of this software and associated documentation files (the ""Software""), to deal
2743 * in the Software without restriction, including without limitation the rights
2744 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2745 * copies of the Software, and to permit persons to whom the Software is
2746 * furnished to do so, subject to the following conditions:
2747 *
2748 * The above copyright notice and this permission notice shall be included in
2749 * all copies or substantial portions of the Software.
2750 *
2751 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2752 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2753 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2754 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2755 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2756 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2757 * THE SOFTWARE.
2758 */
2759var jsCommon;
2760(function (jsCommon) {
2761 var Double = powerbi.Double;
2762 var Color;
2763 (function (Color) {
2764 function rotate(rgbString, rotateFactor) {
2765 if (rotateFactor === 0)
2766 return rgbString;
2767 var originalRgb = parseColorString(rgbString);
2768 var originalHsv = rgbToHsv(originalRgb);
2769 var rotatedHsv = rotateHsv(originalHsv, rotateFactor);
2770 var rotatedRgb = hsvToRgb(rotatedHsv);
2771 return hexString(rotatedRgb);
2772 }
2773 Color.rotate = rotate;
2774 function normalizeToHexString(color) {
2775 var rgb = parseColorString(color);
2776 return hexString(rgb);
2777 }
2778 Color.normalizeToHexString = normalizeToHexString;
2779 function parseColorString(color) {
2780 debug.assertValue(color, 'color');
2781 if (color.indexOf('#') >= 0) {
2782 if (color.length === 7) {
2783 // #RRGGBB
2784 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
2785 if (result == null || result.length < 4)
2786 return;
2787 return {
2788 R: parseInt(result[1], 16),
2789 G: parseInt(result[2], 16),
2790 B: parseInt(result[3], 16),
2791 };
2792 }
2793 else if (color.length === 4) {
2794 // #RGB
2795 var result = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(color);
2796 if (result == null || result.length < 4)
2797 return;
2798 return {
2799 R: parseInt(result[1] + result[1], 16),
2800 G: parseInt(result[2] + result[2], 16),
2801 B: parseInt(result[3] + result[3], 16),
2802 };
2803 }
2804 }
2805 else if (color.indexOf('rgb(') >= 0) {
2806 // rgb(R, G, B)
2807 var result = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.exec(color);
2808 if (result == null || result.length < 4)
2809 return;
2810 return {
2811 R: parseInt(result[1], 10),
2812 G: parseInt(result[2], 10),
2813 B: parseInt(result[3], 10),
2814 };
2815 }
2816 else if (color.indexOf('rgba(') >= 0) {
2817 // rgba(R, G, B, A)
2818 var result = /^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d*(?:\.\d+)?)\)$/.exec(color);
2819 if (result == null || result.length < 5)
2820 return;
2821 return {
2822 R: parseInt(result[1], 10),
2823 G: parseInt(result[2], 10),
2824 B: parseInt(result[3], 10),
2825 A: parseFloat(result[4]),
2826 };
2827 }
2828 }
2829 Color.parseColorString = parseColorString;
2830 function rgbToHsv(rgbColor) {
2831 var s, h;
2832 var r = rgbColor.R / 255, g = rgbColor.G / 255, b = rgbColor.B / 255;
2833 var min = Math.min(r, Math.min(g, b));
2834 var max = Math.max(r, Math.max(g, b));
2835 var v = max;
2836 var delta = max - min;
2837 if (max === 0 || delta === 0) {
2838 // R, G, and B must be 0.0, or all the same.
2839 // In this case, S is 0.0, and H is undefined.
2840 // Using H = 0.0 is as good as any...
2841 s = 0;
2842 h = 0;
2843 }
2844 else {
2845 s = delta / max;
2846 if (r === max) {
2847 // Between Yellow and Magenta
2848 h = (g - b) / delta;
2849 }
2850 else if (g === max) {
2851 // Between Cyan and Yellow
2852 h = 2 + (b - r) / delta;
2853 }
2854 else {
2855 // Between Magenta and Cyan
2856 h = 4 + (r - g) / delta;
2857 }
2858 }
2859 // Scale h to be between 0.0 and 1.
2860 // This may require adding 1, if the value
2861 // is negative.
2862 h /= 6;
2863 if (h < 0) {
2864 h += 1;
2865 }
2866 return {
2867 H: h,
2868 S: s,
2869 V: v,
2870 };
2871 }
2872 function hsvToRgb(hsvColor) {
2873 var r, g, b;
2874 var h = hsvColor.H, s = hsvColor.S, v = hsvColor.V;
2875 if (s === 0) {
2876 // If s is 0, all colors are the same.
2877 // This is some flavor of gray.
2878 r = v;
2879 g = v;
2880 b = v;
2881 }
2882 else {
2883 var p = void 0, q = void 0, t = void 0, fractionalSector = void 0, sectorNumber = void 0, sectorPos = void 0;
2884 // The color wheel consists of 6 sectors.
2885 // Figure out which sector you//re in.
2886 sectorPos = h * 6;
2887 sectorNumber = Math.floor(sectorPos);
2888 // get the fractional part of the sector.
2889 // That is, how many degrees into the sector
2890 // are you?
2891 fractionalSector = sectorPos - sectorNumber;
2892 // Calculate values for the three axes
2893 // of the color.
2894 p = v * (1.0 - s);
2895 q = v * (1.0 - (s * fractionalSector));
2896 t = v * (1.0 - (s * (1 - fractionalSector)));
2897 // Assign the fractional colors to r, g, and b
2898 // based on the sector the angle is in.
2899 switch (sectorNumber) {
2900 case 0:
2901 r = v;
2902 g = t;
2903 b = p;
2904 break;
2905 case 1:
2906 r = q;
2907 g = v;
2908 b = p;
2909 break;
2910 case 2:
2911 r = p;
2912 g = v;
2913 b = t;
2914 break;
2915 case 3:
2916 r = p;
2917 g = q;
2918 b = v;
2919 break;
2920 case 4:
2921 r = t;
2922 g = p;
2923 b = v;
2924 break;
2925 case 5:
2926 r = v;
2927 g = p;
2928 b = q;
2929 break;
2930 }
2931 }
2932 return {
2933 R: Math.floor(r * 255),
2934 G: Math.floor(g * 255),
2935 B: Math.floor(b * 255),
2936 };
2937 }
2938 function rotateHsv(hsvColor, rotateFactor) {
2939 var newH = hsvColor.H + rotateFactor;
2940 return {
2941 H: newH > 1 ? newH - 1 : newH,
2942 S: hsvColor.S,
2943 V: hsvColor.V,
2944 };
2945 }
2946 function darken(color, diff) {
2947 var flooredNumber = Math.floor(diff);
2948 return {
2949 R: Math.max(0, color.R - flooredNumber),
2950 G: Math.max(0, color.G - flooredNumber),
2951 B: Math.max(0, color.B - flooredNumber),
2952 };
2953 }
2954 Color.darken = darken;
2955 function rgbString(color) {
2956 if (color.A == null)
2957 return "rgb(" + color.R + "," + color.G + "," + color.B + ")";
2958 return "rgba(" + color.R + "," + color.G + "," + color.B + "," + color.A + ")";
2959 }
2960 Color.rgbString = rgbString;
2961 function hexString(color) {
2962 return "#" + componentToHex(color.R) + componentToHex(color.G) + componentToHex(color.B);
2963 }
2964 Color.hexString = hexString;
2965 function componentToHex(hexComponent) {
2966 var clamped = Double.ensureInRange(hexComponent, 0, 255);
2967 var hex = clamped.toString(16).toUpperCase();
2968 return hex.length === 1 ? "0" + hex : hex;
2969 }
2970 })(Color = jsCommon.Color || (jsCommon.Color = {}));
2971})(jsCommon || (jsCommon = {}));
2972/*
2973 * Power BI Visualizations
2974 *
2975 * Copyright (c) Microsoft Corporation
2976 * All rights reserved.
2977 * MIT License
2978 *
2979 * Permission is hereby granted, free of charge, to any person obtaining a copy
2980 * of this software and associated documentation files (the ""Software""), to deal
2981 * in the Software without restriction, including without limitation the rights
2982 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2983 * copies of the Software, and to permit persons to whom the Software is
2984 * furnished to do so, subject to the following conditions:
2985 *
2986 * The above copyright notice and this permission notice shall be included in
2987 * all copies or substantial portions of the Software.
2988 *
2989 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2990 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2991 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2992 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2993 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2994 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2995 * THE SOFTWARE.
2996 */
2997var jsCommon;
2998(function (jsCommon) {
2999 /**
3000 * CSS constants.
3001 */
3002 var CssConstants;
3003 (function (CssConstants) {
3004 function createClassAndSelector(className) {
3005 return {
3006 class: className,
3007 selector: '.' + className,
3008 };
3009 }
3010 CssConstants.createClassAndSelector = createClassAndSelector;
3011 CssConstants.styleAttribute = 'style';
3012 CssConstants.pixelUnits = 'px';
3013 CssConstants.heightProperty = 'height';
3014 CssConstants.widthProperty = 'width';
3015 CssConstants.topProperty = 'top';
3016 CssConstants.bottomProperty = 'bottom';
3017 CssConstants.leftProperty = 'left';
3018 CssConstants.rightProperty = 'right';
3019 CssConstants.marginTopProperty = 'margin-top';
3020 CssConstants.marginLeftProperty = 'margin-left';
3021 CssConstants.displayProperty = 'display';
3022 CssConstants.backgroundProperty = 'background';
3023 CssConstants.backgroundColorProperty = 'background-color';
3024 CssConstants.backgroundRepeatProperty = 'background-repeat';
3025 CssConstants.backgroundSizeProperty = 'background-size';
3026 CssConstants.backgroundImageProperty = 'background-image';
3027 CssConstants.textShadowProperty = 'text-shadow';
3028 CssConstants.textAlignProperty = 'text-align';
3029 CssConstants.borderTopWidthProperty = 'border-top-width';
3030 CssConstants.borderBottomWidthProperty = 'border-bottom-width';
3031 CssConstants.borderLeftWidthProperty = 'border-left-width';
3032 CssConstants.borderRightWidthProperty = 'border-right-width';
3033 CssConstants.fontSizeProperty = 'font-size';
3034 CssConstants.fontWeightProperty = 'font-weight';
3035 CssConstants.colorProperty = 'color';
3036 CssConstants.opacityProperty = 'opacity';
3037 CssConstants.paddingLeftProperty = 'padding-left';
3038 CssConstants.paddingRightProperty = 'padding-right';
3039 CssConstants.positionProperty = 'position';
3040 CssConstants.maxWidthProperty = 'max-width';
3041 CssConstants.minWidthProperty = 'min-width';
3042 CssConstants.overflowProperty = 'overflow';
3043 CssConstants.overflowXProperty = 'overflow-x';
3044 CssConstants.overflowYProperty = 'overflow-y';
3045 CssConstants.transformProperty = 'transform';
3046 CssConstants.webkitTransformProperty = '-webkit-transform';
3047 CssConstants.cursorProperty = 'cursor';
3048 CssConstants.visibilityProperty = 'visibility';
3049 CssConstants.absoluteValue = 'absolute';
3050 CssConstants.zeroPixelValue = '0px';
3051 CssConstants.autoValue = 'auto';
3052 CssConstants.hiddenValue = 'hidden';
3053 CssConstants.noneValue = 'none';
3054 CssConstants.blockValue = 'block';
3055 CssConstants.inlineBlockValue = 'inline-block';
3056 CssConstants.transparentValue = 'transparent';
3057 CssConstants.boldValue = 'bold';
3058 CssConstants.visibleValue = 'visible';
3059 CssConstants.tableRowValue = 'table-row';
3060 CssConstants.coverValue = 'cover';
3061 CssConstants.pointerValue = 'pointer';
3062 CssConstants.scrollValue = 'scroll';
3063 })(CssConstants = jsCommon.CssConstants || (jsCommon.CssConstants = {}));
3064})(jsCommon || (jsCommon = {}));
3065/*
3066 * Power BI Visualizations
3067 *
3068 * Copyright (c) Microsoft Corporation
3069 * All rights reserved.
3070 * MIT License
3071 *
3072 * Permission is hereby granted, free of charge, to any person obtaining a copy
3073 * of this software and associated documentation files (the ""Software""), to deal
3074 * in the Software without restriction, including without limitation the rights
3075 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3076 * copies of the Software, and to permit persons to whom the Software is
3077 * furnished to do so, subject to the following conditions:
3078 *
3079 * The above copyright notice and this permission notice shall be included in
3080 * all copies or substantial portions of the Software.
3081 *
3082 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3083 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3084 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3085 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3086 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3087 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3088 * THE SOFTWARE.
3089 */
3090/**
3091 * Defines a Debug object. Calls to any functions in this object removed by the minifier.
3092 * The functions within this class are not minified away, so we use the preprocessor-style
3093 * comments to have the minifier remove those as well.
3094 */
3095///#DEBUG
3096var debug;
3097(function (debug) {
3098 /**
3099 * Asserts that the condition is true, fails otherwise.
3100 */
3101 function assert(condition, message) {
3102 if (condition !== true) {
3103 assertFail(message || ('condition: ' + condition));
3104 }
3105 }
3106 debug.assert = assert;
3107 /**
3108 * Asserts that the value is neither null nor undefined, fails otherwise.
3109 */
3110 function assertValue(value, message) {
3111 if (value === null || value === undefined) {
3112 assertFail(message || ('condition: ' + value));
3113 }
3114 }
3115 debug.assertValue = assertValue;
3116 /**
3117 * Asserts that the value is neither null nor undefined, and has a length property that returns greater than zero, fails otherwise.
3118 */
3119 function assertNonEmpty(value, message) {
3120 if (!(value != null && value.length > 0)) {
3121 assertFail(message || ('condition: ' + value));
3122 }
3123 }
3124 debug.assertNonEmpty = assertNonEmpty;
3125 /**
3126 * Makes no assertion on the given value.
3127 * This is documentation/placeholder that a value is possibly null or undefined (unlike assertValue).
3128 */
3129 function assertAnyValue(value, message) {
3130 }
3131 debug.assertAnyValue = assertAnyValue;
3132 function assertFail(message) {
3133 (debug.assertFailFunction || alert)('Debug Assert failed: ' + message);
3134 }
3135 debug.assertFail = assertFail;
3136})(debug || (debug = {}));
3137///#ENDDEBUG
3138/*
3139 * Power BI Visualizations
3140 *
3141 * Copyright (c) Microsoft Corporation
3142 * All rights reserved.
3143 * MIT License
3144 *
3145 * Permission is hereby granted, free of charge, to any person obtaining a copy
3146 * of this software and associated documentation files (the ""Software""), to deal
3147 * in the Software without restriction, including without limitation the rights
3148 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3149 * copies of the Software, and to permit persons to whom the Software is
3150 * furnished to do so, subject to the following conditions:
3151 *
3152 * The above copyright notice and this permission notice shall be included in
3153 * all copies or substantial portions of the Software.
3154 *
3155 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3156 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3157 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3158 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3159 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3160 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3161 * THE SOFTWARE.
3162 */
3163var jsCommon;
3164(function (jsCommon) {
3165 var Errors;
3166 (function (Errors) {
3167 function infoNavAppAlreadyPresent() {
3168 return {
3169 name: 'infoNavAppAlreadyPresent',
3170 message: 'Cannot initialize embedded scenario when the InfoNav App is already present in this context',
3171 stack: getExceptionStackTrace()
3172 };
3173 }
3174 Errors.infoNavAppAlreadyPresent = infoNavAppAlreadyPresent;
3175 function invalidOperation(message) {
3176 return {
3177 name: 'invalidOperation',
3178 message: message,
3179 stack: getExceptionStackTrace()
3180 };
3181 }
3182 Errors.invalidOperation = invalidOperation;
3183 function argument(argumentName, message) {
3184 return {
3185 name: 'invalidArgumentError',
3186 argument: argumentName,
3187 message: message,
3188 stack: getExceptionStackTrace()
3189 };
3190 }
3191 Errors.argument = argument;
3192 function argumentNull(argumentName) {
3193 return {
3194 name: 'argumentNull',
3195 argument: argumentName,
3196 message: 'Argument was null',
3197 stack: getExceptionStackTrace()
3198 };
3199 }
3200 Errors.argumentNull = argumentNull;
3201 function argumentUndefined(argumentName) {
3202 return {
3203 name: 'argumentUndefined',
3204 argument: argumentName,
3205 message: 'Argument was undefined',
3206 stack: getExceptionStackTrace()
3207 };
3208 }
3209 Errors.argumentUndefined = argumentUndefined;
3210 function argumentOutOfRange(argumentName) {
3211 return {
3212 name: 'argumentOutOfRange',
3213 argument: argumentName,
3214 message: 'Argument was out of range',
3215 stack: getExceptionStackTrace()
3216 };
3217 }
3218 Errors.argumentOutOfRange = argumentOutOfRange;
3219 function pureVirtualMethodException(className, methodName) {
3220 return {
3221 name: 'pureVirtualMethodException',
3222 message: 'This method must be overriden by the derived class:' + className + '.' + methodName,
3223 stack: getExceptionStackTrace()
3224 };
3225 }
3226 Errors.pureVirtualMethodException = pureVirtualMethodException;
3227 function notImplementedException(message) {
3228 return {
3229 name: 'notImplementedException',
3230 message: message,
3231 stack: getExceptionStackTrace()
3232 };
3233 }
3234 Errors.notImplementedException = notImplementedException;
3235 function getExceptionStackTrace() {
3236 return getStackTrace(/*leadingFramesToRemove*/ 2);
3237 }
3238 })(Errors = jsCommon.Errors || (jsCommon.Errors = {}));
3239 /**
3240 * Captures the stack trace, if available.
3241 * It optionally takes the number of frames to remove from the stack trace.
3242 * By default, it removes the last frame to consider the calling type's
3243 * constructor and the temporary error used to capture the stack trace (below).
3244 * More levels can be requested as needed e..g. when an error is created
3245 * from a helper method. <Min requirement: IE10, Chrome, Firefox, Opera>.
3246 */
3247 function getStackTrace(leadingFramesToRemove) {
3248 if (leadingFramesToRemove === void 0) { leadingFramesToRemove = 1; }
3249 var stackTrace, stackSegments;
3250 try {
3251 // needs to throw for stack trace to work in IE
3252 throw new Error();
3253 }
3254 catch (error) {
3255 stackTrace = error.stack;
3256 if (stackTrace != null) {
3257 stackSegments = stackTrace.split('\n');
3258 stackSegments.splice(1, leadingFramesToRemove);
3259 // Finally
3260 stackTrace = stackSegments.join('\n');
3261 }
3262 }
3263 return stackTrace;
3264 }
3265 jsCommon.getStackTrace = getStackTrace;
3266})(jsCommon || (jsCommon = {}));
3267/*
3268 * Power BI Visualizations
3269 *
3270 * Copyright (c) Microsoft Corporation
3271 * All rights reserved.
3272 * MIT License
3273 *
3274 * Permission is hereby granted, free of charge, to any person obtaining a copy
3275 * of this software and associated documentation files (the ""Software""), to deal
3276 * in the Software without restriction, including without limitation the rights
3277 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3278 * copies of the Software, and to permit persons to whom the Software is
3279 * furnished to do so, subject to the following conditions:
3280 *
3281 * The above copyright notice and this permission notice shall be included in
3282 * all copies or substantial portions of the Software.
3283 *
3284 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3285 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3286 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3287 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3288 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3289 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3290 * THE SOFTWARE.
3291 */
3292$.fn.multiline = function (text) {
3293 this.text(text);
3294 this.html(this.html().replace(/\n/g, '<br/>'));
3295 return this;
3296};
3297$.fn.togglePanelControl = function () {
3298 return this.each(function () {
3299 $(this).addClass("ui-accordion ui-accordion-icons ui-widget ui-helper-reset")
3300 .find(".accordionHeader")
3301 .addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom")
3302 .hover(function () {
3303 $(this).toggleClass("ui-state-hover");
3304 })
3305 .prepend('<span class="ui-icon ui-icon-triangle-1-e"></span>')
3306 .click(function () {
3307 $(this)
3308 .toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
3309 .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s").end()
3310 .next().slideToggle();
3311 return false;
3312 })
3313 .next()
3314 .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom")
3315 .hide();
3316 });
3317};
3318var jsCommon;
3319(function (jsCommon) {
3320 var JQueryConstants;
3321 (function (JQueryConstants) {
3322 JQueryConstants.VisibleSelector = ':visible';
3323 })(JQueryConstants = jsCommon.JQueryConstants || (jsCommon.JQueryConstants = {}));
3324})(jsCommon || (jsCommon = {}));
3325/*
3326 * Power BI Visualizations
3327 *
3328 * Copyright (c) Microsoft Corporation
3329 * All rights reserved.
3330 * MIT License
3331 *
3332 * Permission is hereby granted, free of charge, to any person obtaining a copy
3333 * of this software and associated documentation files (the ""Software""), to deal
3334 * in the Software without restriction, including without limitation the rights
3335 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3336 * copies of the Software, and to permit persons to whom the Software is
3337 * furnished to do so, subject to the following conditions:
3338 *
3339 * The above copyright notice and this permission notice shall be included in
3340 * all copies or substantial portions of the Software.
3341 *
3342 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3343 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3344 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3345 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3346 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3347 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3348 * THE SOFTWARE.
3349 */
3350var jsCommon;
3351(function (jsCommon) {
3352 /**
3353 * Represents a lazily instantiated value.
3354 */
3355 var Lazy = (function () {
3356 function Lazy(factoryMethod) {
3357 jsCommon.Utility.throwIfNullOrUndefined(factoryMethod, this, 'constructor', 'factoryMethod');
3358 this.factoryMethod = factoryMethod;
3359 }
3360 Lazy.prototype.getValue = function () {
3361 if (this.factoryMethod !== null) {
3362 this.value = this.factoryMethod();
3363 // Optimization: Release the factoryMethod, as it could be holding a large object graph.
3364 this.factoryMethod = null;
3365 }
3366 return this.value;
3367 };
3368 return Lazy;
3369 }());
3370 jsCommon.Lazy = Lazy;
3371})(jsCommon || (jsCommon = {}));
3372/*
3373 * Power BI Visualizations
3374 *
3375 * Copyright (c) Microsoft Corporation
3376 * All rights reserved.
3377 * MIT License
3378 *
3379 * Permission is hereby granted, free of charge, to any person obtaining a copy
3380 * of this software and associated documentation files (the ""Software""), to deal
3381 * in the Software without restriction, including without limitation the rights
3382 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3383 * copies of the Software, and to permit persons to whom the Software is
3384 * furnished to do so, subject to the following conditions:
3385 *
3386 * The above copyright notice and this permission notice shall be included in
3387 * all copies or substantial portions of the Software.
3388 *
3389 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3390 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3391 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3392 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3393 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3394 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3395 * THE SOFTWARE.
3396 */
3397var powerbi;
3398(function (powerbi) {
3399 var Prototype;
3400 (function (Prototype) {
3401 /**
3402 * Returns a new object with the provided obj as its prototype.
3403 */
3404 function inherit(obj, extension) {
3405 debug.assertValue(obj, 'obj');
3406 function wrapCtor() { }
3407 ;
3408 wrapCtor.prototype = obj;
3409 var inherited = new wrapCtor();
3410 if (extension)
3411 extension(inherited);
3412 return inherited;
3413 }
3414 Prototype.inherit = inherit;
3415 /**
3416 * Returns a new object with the provided obj as its prototype
3417 * if, and only if, the prototype has not been previously set
3418 */
3419 function inheritSingle(obj) {
3420 debug.assertValue(obj, 'obj');
3421 var proto = Object.getPrototypeOf(obj);
3422 if (proto === Object.prototype || proto === Array.prototype)
3423 obj = inherit(obj);
3424 return obj;
3425 }
3426 Prototype.inheritSingle = inheritSingle;
3427 /**
3428 * Uses the provided callback function to selectively replace contents in the provided array.
3429 * @return A new array with those values overriden
3430 * or undefined if no overrides are necessary.
3431 */
3432 function overrideArray(prototype, override) {
3433 if (!prototype)
3434 return;
3435 var overwritten;
3436 for (var i = 0, len = prototype.length; i < len; i++) {
3437 var value = override(prototype[i]);
3438 if (value) {
3439 if (!overwritten)
3440 overwritten = inherit(prototype);
3441 overwritten[i] = value;
3442 }
3443 }
3444 return overwritten;
3445 }
3446 Prototype.overrideArray = overrideArray;
3447 })(Prototype = powerbi.Prototype || (powerbi.Prototype = {}));
3448})(powerbi || (powerbi = {}));
3449/*
3450 * Power BI Visualizations
3451 *
3452 * Copyright (c) Microsoft Corporation
3453 * All rights reserved.
3454 * MIT License
3455 *
3456 * Permission is hereby granted, free of charge, to any person obtaining a copy
3457 * of this software and associated documentation files (the ""Software""), to deal
3458 * in the Software without restriction, including without limitation the rights
3459 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3460 * copies of the Software, and to permit persons to whom the Software is
3461 * furnished to do so, subject to the following conditions:
3462 *
3463 * The above copyright notice and this permission notice shall be included in
3464 * all copies or substantial portions of the Software.
3465 *
3466 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3467 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3468 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3469 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3470 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3471 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3472 * THE SOFTWARE.
3473 */
3474/*
3475 * Power BI Visualizations
3476 *
3477 * Copyright (c) Microsoft Corporation
3478 * All rights reserved.
3479 * MIT License
3480 *
3481 * Permission is hereby granted, free of charge, to any person obtaining a copy
3482 * of this software and associated documentation files (the ""Software""), to deal
3483 * in the Software without restriction, including without limitation the rights
3484 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3485 * copies of the Software, and to permit persons to whom the Software is
3486 * furnished to do so, subject to the following conditions:
3487 *
3488 * The above copyright notice and this permission notice shall be included in
3489 * all copies or substantial portions of the Software.
3490 *
3491 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3492 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3493 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3494 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3495 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3496 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3497 * THE SOFTWARE.
3498 */
3499/*
3500 * Power BI Visualizations
3501 *
3502 * Copyright (c) Microsoft Corporation
3503 * All rights reserved.
3504 * MIT License
3505 *
3506 * Permission is hereby granted, free of charge, to any person obtaining a copy
3507 * of this software and associated documentation files (the ""Software""), to deal
3508 * in the Software without restriction, including without limitation the rights
3509 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3510 * copies of the Software, and to permit persons to whom the Software is
3511 * furnished to do so, subject to the following conditions:
3512 *
3513 * The above copyright notice and this permission notice shall be included in
3514 * all copies or substantial portions of the Software.
3515 *
3516 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3517 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3518 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3519 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3520 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3521 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3522 * THE SOFTWARE.
3523 */
3524var jsCommon;
3525(function (jsCommon) {
3526 var Formatting;
3527 (function (Formatting) {
3528 var regexCache;
3529 /**
3530 * Translate .NET format into something supported by jQuery.Globalize.
3531 */
3532 function findDateFormat(value, format, cultureName) {
3533 switch (format) {
3534 case "m":
3535 // Month + day
3536 format = "M";
3537 break;
3538 case "O":
3539 case "o":
3540 // Roundtrip
3541 format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'0000'";
3542 break;
3543 case "R":
3544 case "r":
3545 // RFC1123 pattern - - time must be converted to UTC before formatting
3546 value = new Date(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate(), value.getUTCHours(), value.getUTCMinutes(), value.getUTCSeconds(), value.getUTCMilliseconds());
3547 format = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
3548 break;
3549 case "s":
3550 // Sortable - should use invariant culture
3551 format = "S";
3552 break;
3553 case "u":
3554 // Universal sortable - should convert to UTC before applying the "yyyy'-'MM'-'dd HH':'mm':'ss'Z' format.
3555 value = new Date(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate(), value.getUTCHours(), value.getUTCMinutes(), value.getUTCSeconds(), value.getUTCMilliseconds());
3556 format = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
3557 break;
3558 case "U":
3559 // Universal full - the pattern is same as F but the time must be converted to UTC before formatting
3560 value = new Date(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate(), value.getUTCHours(), value.getUTCMinutes(), value.getUTCSeconds(), value.getUTCMilliseconds());
3561 format = "F";
3562 break;
3563 case "y":
3564 case "Y":
3565 // Year and month
3566 switch (cultureName) {
3567 case "default":
3568 case "en":
3569 case "en-US":
3570 format = "MMMM, yyyy"; // Fix the default year-month pattern for english
3571 break;
3572 default:
3573 format = "Y"; // For other cultures - use the localized pattern
3574 }
3575 break;
3576 }
3577 return { value: value, format: format };
3578 }
3579 Formatting.findDateFormat = findDateFormat;
3580 /**
3581 * Translates unsupported .NET custom format expressions to the custom expressions supported by JQuery.Globalize.
3582 */
3583 function fixDateTimeFormat(format) {
3584 // Fix for the "K" format (timezone):
3585 //The js dates don't have a kind property so we'll support only local kind which is equavalent to zzz format.
3586 format = format.replace(/%K/g, "zzz");
3587 format = format.replace(/K/g, "zzz");
3588 format = format.replace(/fffffff/g, "fff0000");
3589 format = format.replace(/ffffff/g, "fff000");
3590 format = format.replace(/fffff/g, "fff00");
3591 format = format.replace(/ffff/g, "fff0");
3592 // Fix for the 5 digit year: "yyyyy" format.
3593 //The Globalize doesn't support dates greater than 9999 so we replace the "yyyyy" with "0yyyy".
3594 format = format.replace(/yyyyy/g, "0yyyy");
3595 // Fix for the 3 digit year: "yyy" format.
3596 //The Globalize doesn't support this formatting so we need to replace it with the 4 digit year "yyyy" format.
3597 format = format.replace(/(^y|^)yyy(^y|$)/g, "yyyy");
3598 if (!regexCache) {
3599 // Creating Regexes for cases "Using single format specifier"
3600 //- http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx#UsingSingleSpecifiers
3601 // This is not supported from The Globalize.
3602 // The case covers all single "%" lead specifier (like "%d" but not %dd)
3603 // The cases as single "%d" are filtered in if the bellow.
3604 // (?!S) where S is the specifier make sure that we only one symbol for specifier.
3605 regexCache = ["d", "f", "F", "g", "h", "H", "K", "m", "M", "s", "t", "y", "z", ":", "/"].map(function (s) {
3606 return { r: new RegExp("\%" + s + "(?!" + s + ")", "g"), s: s };
3607 });
3608 }
3609 if (format.indexOf("%") !== -1 && format.length > 2) {
3610 for (var i = 0; i < regexCache.length; i++) {
3611 format = format.replace(regexCache[i].r, regexCache[i].s);
3612 }
3613 }
3614 return format;
3615 }
3616 Formatting.fixDateTimeFormat = fixDateTimeFormat;
3617 })(Formatting = jsCommon.Formatting || (jsCommon.Formatting = {}));
3618})(jsCommon || (jsCommon = {}));
3619/*
3620 * Power BI Visualizations
3621 *
3622 * Copyright (c) Microsoft Corporation
3623 * All rights reserved.
3624 * MIT License
3625 *
3626 * Permission is hereby granted, free of charge, to any person obtaining a copy
3627 * of this software and associated documentation files (the ""Software""), to deal
3628 * in the Software without restriction, including without limitation the rights
3629 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3630 * copies of the Software, and to permit persons to whom the Software is
3631 * furnished to do so, subject to the following conditions:
3632 *
3633 * The above copyright notice and this permission notice shall be included in
3634 * all copies or substantial portions of the Software.
3635 *
3636 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3637 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3638 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3639 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3640 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3641 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3642 * THE SOFTWARE.
3643 */
3644var jsCommon;
3645(function (jsCommon) {
3646 var doc = document, headElement = doc.head, firstScriptInHeadElement = headElement.getElementsByTagName('script')[0], linkElement = doc.createElement('link'), scriptElement = doc.createElement('script'), styleSheetLoaded = [], javaScriptFilesLoaded = [], javaScriptFilesLoading = [];
3647 linkElement.setAttribute('rel', 'stylesheet');
3648 function requires(dependency, to) {
3649 if (to === void 0) { to = $.noop; }
3650 loadStyleSheets(dependency.cssFiles || []);
3651 var scriptsToRun = dependency.javaScriptFilesWithCallback || [];
3652 if (dependency.javaScriptFiles) {
3653 for (var i = 0, len = dependency.javaScriptFiles.length; i < len; ++i) {
3654 scriptsToRun.push({ javascriptFile: dependency.javaScriptFiles[i] });
3655 }
3656 }
3657 loadJavaScriptFiles(scriptsToRun, to);
3658 }
3659 jsCommon.requires = requires;
3660 /**
3661 * Private Helpers.
3662 */
3663 function loadStyleSheets(hrefList) {
3664 hrefList.forEach(function (href) {
3665 if (styleSheetLoaded.indexOf(href) === -1) {
3666 styleSheetLoaded.push(href);
3667 loadStyleSheet(href);
3668 }
3669 });
3670 }
3671 function loadJavaScriptFiles(scripts, callback) {
3672 var loadingCount = scripts.length, parsingCount = loadingCount, sourceCodeList = [];
3673 function parseIfLoadingComplete() {
3674 if (!--loadingCount) {
3675 parseJavaScriptSourceCodes(scripts, sourceCodeList);
3676 }
3677 }
3678 function makeCallbackIfParsingComplete() {
3679 if (!--parsingCount) {
3680 callback();
3681 }
3682 }
3683 scripts.forEach(function (script, index) {
3684 var file = script.javascriptFile;
3685 if (javaScriptFilesLoaded.indexOf(file) === -1) {
3686 if (file in javaScriptFilesLoading) {
3687 javaScriptFilesLoading[file].push(function () {
3688 parseIfLoadingComplete();
3689 makeCallbackIfParsingComplete();
3690 });
3691 }
3692 else {
3693 javaScriptFilesLoading[file] = [function () {
3694 makeCallbackIfParsingComplete();
3695 }];
3696 if (isExternalUrl(file)) {
3697 sourceCodeList[index] = script;
3698 parseIfLoadingComplete();
3699 }
3700 else {
3701 loadJavaScriptSourceCode(file, function (sourceCode) {
3702 sourceCodeList[index] = { javascriptFile: sourceCode };
3703 parseIfLoadingComplete();
3704 });
3705 }
3706 }
3707 }
3708 else {
3709 parseIfLoadingComplete();
3710 makeCallbackIfParsingComplete();
3711 }
3712 });
3713 }
3714 function loadStyleSheet(href) {
3715 var link = linkElement.cloneNode();
3716 link.href = href;
3717 if (firstScriptInHeadElement) {
3718 headElement.insertBefore(link, firstScriptInHeadElement);
3719 }
3720 else {
3721 headElement.appendChild(link);
3722 }
3723 }
3724 function loadJavaScriptSourceCode(src, onload) {
3725 webGet(src, function () {
3726 onload(this.responseText);
3727 });
3728 }
3729 function parseJavaScript(script, onComplete) {
3730 if (onComplete === void 0) { onComplete = $.noop; }
3731 if (!script) {
3732 onComplete();
3733 return;
3734 }
3735 var sourceCodeOrFileName = script.javascriptFile;
3736 var targetCallback = onComplete;
3737 if (script.onLoadCallback) {
3738 var promiseAsCallback = function () {
3739 script.onLoadCallback().then(onComplete);
3740 };
3741 targetCallback = promiseAsCallback;
3742 }
3743 isExternalUrl(sourceCodeOrFileName)
3744 ? loadExternalJavaScriptFile(sourceCodeOrFileName, targetCallback)
3745 : parseInternalJavaScriptCode(sourceCodeOrFileName, targetCallback);
3746 }
3747 function parseInternalJavaScriptCode(sourceCode, onComplete) {
3748 if (onComplete === void 0) { onComplete = $.noop; }
3749 var script;
3750 if (sourceCode) {
3751 script = scriptElement.cloneNode();
3752 script.setAttribute('type', 'text/javascript');
3753 script.innerHTML = sourceCode;
3754 headElement.appendChild(script);
3755 }
3756 setTimeout(onComplete, 0);
3757 }
3758 function loadExternalJavaScriptFile(src, onload) {
3759 var script;
3760 if (src) {
3761 script = scriptElement.cloneNode();
3762 script.setAttribute('src', src);
3763 script.setAttribute('charset', 'utf-8');
3764 script.onload = onload;
3765 headElement.appendChild(script);
3766 }
3767 }
3768 function parseJavaScriptSourceCodes(scripts, sourceCodeList) {
3769 asyncLoop(sourceCodeList, parseJavaScript, /*on all files parsed*/ function () {
3770 scripts.forEach(function (script) {
3771 var file = script.javascriptFile;
3772 var listeners = javaScriptFilesLoading[file];
3773 if (listeners) {
3774 listeners.forEach(function (listener) {
3775 listener();
3776 });
3777 }
3778 delete javaScriptFilesLoading[file];
3779 if (javaScriptFilesLoaded.indexOf(file) === -1) {
3780 javaScriptFilesLoaded.push(file);
3781 }
3782 });
3783 });
3784 }
3785 function webGet(src, onload, onerror) {
3786 var xhr = new XMLHttpRequest();
3787 try {
3788 xhr.open('GET', src, true);
3789 xhr.onload = onload;
3790 xhr.onerror = onerror;
3791 xhr.send(null);
3792 }
3793 catch (e) {
3794 }
3795 }
3796 function isExternalUrl(url) {
3797 var origin = location.protocol + '//' + location.host + '/';
3798 return /^http[s]?:\/\/.+/i.test(url) && url.indexOf(origin) !== 0;
3799 }
3800 function _() {
3801 var args = [];
3802 for (var _i = 0; _i < arguments.length; _i++) {
3803 args[_i - 0] = arguments[_i];
3804 }
3805 }
3806 function asyncSteps() {
3807 var args = [];
3808 for (var _i = 0; _i < arguments.length; _i++) {
3809 args[_i - 0] = arguments[_i];
3810 }
3811 if (args.length === 0) {
3812 return;
3813 }
3814 var steps = [], i = args.length;
3815 while (i--) {
3816 (function (j) {
3817 steps[j] = function () {
3818 args[j](steps[j + 1] || _);
3819 };
3820 })(i);
3821 }
3822 steps[0]();
3823 }
3824 function asyncLoop(enumerable, func, callback) {
3825 var steps = [], i = 0, len = enumerable.length;
3826 for (; i < len - 1; i++) {
3827 (function (i) {
3828 steps[i] = function (next) {
3829 func(enumerable[i], next);
3830 };
3831 }(i));
3832 }
3833 steps[len - 1] = function (next) {
3834 func(enumerable[len - 1], callback);
3835 };
3836 asyncSteps.apply(null, steps);
3837 }
3838})(jsCommon || (jsCommon = {}));
3839/*
3840 * Power BI Visualizations
3841 *
3842 * Copyright (c) Microsoft Corporation
3843 * All rights reserved.
3844 * MIT License
3845 *
3846 * Permission is hereby granted, free of charge, to any person obtaining a copy
3847 * of this software and associated documentation files (the ""Software""), to deal
3848 * in the Software without restriction, including without limitation the rights
3849 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3850 * copies of the Software, and to permit persons to whom the Software is
3851 * furnished to do so, subject to the following conditions:
3852 *
3853 * The above copyright notice and this permission notice shall be included in
3854 * all copies or substantial portions of the Software.
3855 *
3856 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3857 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3858 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3859 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3860 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3861 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3862 * THE SOFTWARE.
3863 */
3864var powerbi;
3865(function (powerbi) {
3866 function createJQueryPromiseFactory() {
3867 return new JQueryPromiseFactory();
3868 }
3869 powerbi.createJQueryPromiseFactory = createJQueryPromiseFactory;
3870 /**
3871 * jQuery-based implementation of IPromiseFactory.
3872 * This is useful for cases when Angular is not present, or when immediate promise resolving (not tied to Angular digest cycle) is desired.
3873 */
3874 var JQueryPromiseFactory = (function () {
3875 function JQueryPromiseFactory() {
3876 }
3877 JQueryPromiseFactory.prototype.defer = function () {
3878 return new JQueryDeferredWrapper($.Deferred());
3879 };
3880 JQueryPromiseFactory.prototype.reject = function (reason) {
3881 var deferred = this.defer();
3882 deferred.reject(reason);
3883 return deferred.promise;
3884 };
3885 JQueryPromiseFactory.prototype.resolve = function (value) {
3886 var deferred = this.defer();
3887 deferred.resolve(value);
3888 return deferred.promise;
3889 };
3890 JQueryPromiseFactory.prototype.all = function (promises) {
3891 var unwrappedPromises = jQuery.map(promises, function (value) {
3892 return value && value.promise ? value.promise : value;
3893 });
3894 return new JQueryPromiseWrapper($.when.apply($, unwrappedPromises));
3895 };
3896 JQueryPromiseFactory.prototype.when = function (value) {
3897 var unwrappedPromise = value && value.promise ? value.promise : value;
3898 return new JQueryPromiseWrapper($.when(unwrappedPromise));
3899 };
3900 return JQueryPromiseFactory;
3901 }());
3902 /**
3903 * Implements IDeferred via a wrapped a jQuery Deferred.
3904 */
3905 var JQueryDeferredWrapper = (function () {
3906 function JQueryDeferredWrapper(deferred) {
3907 debug.assertValue(deferred, 'deferred');
3908 this.deferred = deferred;
3909 this.promise = new JQueryPromiseWrapper(deferred.promise());
3910 }
3911 JQueryDeferredWrapper.prototype.resolve = function (value) {
3912 this.deferred.resolve(value);
3913 };
3914 JQueryDeferredWrapper.prototype.reject = function (reason) {
3915 this.deferred.reject(reason);
3916 };
3917 return JQueryDeferredWrapper;
3918 }());
3919 /**
3920 * Implements IDeferred via a wrapped a jQuery Promise.
3921 */
3922 var JQueryPromiseWrapper = (function () {
3923 function JQueryPromiseWrapper(promise) {
3924 debug.assertValue(promise, 'promise');
3925 this.promise = promise;
3926 }
3927 JQueryPromiseWrapper.prototype.then = function (a, b) {
3928 return new JQueryPromiseWrapper(this.promise.then(JQueryPromiseWrapper.wrapCallback(a), JQueryPromiseWrapper.wrapCallback(b)));
3929 };
3930 JQueryPromiseWrapper.prototype.catch = function (callback) {
3931 return this.then(null, callback);
3932 };
3933 JQueryPromiseWrapper.prototype.finally = function (callback) {
3934 this.promise.always(JQueryPromiseWrapper.wrapCallback(callback));
3935 return this;
3936 };
3937 /**
3938 * Wraps a callback, which may return a IPromise.
3939 */
3940 JQueryPromiseWrapper.wrapCallback = function (callback) {
3941 if (callback)
3942 return function (arg) {
3943 var value = callback(arg);
3944 // If the callback returns a Promise, unwrap that to allow jQuery to chain.
3945 if (value instanceof JQueryPromiseWrapper)
3946 return value.promise;
3947 return value;
3948 };
3949 return callback;
3950 };
3951 return JQueryPromiseWrapper;
3952 }());
3953})(powerbi || (powerbi = {}));
3954/*
3955 * Power BI Visualizations
3956 *
3957 * Copyright (c) Microsoft Corporation
3958 * All rights reserved.
3959 * MIT License
3960 *
3961 * Permission is hereby granted, free of charge, to any person obtaining a copy
3962 * of this software and associated documentation files (the ""Software""), to deal
3963 * in the Software without restriction, including without limitation the rights
3964 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3965 * copies of the Software, and to permit persons to whom the Software is
3966 * furnished to do so, subject to the following conditions:
3967 *
3968 * The above copyright notice and this permission notice shall be included in
3969 * all copies or substantial portions of the Software.
3970 *
3971 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3972 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3973 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3974 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3975 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3976 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3977 * THE SOFTWARE.
3978 */
3979var powerbi;
3980(function (powerbi) {
3981 var LocalStorageService = (function () {
3982 function LocalStorageService() {
3983 }
3984 LocalStorageService.prototype.getData = function (key) {
3985 try {
3986 if (localStorage) {
3987 var value = localStorage[key];
3988 if (value) {
3989 return JSON.parse(value);
3990 }
3991 }
3992 }
3993 catch (exception) { }
3994 return null;
3995 };
3996 LocalStorageService.prototype.setData = function (key, data) {
3997 try {
3998 if (localStorage) {
3999 localStorage[key] = JSON.stringify(data);
4000 }
4001 }
4002 catch (e) { }
4003 };
4004 return LocalStorageService;
4005 }());
4006 var EphemeralStorageService = (function () {
4007 function EphemeralStorageService(clearCacheInterval) {
4008 this.cache = {};
4009 this.clearCacheInterval = (clearCacheInterval != null)
4010 ? clearCacheInterval
4011 : EphemeralStorageService.defaultClearCacheInterval;
4012 this.clearCache();
4013 }
4014 EphemeralStorageService.prototype.getData = function (key) {
4015 return this.cache[key];
4016 };
4017 EphemeralStorageService.prototype.setData = function (key, data) {
4018 var _this = this;
4019 this.cache[key] = data;
4020 if (this.clearCacheTimerId == null) {
4021 this.clearCacheTimerId = setTimeout(function () { return _this.clearCache(); }, this.clearCacheInterval);
4022 }
4023 };
4024 EphemeralStorageService.prototype.clearCache = function () {
4025 this.cache = {};
4026 this.clearCacheTimerId = undefined;
4027 };
4028 EphemeralStorageService.defaultClearCacheInterval = (1000 * 60 * 60 * 24); // 1 day
4029 return EphemeralStorageService;
4030 }());
4031 powerbi.EphemeralStorageService = EphemeralStorageService;
4032 powerbi.localStorageService = new LocalStorageService();
4033 powerbi.ephemeralStorageService = new EphemeralStorageService();
4034})(powerbi || (powerbi = {}));
4035/*
4036 * Power BI Visualizations
4037 *
4038 * Copyright (c) Microsoft Corporation
4039 * All rights reserved.
4040 * MIT License
4041 *
4042 * Permission is hereby granted, free of charge, to any person obtaining a copy
4043 * of this software and associated documentation files (the ""Software""), to deal
4044 * in the Software without restriction, including without limitation the rights
4045 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4046 * copies of the Software, and to permit persons to whom the Software is
4047 * furnished to do so, subject to the following conditions:
4048 *
4049 * The above copyright notice and this permission notice shall be included in
4050 * all copies or substantial portions of the Software.
4051 *
4052 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4053 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4054 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4055 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4056 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4057 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4058 * THE SOFTWARE.
4059 */
4060var jsCommon;
4061(function (jsCommon) {
4062 var WordBreaker;
4063 (function (WordBreaker) {
4064 var SPACE = ' ';
4065 var BREAKERS_REGEX = /[\s\n]+/g;
4066 function search(index, content, backward) {
4067 if (backward) {
4068 for (var i = index - 1; i > -1; i--) {
4069 if (hasBreakers(content[i]))
4070 return i + 1;
4071 }
4072 }
4073 else {
4074 for (var i = index, ilen = content.length; i < ilen; i++) {
4075 if (hasBreakers(content[i]))
4076 return i;
4077 }
4078 }
4079 return backward ? 0 : content.length;
4080 }
4081 /**
4082 * Find the word nearest the cursor specified within content
4083 * @param index - point within content to search forward/backward from
4084 * @param content - string to search
4085 */
4086 function find(index, content) {
4087 debug.assert(index >= 0 && index <= content.length, 'index within content string bounds');
4088 var result = { start: 0, end: 0 };
4089 if (content.length === 0)
4090 return result;
4091 result.start = search(index, content, true);
4092 result.end = search(index, content, false);
4093 return result;
4094 }
4095 WordBreaker.find = find;
4096 /**
4097 * Test for presence of breakers within content
4098 * @param content - string to test
4099 */
4100 function hasBreakers(content) {
4101 BREAKERS_REGEX.lastIndex = 0;
4102 return BREAKERS_REGEX.test(content);
4103 }
4104 WordBreaker.hasBreakers = hasBreakers;
4105 /**
4106 * Count the number of pieces when broken by BREAKERS_REGEX
4107 * ~2.7x faster than WordBreaker.split(content).length
4108 * @param content - string to break and count
4109 */
4110 function wordCount(content) {
4111 var count = 1;
4112 BREAKERS_REGEX.lastIndex = 0;
4113 BREAKERS_REGEX.exec(content);
4114 while (BREAKERS_REGEX.lastIndex !== 0) {
4115 count++;
4116 BREAKERS_REGEX.exec(content);
4117 }
4118 return count;
4119 }
4120 WordBreaker.wordCount = wordCount;
4121 function getMaxWordWidth(content, textWidthMeasurer, properties) {
4122 var words = split(content);
4123 var maxWidth = 0;
4124 for (var _i = 0, words_1 = words; _i < words_1.length; _i++) {
4125 var w = words_1[_i];
4126 properties.text = w;
4127 maxWidth = Math.max(maxWidth, textWidthMeasurer(properties));
4128 }
4129 return maxWidth;
4130 }
4131 WordBreaker.getMaxWordWidth = getMaxWordWidth;
4132 function split(content) {
4133 return content.split(BREAKERS_REGEX);
4134 }
4135 function getWidth(content, properties, textWidthMeasurer) {
4136 properties.text = content;
4137 return textWidthMeasurer(properties);
4138 }
4139 function truncate(content, properties, truncator, maxWidth) {
4140 properties.text = content;
4141 return truncator(properties, maxWidth);
4142 }
4143 /**
4144 * Split content by breakers (words) and greedy fit as many words
4145 * into each index in the result based on max width and number of lines
4146 * e.g. Each index in result corresponds to a line of content
4147 * when used by AxisHelper.LabelLayoutStrategy.wordBreak
4148 * @param content - string to split
4149 * @param properties - text properties to be used by @param:textWidthMeasurer
4150 * @param textWidthMeasurer - function to calculate width of given text content
4151 * @param maxWidth - maximum allowed width of text content in each result
4152 * @param maxNumLines - maximum number of results we will allow, valid values must be greater than 0
4153 * @param truncator - (optional) if specified, used as a function to truncate content to a given width
4154 */
4155 function splitByWidth(content, properties, textWidthMeasurer, maxWidth, maxNumLines, truncator) {
4156 // Default truncator returns string as-is
4157 truncator = truncator ? truncator : function (properties, maxWidth) { return properties.text; };
4158 var result = [];
4159 var words = split(content);
4160 var usedWidth = 0;
4161 var wordsInLine = [];
4162 for (var _i = 0, words_2 = words; _i < words_2.length; _i++) {
4163 var word = words_2[_i];
4164 // Last line? Just add whatever is left
4165 if ((maxNumLines > 0) && (result.length >= maxNumLines - 1)) {
4166 wordsInLine.push(word);
4167 continue;
4168 }
4169 // Determine width if we add this word
4170 // Account for SPACE we will add when joining...
4171 var wordWidth = wordsInLine.length === 0
4172 ? getWidth(word, properties, textWidthMeasurer)
4173 : getWidth(SPACE + word, properties, textWidthMeasurer);
4174 // If width would exceed max width,
4175 // then push used words and start new split result
4176 if (usedWidth + wordWidth > maxWidth) {
4177 // Word alone exceeds max width, just add it.
4178 if (wordsInLine.length === 0) {
4179 result.push(truncate(word, properties, truncator, maxWidth));
4180 usedWidth = 0;
4181 wordsInLine = [];
4182 continue;
4183 }
4184 result.push(truncate(wordsInLine.join(SPACE), properties, truncator, maxWidth));
4185 usedWidth = 0;
4186 wordsInLine = [];
4187 }
4188 // ...otherwise, add word and continue
4189 wordsInLine.push(word);
4190 usedWidth += wordWidth;
4191 }
4192 // Push remaining words onto result
4193 result.push(truncate(wordsInLine.join(SPACE), properties, truncator, maxWidth));
4194 return result;
4195 }
4196 WordBreaker.splitByWidth = splitByWidth;
4197 })(WordBreaker = jsCommon.WordBreaker || (jsCommon.WordBreaker = {}));
4198})(jsCommon || (jsCommon = {}));
4199/*
4200 * Power BI Visualizations
4201 *
4202 * Copyright (c) Microsoft Corporation
4203 * All rights reserved.
4204 * MIT License
4205 *
4206 * Permission is hereby granted, free of charge, to any person obtaining a copy
4207 * of this software and associated documentation files (the ""Software""), to deal
4208 * in the Software without restriction, including without limitation the rights
4209 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4210 * copies of the Software, and to permit persons to whom the Software is
4211 * furnished to do so, subject to the following conditions:
4212 *
4213 * The above copyright notice and this permission notice shall be included in
4214 * all copies or substantial portions of the Software.
4215 *
4216 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4217 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4218 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4219 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4220 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4221 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4222 * THE SOFTWARE.
4223 */
4224var powerbi;
4225(function (powerbi) {
4226 var TextMeasurementService;
4227 (function (TextMeasurementService) {
4228 var ellipsis = '…';
4229 var OverflowingText = jsCommon.CssConstants.createClassAndSelector('overflowingText');
4230 var spanElement;
4231 var svgTextElement;
4232 var canvasCtx;
4233 var fallbackFontFamily;
4234 /**
4235 * Idempotent function for adding the elements to the DOM.
4236 */
4237 function ensureDOM() {
4238 if (spanElement)
4239 return;
4240 spanElement = $('<span/>');
4241 $('body').append(spanElement);
4242 //The style hides the svg element from the canvas, preventing canvas from scrolling down to show svg black square.
4243 svgTextElement = d3.select($('body').get(0))
4244 .append('svg')
4245 .style({
4246 'height': '0px',
4247 'width': '0px',
4248 'position': 'absolute'
4249 })
4250 .append('text');
4251 canvasCtx = $('<canvas/>').get(0).getContext("2d");
4252 fallbackFontFamily = window.getComputedStyle(svgTextElement.node()).fontFamily;
4253 }
4254 /**
4255 * Removes spanElement from DOM.
4256 */
4257 function removeSpanElement() {
4258 if (spanElement && spanElement.remove) {
4259 spanElement.remove();
4260 }
4261 spanElement = null;
4262 }
4263 TextMeasurementService.removeSpanElement = removeSpanElement;
4264 /**
4265 * This method measures the width of the text with the given SVG text properties.
4266 * @param textProperties The text properties to use for text measurement.
4267 */
4268 function measureSvgTextWidth(textProperties) {
4269 debug.assertValue(textProperties, 'textProperties');
4270 debug.assert(_.isEmpty(textProperties.fontSize) || textProperties.fontSize.indexOf("px") !== -1, "TextProperties' text size should be in px.");
4271 ensureDOM();
4272 canvasCtx.font =
4273 (textProperties.fontStyle || "") + " " +
4274 (textProperties.fontVariant || "") + " " +
4275 (textProperties.fontWeight || "") + " " +
4276 textProperties.fontSize + " " +
4277 (textProperties.fontFamily || fallbackFontFamily);
4278 return canvasCtx.measureText(textProperties.text).width;
4279 }
4280 TextMeasurementService.measureSvgTextWidth = measureSvgTextWidth;
4281 /**
4282 * This method return the rect with the given SVG text properties.
4283 * @param textProperties The text properties to use for text measurement.
4284 */
4285 function measureSvgTextRect(textProperties) {
4286 debug.assertValue(textProperties, 'textProperties');
4287 debug.assert(_.isEmpty(textProperties.fontSize) || textProperties.fontSize.indexOf("px") !== -1, "TextProperties' text size should be in px.");
4288 ensureDOM();
4289 svgTextElement.style(null);
4290 svgTextElement
4291 .text(textProperties.text)
4292 .attr({
4293 'visibility': 'hidden',
4294 'font-family': textProperties.fontFamily || fallbackFontFamily,
4295 'font-variant': textProperties.fontVariant,
4296 'font-size': textProperties.fontSize,
4297 'font-weight': textProperties.fontWeight,
4298 'font-style': textProperties.fontStyle,
4299 'white-space': textProperties.whiteSpace || 'nowrap'
4300 });
4301 // We're expecting the browser to give a synchronous measurement here
4302 // We're using SVGTextElement because it works across all browsers
4303 return svgTextElement.node().getBBox();
4304 }
4305 TextMeasurementService.measureSvgTextRect = measureSvgTextRect;
4306 /**
4307 * This method measures the height of the text with the given SVG text properties.
4308 * @param textProperties The text properties to use for text measurement.
4309 */
4310 function measureSvgTextHeight(textProperties) {
4311 return measureSvgTextRect(textProperties).height;
4312 }
4313 TextMeasurementService.measureSvgTextHeight = measureSvgTextHeight;
4314 /**
4315 * This method returns the text Rect with the given SVG text properties.
4316 * Does NOT return text width; obliterates text value
4317 * @param {TextProperties} textProperties - The text properties to use for text measurement
4318 */
4319 function estimateSvgTextRect(textProperties) {
4320 debug.assertValue(textProperties, 'textProperties');
4321 debug.assert(_.isEmpty(textProperties.fontSize) || textProperties.fontSize.indexOf("px") !== -1, "TextProperties' text size should be in px.");
4322 var propertiesKey = textProperties.fontFamily + textProperties.fontSize;
4323 var rect = powerbi.ephemeralStorageService.getData(propertiesKey);
4324 if (rect == null) {
4325 // To estimate we check the height of a particular character, once it is cached, subsequent
4326 // calls should always get the height from the cache (regardless of the text).
4327 var estimatedTextProperties = {
4328 fontFamily: textProperties.fontFamily,
4329 fontSize: textProperties.fontSize,
4330 text: "M",
4331 };
4332 rect = TextMeasurementService.measureSvgTextRect(estimatedTextProperties);
4333 // NOTE: In some cases (disconnected/hidden DOM) we may provide incorrect measurement results (zero sized bounding-box), so
4334 // we only store values in the cache if we are confident they are correct.
4335 if (rect.height > 0)
4336 powerbi.ephemeralStorageService.setData(propertiesKey, rect);
4337 }
4338 return rect;
4339 }
4340 /**
4341 * This method returns the text Rect with the given SVG text properties.
4342 * @param {TextProperties} textProperties - The text properties to use for text measurement
4343 */
4344 function estimateSvgTextBaselineDelta(textProperties) {
4345 var rect = estimateSvgTextRect(textProperties);
4346 return rect.y + rect.height;
4347 }
4348 TextMeasurementService.estimateSvgTextBaselineDelta = estimateSvgTextBaselineDelta;
4349 /**
4350 * This method estimates the height of the text with the given SVG text properties.
4351 * @param {TextProperties} textProperties - The text properties to use for text measurement
4352 */
4353 function estimateSvgTextHeight(textProperties, tightFightForNumeric) {
4354 if (tightFightForNumeric === void 0) { tightFightForNumeric = false; }
4355 var height = estimateSvgTextRect(textProperties).height;
4356 //TODO: replace it with new baseline calculation
4357 if (tightFightForNumeric)
4358 height *= 0.7;
4359 return height;
4360 }
4361 TextMeasurementService.estimateSvgTextHeight = estimateSvgTextHeight;
4362 /**
4363 * This method measures the width of the svgElement.
4364 * @param svgElement The SVGTextElement to be measured.
4365 */
4366 function measureSvgTextElementWidth(svgElement) {
4367 debug.assertValue(svgElement, 'svgElement');
4368 return measureSvgTextWidth(getSvgMeasurementProperties(svgElement));
4369 }
4370 TextMeasurementService.measureSvgTextElementWidth = measureSvgTextElementWidth;
4371 /**
4372 * This method fetches the text measurement properties of the given DOM element.
4373 * @param element The selector for the DOM Element.
4374 */
4375 function getMeasurementProperties(element) {
4376 debug.assertValue(element, 'element');
4377 return {
4378 text: element.val() || element.text(),
4379 fontFamily: element.css('font-family'),
4380 fontSize: element.css('font-size'),
4381 fontWeight: element.css('font-weight'),
4382 fontStyle: element.css('font-style'),
4383 fontVariant: element.css('font-variant'),
4384 whiteSpace: element.css('white-space')
4385 };
4386 }
4387 TextMeasurementService.getMeasurementProperties = getMeasurementProperties;
4388 /**
4389 * This method fetches the text measurement properties of the given SVG text element.
4390 * @param svgElement The SVGTextElement to be measured.
4391 */
4392 function getSvgMeasurementProperties(svgElement) {
4393 debug.assertValue(svgElement, 'svgElement');
4394 var style = window.getComputedStyle(svgElement, null);
4395 return {
4396 text: svgElement.textContent,
4397 fontFamily: style.fontFamily,
4398 fontSize: style.fontSize,
4399 fontWeight: style.fontWeight,
4400 fontStyle: style.fontStyle,
4401 fontVariant: style.fontVariant,
4402 whiteSpace: style.whiteSpace
4403 };
4404 }
4405 TextMeasurementService.getSvgMeasurementProperties = getSvgMeasurementProperties;
4406 /**
4407 * This method returns the width of a div element.
4408 * @param element The div element.
4409 */
4410 function getDivElementWidth(element) {
4411 debug.assert(element.is('div'), 'Given element is not a div type. Cannot get width');
4412 return getComputedStyle(element[0]).width;
4413 }
4414 TextMeasurementService.getDivElementWidth = getDivElementWidth;
4415 /**
4416 * Compares labels text size to the available size and renders ellipses when the available size is smaller.
4417 * @param textProperties The text properties (including text content) to use for text measurement.
4418 * @param maxWidth The maximum width available for rendering the text.
4419 */
4420 function getTailoredTextOrDefault(textProperties, maxWidth) {
4421 debug.assertValue(textProperties, 'properties');
4422 debug.assertValue(textProperties.text, 'properties.text');
4423 debug.assert(_.isEmpty(textProperties.fontSize) || textProperties.fontSize.indexOf("px") !== -1, "TextProperties' text size should be in px.");
4424 ensureDOM();
4425 var strLength = textProperties.text.length;
4426 if (strLength === 0)
4427 return textProperties.text;
4428 var width = measureSvgTextWidth(textProperties);
4429 if (width < maxWidth)
4430 return textProperties.text;
4431 // Create a copy of the textProperties so we don't modify the one that's passed in.
4432 var copiedTextProperties = powerbi.Prototype.inherit(textProperties);
4433 // Take the properties and apply them to svgTextElement
4434 // Then, do the binary search to figure out the substring we want
4435 // Set the substring on textElement argument
4436 var text = copiedTextProperties.text = ellipsis + copiedTextProperties.text;
4437 var min = 1;
4438 var max = text.length;
4439 var i = ellipsis.length;
4440 while (min <= max) {
4441 // num | 0 prefered to Math.floor(num) for performance benefits
4442 i = (min + max) / 2 | 0;
4443 copiedTextProperties.text = text.substr(0, i);
4444 width = measureSvgTextWidth(copiedTextProperties);
4445 if (maxWidth > width)
4446 min = i + 1;
4447 else if (maxWidth < width)
4448 max = i - 1;
4449 else
4450 break;
4451 }
4452 // Since the search algorithm almost never finds an exact match,
4453 // it will pick one of the closest two, which could result in a
4454 // value bigger with than 'maxWidth' thus we need to go back by
4455 // one to guarantee a smaller width than 'maxWidth'.
4456 copiedTextProperties.text = text.substr(0, i);
4457 width = measureSvgTextWidth(copiedTextProperties);
4458 if (width > maxWidth)
4459 i--;
4460 return text.substr(ellipsis.length, i - ellipsis.length) + ellipsis;
4461 }
4462 TextMeasurementService.getTailoredTextOrDefault = getTailoredTextOrDefault;
4463 /**
4464 * Compares labels text size to the available size and renders ellipses when the available size is smaller.
4465 * @param textElement The SVGTextElement containing the text to render.
4466 * @param maxWidth The maximum width available for rendering the text.
4467 */
4468 function svgEllipsis(textElement, maxWidth) {
4469 debug.assertValue(textElement, 'textElement');
4470 var properties = getSvgMeasurementProperties(textElement);
4471 var originalText = properties.text;
4472 var tailoredText = getTailoredTextOrDefault(properties, maxWidth);
4473 if (originalText !== tailoredText) {
4474 textElement.textContent = tailoredText;
4475 }
4476 }
4477 TextMeasurementService.svgEllipsis = svgEllipsis;
4478 /**
4479 * Word break textContent of <text> SVG element into <tspan>s
4480 * Each tspan will be the height of a single line of text
4481 * @param textElement - the SVGTextElement containing the text to wrap
4482 * @param maxWidth - the maximum width available
4483 * @param maxHeight - the maximum height available (defaults to single line)
4484 * @param linePadding - (optional) padding to add to line height
4485 */
4486 function wordBreak(textElement, maxWidth, maxHeight, linePadding) {
4487 if (linePadding === void 0) { linePadding = 0; }
4488 debug.assertValue(textElement, 'textElement');
4489 var properties = getSvgMeasurementProperties(textElement);
4490 var height = estimateSvgTextHeight(properties) + linePadding;
4491 var maxNumLines = Math.max(1, Math.floor(maxHeight / height));
4492 var node = d3.select(textElement);
4493 // Save y of parent textElement to apply as first tspan dy
4494 var firstDY = node.attr('y');
4495 // Store and clear text content
4496 var labelText = textElement.textContent;
4497 textElement.textContent = null;
4498 // Append a tspan for each word broken section
4499 var words = jsCommon.WordBreaker.splitByWidth(labelText, properties, measureSvgTextWidth, maxWidth, maxNumLines);
4500 for (var i = 0, ilen = words.length; i < ilen; i++) {
4501 properties.text = words[i];
4502 node
4503 .append('tspan')
4504 .attr({
4505 'x': 0,
4506 'dy': i === 0 ? firstDY : height,
4507 })
4508 .text(getTailoredTextOrDefault(properties, maxWidth));
4509 }
4510 }
4511 TextMeasurementService.wordBreak = wordBreak;
4512 /**
4513 * Word break textContent of span element into <span>s
4514 * Each span will be the height of a single line of text
4515 * @param textElement - the element containing the text to wrap
4516 * @param maxWidth - the maximum width available
4517 * @param maxHeight - the maximum height available (defaults to single line)
4518 * @param linePadding - (optional) padding to add to line height
4519 */
4520 function wordBreakOverflowingText(textElement, maxWidth, maxHeight, linePadding) {
4521 if (linePadding === void 0) { linePadding = 0; }
4522 debug.assertValue(textElement, 'textElement');
4523 var properties = getSvgMeasurementProperties(textElement);
4524 var height = estimateSvgTextHeight(properties) + linePadding;
4525 var maxNumLines = Math.max(1, Math.floor(maxHeight / height));
4526 // Store and clear text content
4527 var labelText = textElement.textContent;
4528 textElement.textContent = null;
4529 // Append a span for each word broken section
4530 var words = jsCommon.WordBreaker.splitByWidth(labelText, properties, measureSvgTextWidth, maxWidth, maxNumLines);
4531 // splitByWidth() occasionally returns unnecessary empty strings, so get rid of them.
4532 // TODO: Fix splitByWidth.
4533 words = _.compact(words);
4534 var spanItem = d3.select(textElement)
4535 .selectAll(OverflowingText.selector)
4536 .data(words, function (d) { return $.inArray(d, words); });
4537 spanItem
4538 .enter()
4539 .append("span")
4540 .classed(OverflowingText.class, true)
4541 .text(function (d) { return d; })
4542 .style("width", jsCommon.PixelConverter.toString(maxWidth));
4543 }
4544 TextMeasurementService.wordBreakOverflowingText = wordBreakOverflowingText;
4545 })(TextMeasurementService = powerbi.TextMeasurementService || (powerbi.TextMeasurementService = {}));
4546})(powerbi || (powerbi = {}));
4547/*
4548 * Power BI Visualizations
4549 *
4550 * Copyright (c) Microsoft Corporation
4551 * All rights reserved.
4552 * MIT License
4553 *
4554 * Permission is hereby granted, free of charge, to any person obtaining a copy
4555 * of this software and associated documentation files (the ""Software""), to deal
4556 * in the Software without restriction, including without limitation the rights
4557 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4558 * copies of the Software, and to permit persons to whom the Software is
4559 * furnished to do so, subject to the following conditions:
4560 *
4561 * The above copyright notice and this permission notice shall be included in
4562 * all copies or substantial portions of the Software.
4563 *
4564 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4565 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4566 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4567 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4568 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4569 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4570 * THE SOFTWARE.
4571 */
4572var jsCommon;
4573(function (jsCommon) {
4574 var DOMConstants = jsCommon.DOMConstants;
4575 var KeyUtils;
4576 (function (KeyUtils) {
4577 function isArrowKey(keyCode) {
4578 return keyCode === DOMConstants.downArrowKeyCode
4579 || keyCode === DOMConstants.upArrowKeyCode
4580 || keyCode === DOMConstants.leftArrowKeyCode
4581 || keyCode === DOMConstants.rightArrowKeyCode;
4582 }
4583 KeyUtils.isArrowKey = isArrowKey;
4584 })(KeyUtils = jsCommon.KeyUtils || (jsCommon.KeyUtils = {}));
4585})(jsCommon || (jsCommon = {}));
4586/*
4587 * Power BI Visualizations
4588 *
4589 * Copyright (c) Microsoft Corporation
4590 * All rights reserved.
4591 * MIT License
4592 *
4593 * Permission is hereby granted, free of charge, to any person obtaining a copy
4594 * of this software and associated documentation files (the ""Software""), to deal
4595 * in the Software without restriction, including without limitation the rights
4596 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4597 * copies of the Software, and to permit persons to whom the Software is
4598 * furnished to do so, subject to the following conditions:
4599 *
4600 * The above copyright notice and this permission notice shall be included in
4601 * all copies or substantial portions of the Software.
4602 *
4603 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4604 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4605 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4606 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4607 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4608 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4609 * THE SOFTWARE.
4610 */
4611var jsCommon;
4612(function (jsCommon) {
4613 /**
4614 * Responsible for throttling input function.
4615 */
4616 var ThrottleUtility = (function () {
4617 function ThrottleUtility(delay) {
4618 this.timerFactory = jsCommon.TimerPromiseFactory.instance;
4619 this.delay = 0;
4620 if (delay) {
4621 this.delay = delay;
4622 }
4623 }
4624 ThrottleUtility.prototype.run = function (fn) {
4625 var _this = this;
4626 if (!this.fn) {
4627 this.fn = fn;
4628 this.timerFactory.create(this.delay).done(function () { return _this.timerComplete(_this.fn); });
4629 }
4630 else {
4631 this.fn = fn;
4632 }
4633 };
4634 /**
4635 * Note: Public for testing purpose.
4636 */
4637 ThrottleUtility.prototype.timerComplete = function (fn) {
4638 // run fn
4639 fn();
4640 // clear fn
4641 this.fn = null;
4642 };
4643 return ThrottleUtility;
4644 }());
4645 jsCommon.ThrottleUtility = ThrottleUtility;
4646})(jsCommon || (jsCommon = {}));
4647/*
4648 * Power BI Visualizations
4649 *
4650 * Copyright (c) Microsoft Corporation
4651 * All rights reserved.
4652 * MIT License
4653 *
4654 * Permission is hereby granted, free of charge, to any person obtaining a copy
4655 * of this software and associated documentation files (the ""Software""), to deal
4656 * in the Software without restriction, including without limitation the rights
4657 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4658 * copies of the Software, and to permit persons to whom the Software is
4659 * furnished to do so, subject to the following conditions:
4660 *
4661 * The above copyright notice and this permission notice shall be included in
4662 * all copies or substantial portions of the Software.
4663 *
4664 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4665 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4666 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4667 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4668 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4669 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4670 * THE SOFTWARE.
4671 */
4672var jsCommon;
4673(function (jsCommon) {
4674 /**
4675 * Responsible for creating timer promises.
4676 */
4677 var TimerPromiseFactory = (function () {
4678 function TimerPromiseFactory() {
4679 }
4680 /**
4681 * {@inheritDoc}
4682 */
4683 TimerPromiseFactory.prototype.create = function (delayInMs) {
4684 debug.assertValue(delayInMs, 'delayInMs');
4685 debug.assert(delayInMs >= 0, 'delayInMs must be a positive value.');
4686 var deferred = $.Deferred();
4687 window.setTimeout(function () { return deferred.resolve(); }, delayInMs);
4688 return deferred;
4689 };
4690 TimerPromiseFactory.instance = new TimerPromiseFactory();
4691 return TimerPromiseFactory;
4692 }());
4693 jsCommon.TimerPromiseFactory = TimerPromiseFactory;
4694})(jsCommon || (jsCommon = {}));
4695/*
4696 * Power BI Visualizations
4697 *
4698 * Copyright (c) Microsoft Corporation
4699 * All rights reserved.
4700 * MIT License
4701 *
4702 * Permission is hereby granted, free of charge, to any person obtaining a copy
4703 * of this software and associated documentation files (the ""Software""), to deal
4704 * in the Software without restriction, including without limitation the rights
4705 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4706 * copies of the Software, and to permit persons to whom the Software is
4707 * furnished to do so, subject to the following conditions:
4708 *
4709 * The above copyright notice and this permission notice shall be included in
4710 * all copies or substantial portions of the Software.
4711 *
4712 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4713 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4714 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4715 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4716 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4717 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4718 * THE SOFTWARE.
4719 */
4720var jsCommon;
4721(function (jsCommon) {
4722 /**
4723 * Http Status code we are interested.
4724 */
4725 (function (HttpStatusCode) {
4726 HttpStatusCode[HttpStatusCode["OK"] = 200] = "OK";
4727 HttpStatusCode[HttpStatusCode["BadRequest"] = 400] = "BadRequest";
4728 HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
4729 HttpStatusCode[HttpStatusCode["Forbidden"] = 403] = "Forbidden";
4730 HttpStatusCode[HttpStatusCode["RequestEntityTooLarge"] = 413] = "RequestEntityTooLarge";
4731 })(jsCommon.HttpStatusCode || (jsCommon.HttpStatusCode = {}));
4732 var HttpStatusCode = jsCommon.HttpStatusCode;
4733 /**
4734 * Other HTTP Constants.
4735 */
4736 var HttpConstants;
4737 (function (HttpConstants) {
4738 HttpConstants.ApplicationOctetStream = 'application/octet-stream';
4739 HttpConstants.MultiPartFormData = 'multipart/form-data';
4740 })(HttpConstants = jsCommon.HttpConstants || (jsCommon.HttpConstants = {}));
4741 /**
4742 * Extensions to String class.
4743 */
4744 var StringExtensions;
4745 (function (StringExtensions) {
4746 var HtmlTagRegex = new RegExp('[<>]', 'g');
4747 function format() {
4748 var args = [];
4749 for (var _i = 0; _i < arguments.length; _i++) {
4750 args[_i - 0] = arguments[_i];
4751 }
4752 var s = args[0];
4753 if (isNullOrUndefinedOrWhiteSpaceString(s))
4754 return s;
4755 for (var i = 0; i < args.length - 1; i++) {
4756 var reg = new RegExp("\\{" + i + "\\}", "gm");
4757 s = s.replace(reg, args[i + 1]);
4758 }
4759 return s;
4760 }
4761 StringExtensions.format = format;
4762 /**
4763 * Compares two strings for equality, ignoring case.
4764 */
4765 function equalIgnoreCase(a, b) {
4766 return StringExtensions.normalizeCase(a) === StringExtensions.normalizeCase(b);
4767 }
4768 StringExtensions.equalIgnoreCase = equalIgnoreCase;
4769 function startsWithIgnoreCase(a, b) {
4770 var normalizedSearchString = StringExtensions.normalizeCase(b);
4771 return StringExtensions.normalizeCase(a).indexOf(normalizedSearchString) === 0;
4772 }
4773 StringExtensions.startsWithIgnoreCase = startsWithIgnoreCase;
4774 function startsWith(a, b) {
4775 return a.indexOf(b) === 0;
4776 }
4777 StringExtensions.startsWith = startsWith;
4778 /** Determines whether a string contains a specified substring (while ignoring case). */
4779 function containsIgnoreCase(source, substring) {
4780 if (source == null)
4781 return false;
4782 return source.toLowerCase().indexOf(substring.toLowerCase().toString()) !== -1;
4783 }
4784 StringExtensions.containsIgnoreCase = containsIgnoreCase;
4785 /**
4786 * Normalizes case for a string.
4787 * Used by equalIgnoreCase method.
4788 */
4789 function normalizeCase(value) {
4790 Utility.throwIfNullOrUndefined(value, StringExtensions, 'normalizeCase', 'value');
4791 return value.toUpperCase();
4792 }
4793 StringExtensions.normalizeCase = normalizeCase;
4794 /**
4795 * Is string null or empty or undefined?
4796 * @return True if the value is null or undefined or empty string,
4797 * otherwise false.
4798 */
4799 function isNullOrEmpty(value) {
4800 return (value == null) || (value.length === 0);
4801 }
4802 StringExtensions.isNullOrEmpty = isNullOrEmpty;
4803 /**
4804 * Returns true if the string is null, undefined, empty, or only includes white spaces.
4805 * @return True if the str is null, undefined, empty, or only includes white spaces,
4806 * otherwise false.
4807 */
4808 function isNullOrUndefinedOrWhiteSpaceString(str) {
4809 return StringExtensions.isNullOrEmpty(str) || StringExtensions.isNullOrEmpty(str.trim());
4810 }
4811 StringExtensions.isNullOrUndefinedOrWhiteSpaceString = isNullOrUndefinedOrWhiteSpaceString;
4812 /**
4813 * Returns a value indicating whether the str contains any whitespace.
4814 */
4815 function containsWhitespace(str) {
4816 Utility.throwIfNullOrUndefined(str, this, 'containsWhitespace', 'str');
4817 var expr = /\s/;
4818 return expr.test(str);
4819 }
4820 StringExtensions.containsWhitespace = containsWhitespace;
4821 /**
4822 * Returns a value indicating whether the str is a whitespace string.
4823 */
4824 function isWhitespace(str) {
4825 Utility.throwIfNullOrUndefined(str, this, 'isWhitespace', 'str');
4826 return str.trim() === '';
4827 }
4828 StringExtensions.isWhitespace = isWhitespace;
4829 /**
4830 * Returns the string with any trailing whitespace from str removed.
4831 */
4832 function trimTrailingWhitespace(str) {
4833 Utility.throwIfNullOrUndefined(str, this, 'trimTrailingWhitespace', 'str');
4834 return str.replace(/\s+$/, '');
4835 }
4836 StringExtensions.trimTrailingWhitespace = trimTrailingWhitespace;
4837 /**
4838 * Returns the string with any leading and trailing whitespace from str removed.
4839 */
4840 function trimWhitespace(str) {
4841 Utility.throwIfNullOrUndefined(str, this, 'trimWhitespace', 'str');
4842 return str.replace(/^\s+/, '').replace(/\s+$/, '');
4843 }
4844 StringExtensions.trimWhitespace = trimWhitespace;
4845 /**
4846 * Returns length difference between the two provided strings.
4847 */
4848 function getLengthDifference(left, right) {
4849 Utility.throwIfNullOrUndefined(left, this, 'getLengthDifference', 'left');
4850 Utility.throwIfNullOrUndefined(right, this, 'getLengthDifference', 'right');
4851 return Math.abs(left.length - right.length);
4852 }
4853 StringExtensions.getLengthDifference = getLengthDifference;
4854 /**
4855 * Repeat char or string several times.
4856 * @param char The string to repeat.
4857 * @param count How many times to repeat the string.
4858 */
4859 function repeat(char, count) {
4860 var result = "";
4861 for (var i = 0; i < count; i++) {
4862 result += char;
4863 }
4864 return result;
4865 }
4866 StringExtensions.repeat = repeat;
4867 /**
4868 * Replace all the occurrences of the textToFind in the text with the textToReplace.
4869 * @param text The original string.
4870 * @param textToFind Text to find in the original string.
4871 * @param textToReplace New text replacing the textToFind.
4872 */
4873 function replaceAll(text, textToFind, textToReplace) {
4874 if (!textToFind)
4875 return text;
4876 var pattern = escapeStringForRegex(textToFind);
4877 return text.replace(new RegExp(pattern, 'gi'), textToReplace);
4878 }
4879 StringExtensions.replaceAll = replaceAll;
4880 function ensureUniqueNames(names) {
4881 debug.assertValue(names, 'names');
4882 var usedNames = {};
4883 // Make sure we are giving fair chance for all columns to stay with their original name
4884 // First we fill the used names map to contain all the original unique names from the list.
4885 for (var _i = 0, names_1 = names; _i < names_1.length; _i++) {
4886 var name_1 = names_1[_i];
4887 usedNames[name_1] = false;
4888 }
4889 var uniqueNames = [];
4890 // Now we go over all names and find a unique name for each
4891 for (var _a = 0, names_2 = names; _a < names_2.length; _a++) {
4892 var name_2 = names_2[_a];
4893 var uniqueName = name_2;
4894 // If the (original) column name is already taken lets try to find another name
4895 if (usedNames[uniqueName]) {
4896 var counter = 0;
4897 // Find a name that is not already in the map
4898 while (usedNames[uniqueName] !== undefined) {
4899 uniqueName = name_2 + "." + (++counter);
4900 }
4901 }
4902 uniqueNames.push(uniqueName);
4903 usedNames[uniqueName] = true;
4904 }
4905 return uniqueNames;
4906 }
4907 StringExtensions.ensureUniqueNames = ensureUniqueNames;
4908 /**
4909 * Returns a name that is not specified in the values.
4910 */
4911 function findUniqueName(usedNames, baseName) {
4912 debug.assertValue(usedNames, 'usedNames');
4913 debug.assertValue(baseName, 'baseName');
4914 // Find a unique name
4915 var i = 0, uniqueName = baseName;
4916 while (usedNames[uniqueName]) {
4917 uniqueName = baseName + (++i);
4918 }
4919 return uniqueName;
4920 }
4921 StringExtensions.findUniqueName = findUniqueName;
4922 function constructCommaSeparatedList(list, resourceProvider, maxValue) {
4923 if (!list || list.length === 0)
4924 return '';
4925 if (maxValue === null || maxValue === undefined)
4926 maxValue = Number.MAX_VALUE;
4927 var length = Math.min(maxValue, list.length);
4928 var replacedList = [];
4929 // Only need to replace user entries of {0} and {1} since we build the list in pairs.
4930 for (var j = 0; j < 2; j++) {
4931 var targetValue = '{' + j + '}';
4932 var replaceValue = '_|_<' + j + '>_|_';
4933 for (var i = 0; i < length; i++) {
4934 if (list[i].indexOf(targetValue) > -1) {
4935 list[i] = list[i].replace(targetValue, replaceValue);
4936 replacedList.push({ targetValue: targetValue, replaceValue: replaceValue });
4937 }
4938 }
4939 }
4940 var commaSeparatedList = '';
4941 for (var i = 0; i < length; i++) {
4942 if (i === 0)
4943 commaSeparatedList = list[i];
4944 else
4945 commaSeparatedList = StringExtensions.format(resourceProvider.get('FilterRestatement_Comma'), commaSeparatedList, list[i]);
4946 }
4947 for (var i = 0; i < replacedList.length; i++) {
4948 commaSeparatedList = commaSeparatedList.replace(replacedList[i].replaceValue, replacedList[i].targetValue);
4949 }
4950 return commaSeparatedList;
4951 }
4952 StringExtensions.constructCommaSeparatedList = constructCommaSeparatedList;
4953 function escapeStringForRegex(s) {
4954 return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1');
4955 }
4956 StringExtensions.escapeStringForRegex = escapeStringForRegex;
4957 /**
4958 * Remove file name reserved characters <>:"/\|?* from input string.
4959 */
4960 function normalizeFileName(fileName) {
4961 debug.assertValue(fileName, 'fileName');
4962 return fileName.replace(/[\<\>\:"\/\\\|\?*]/g, '');
4963 }
4964 StringExtensions.normalizeFileName = normalizeFileName;
4965 /**
4966 * Similar to JSON.stringify, but strips away escape sequences so that the resulting
4967 * string is human-readable (and parsable by JSON formatting/validating tools).
4968 */
4969 function stringifyAsPrettyJSON(object) {
4970 //let specialCharacterRemover = (key: string, value: string) => value.replace(/[^\w\s]/gi, '');
4971 return JSON.stringify(object /*, specialCharacterRemover*/);
4972 }
4973 StringExtensions.stringifyAsPrettyJSON = stringifyAsPrettyJSON;
4974 /**
4975 * Derive a CLS-compliant name from a specified string. If no allowed characters are present, return a fallback string instead.
4976 * TODO (6708134): this should have a fully Unicode-aware implementation
4977 */
4978 function deriveClsCompliantName(input, fallback) {
4979 debug.assertValue(input, 'input');
4980 var result = input.replace(/^[^A-Za-z]*/g, '').replace(/[ :\.\/\\\-\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]/g, '_').replace(/[\W]/g, '');
4981 return result.length > 0 ? result : fallback;
4982 }
4983 StringExtensions.deriveClsCompliantName = deriveClsCompliantName;
4984 /** Performs cheap sanitization by stripping away HTML tag (<>) characters. */
4985 function stripTagDelimiters(s) {
4986 return s.replace(HtmlTagRegex, '');
4987 }
4988 StringExtensions.stripTagDelimiters = stripTagDelimiters;
4989 })(StringExtensions = jsCommon.StringExtensions || (jsCommon.StringExtensions = {}));
4990 /**
4991 * The general utility class.
4992 */
4993 var Utility = (function () {
4994 function Utility() {
4995 }
4996 /**
4997 * Ensures the specified value is not null or undefined. Throws a relevent exception if it is.
4998 * @param value The value to check.
4999 * @param context The context from which the check originated.
5000 * @param methodName The name of the method that initiated the check.
5001 * @param parameterName The parameter name of the value to check.
5002 */
5003 Utility.throwIfNullOrUndefined = function (value, context, methodName, parameterName) {
5004 if (value === null) {
5005 Utility.throwException(jsCommon.Errors.argumentNull(Utility.getComponentName(context) + methodName + '.' + parameterName));
5006 }
5007 else if (typeof (value) === Utility.Undefined) {
5008 Utility.throwException(jsCommon.Errors.argumentUndefined(Utility.getComponentName(context) + methodName + '.' + parameterName));
5009 }
5010 };
5011 /**
5012 * Ensures the specified value is not null, undefined or empty. Throws a relevent exception if it is.
5013 * @param value The value to check.
5014 * @param context The context from which the check originated.
5015 * @param methodName The name of the method that initiated the check.
5016 * @param parameterName The parameter name of the value to check.
5017 */
5018 Utility.throwIfNullOrEmpty = function (value, context, methodName, parameterName) {
5019 Utility.throwIfNullOrUndefined(value, context, methodName, parameterName);
5020 if (!value.length) {
5021 Utility.throwException(jsCommon.Errors.argumentOutOfRange(Utility.getComponentName(context) + methodName + '.' + parameterName));
5022 }
5023 };
5024 /**
5025 * Ensures the specified string is not null, undefined or empty. Throws a relevent exception if it is.
5026 * @param value The value to check.
5027 * @param context The context from which the check originated.
5028 * @param methodName The name of the method that initiated the check.
5029 * @param parameterName The parameter name of the value to check.
5030 */
5031 Utility.throwIfNullOrEmptyString = function (value, context, methodName, parameterName) {
5032 Utility.throwIfNullOrUndefined(value, context, methodName, parameterName);
5033 if (value.length < 1) {
5034 Utility.throwException(jsCommon.Errors.argumentOutOfRange(Utility.getComponentName(context) + methodName + '.' + parameterName));
5035 }
5036 };
5037 /**
5038 * Ensures the specified value is not null, undefined, whitespace or empty. Throws a relevent exception if it is.
5039 * @param value The value to check.
5040 * @param context The context from which the check originated.
5041 * @param methodName The name of the method that initiated the check.
5042 * @param parameterName The parameter name of the value to check.
5043 */
5044 Utility.throwIfNullEmptyOrWhitespaceString = function (value, context, methodName, parameterName) {
5045 Utility.throwIfNullOrUndefined(value, context, methodName, parameterName);
5046 if (StringExtensions.isNullOrUndefinedOrWhiteSpaceString(value)) {
5047 Utility.throwException(jsCommon.Errors.argumentOutOfRange(Utility.getComponentName(context) + methodName + '.' + parameterName));
5048 }
5049 };
5050 /**
5051 * Ensures the specified condition is true. Throws relevant exception if it isn't.
5052 * @param condition The condition to check.
5053 * @param context The context from which the check originated.
5054 * @param methodName The name of the method that initiated the check.
5055 * @param parameterName The parameter name against which the condition is checked.
5056 */
5057 Utility.throwIfNotTrue = function (condition, context, methodName, parameterName) {
5058 if (!condition) {
5059 Utility.throwException(jsCommon.Errors.argument(parameterName, Utility.getComponentName(context) + methodName + '.' + parameterName));
5060 }
5061 };
5062 /**
5063 * Checks whether the provided value is a 'string'.
5064 * @param value The value to test.
5065 */
5066 Utility.isString = function (value) {
5067 return ((typeof value) === 'string');
5068 };
5069 /**
5070 * Checks whether the provided value is a 'boolean'.
5071 * @param value The value to test.
5072 */
5073 Utility.isBoolean = function (value) {
5074 return ((typeof value) === 'boolean');
5075 };
5076 /**
5077 * Checks whether the provided value is a 'number'.
5078 * @param value The value to test.
5079 */
5080 Utility.isNumber = function (value) {
5081 return ((typeof value) === 'number');
5082 };
5083 /**
5084 * Checks whether the provided value is a Date instance.
5085 * @param value The value to test.
5086 */
5087 Utility.isDate = function (value) {
5088 return Utility.isObject(value) && (value instanceof Date);
5089 };
5090 /**
5091 * Checks whether the provided value is an 'object'.
5092 * @param value The value to test.
5093 */
5094 Utility.isObject = function (value) {
5095 return (value != null) && ((typeof value) === 'object');
5096 };
5097 /**
5098 * Checks whether the provided value is null or undefined.
5099 * @param value The value to test.
5100 */
5101 Utility.isNullOrUndefined = function (value) {
5102 return (value === null) || (typeof (value) === Utility.Undefined);
5103 };
5104 /**
5105 * Combine a base url and a path.
5106 * @param baseUrl The base url.
5107 * @param path The path to add on to the base url.
5108 * @returns The combined url.
5109 */
5110 Utility.urlCombine = function (baseUrl, path) {
5111 Utility.throwIfNullOrUndefined(baseUrl, null, "urlCombine", "baseUrl");
5112 Utility.throwIfNullOrUndefined(path, null, "urlCombine", "path");
5113 // should any of the components be empty, fail gracefuly - this is important when using the test page
5114 if (StringExtensions.isNullOrUndefinedOrWhiteSpaceString(path)) {
5115 return baseUrl;
5116 }
5117 if (StringExtensions.isNullOrUndefinedOrWhiteSpaceString(baseUrl)) {
5118 return path;
5119 }
5120 var finalUrl = baseUrl;
5121 if (finalUrl.charAt(finalUrl.length - 1) === '/') {
5122 if (path.charAt(0) === '/')
5123 path = path.slice(1);
5124 }
5125 else {
5126 if (path.charAt(0) !== '/')
5127 path = '/' + path;
5128 }
5129 return finalUrl + path;
5130 };
5131 Utility.getAbsoluteUri = function (path) {
5132 Utility.throwIfNullOrUndefined(path, null, "getAbsoluteUri", "path");
5133 var url = path;
5134 // Make absolute
5135 if (url && url.indexOf('http') === -1) {
5136 url = Utility.urlCombine(clusterUri, url);
5137 }
5138 return url;
5139 };
5140 Utility.getStaticResourceUri = function (path) {
5141 Utility.throwIfNullOrUndefined(path, null, "getStaticResourceUri", "path");
5142 var url = path;
5143 // Make absolute
5144 if (url && url.indexOf('http') === -1) {
5145 url = jsCommon.Utility.urlCombine(Utility.staticContentLocation, url);
5146 }
5147 return url;
5148 };
5149 Utility.getComponentName = function (context) {
5150 return !context ? '' : (typeof context).toString() + '.';
5151 };
5152 Utility.throwException = function (e) {
5153 jsCommon.Trace.error(StringExtensions.format("Throwing exception: {0}", JSON.stringify(e)),
5154 /*includeStackTrace*/ e.stack != null ? false : true);
5155 throw e;
5156 };
5157 Utility.createClassSelector = function (className) {
5158 Utility.throwIfNullOrEmptyString(className, null, 'CreateClassSelector', 'className');
5159 return '.' + className;
5160 };
5161 Utility.createIdSelector = function (id) {
5162 Utility.throwIfNullOrEmptyString(id, null, 'CreateIdSelector', 'id');
5163 return '#' + id;
5164 };
5165 /**
5166 * Creates a client-side Guid string.
5167 * @returns A string representation of a Guid.
5168 */
5169 Utility.generateGuid = function () {
5170 var guid = "", idx = 0;
5171 for (idx = 0; idx < 32; idx += 1) {
5172 var guidDigitsItem = Math.random() * 16 | 0;
5173 switch (idx) {
5174 case 8:
5175 case 12:
5176 case 16:
5177 case 20:
5178 guid += "-";
5179 break;
5180 }
5181 guid += guidDigitsItem.toString(16);
5182 }
5183 return guid;
5184 };
5185 /**
5186 * Try extract a cookie from {@link document.cookie} identified by key.
5187 */
5188 Utility.getCookieValue = function (key) {
5189 // the cookie is of the format <key1=value1>; <key2=value2>. Split by ';', then by '='
5190 // to search for the key
5191 var keyValuePairs = document.cookie.split(';');
5192 for (var i = 0; i < keyValuePairs.length; i++) {
5193 var keyValue = keyValuePairs[i];
5194 var split = keyValue.split('=');
5195 if (split.length > 0 && split[0].trim() === key) {
5196 return keyValue.substr(keyValue.indexOf('=') + 1);
5197 }
5198 }
5199 return null;
5200 };
5201 /**
5202 * Extracts the protocol://hostname section of a url.
5203 * @param url The URL from which to extract the section.
5204 * @returns The protocol://hostname portion of the given URL.
5205 */
5206 Utility.getDomainForUrl = function (url) {
5207 var hrefObject = Utility.getHrefObjectFromUrl(url);
5208 return hrefObject.prop('protocol') + '//' + hrefObject.prop('hostname');
5209 };
5210 /**
5211 * Extracts the hostname and absolute path sections of a url.
5212 * @param url The URL from which to extract the section.
5213 * @returns The hostname and absolute path portion of the given URL.
5214 */
5215 Utility.getHostNameForUrl = function (url) {
5216 var hrefObject = Utility.getHrefObjectFromUrl(url);
5217 return Utility.urlCombine(hrefObject.prop('hostname'), hrefObject.prop('pathname'));
5218 };
5219 /**
5220 * Return the original url with query string stripped.
5221 * @param url The URL from which to extract the section.
5222 * @returns the original url with query string stripped.
5223 */
5224 Utility.getUrlWithoutQueryString = function (url) {
5225 var hrefObject = Utility.getHrefObjectFromUrl(url);
5226 return hrefObject.prop('protocol') + '//' + Utility.urlCombine(hrefObject.prop('host'), hrefObject.prop('pathname'));
5227 };
5228 /**
5229 * Extracts the protocol section of a url.
5230 * @param url The URL from which to extract the section.
5231 * @returns The protocol for the current URL.
5232 */
5233 Utility.getProtocolFromUrl = function (url) {
5234 return Utility.getHrefObjectFromUrl(url).prop('protocol').replace(':', '');
5235 };
5236 /**
5237 * Returns a formatted href object from a URL.
5238 * @param url The URL used to generate the object.
5239 * @returns A jQuery object with the url.
5240 */
5241 Utility.getHrefObjectFromUrl = function (url) {
5242 var aObject = $('<a>');
5243 aObject = aObject.prop('href', url);
5244 return aObject;
5245 };
5246 /**
5247 * Converts a WCF representation of a dictionary to a JavaScript dictionary.
5248 * @param wcfDictionary The WCF dictionary to convert.
5249 * @returns The native JavaScript representation of this dictionary.
5250 */
5251 Utility.convertWcfToJsDictionary = function (wcfDictionary) {
5252 // convert the WCF JSON representation of a dictionary
5253 // to JS dictionary.
5254 // WCF representation: [{"Key": Key, "Value": Value}..]
5255 // JS representation: [Key: Value ..]
5256 var result = {};
5257 for (var i = 0; i < wcfDictionary.length; i++) {
5258 var keyValuePair = wcfDictionary[i];
5259 result[keyValuePair['Key']] = keyValuePair['Value'];
5260 }
5261 return result;
5262 };
5263 Utility.getDateFromWcfJsonString = function (jsonDate, fromUtcMilliseconds) {
5264 if (StringExtensions.isNullOrEmpty(jsonDate)) {
5265 return null;
5266 }
5267 var begIndex = jsonDate.indexOf('(');
5268 var endIndex = jsonDate.indexOf(')');
5269 if (begIndex !== -1 && endIndex !== -1) {
5270 var milliseconds = parseInt(jsonDate.substring(begIndex + 1, endIndex), 10);
5271 if (fromUtcMilliseconds) {
5272 return new Date(milliseconds);
5273 }
5274 else {
5275 var retValue = new Date(0);
5276 retValue.setUTCMilliseconds(milliseconds);
5277 return retValue;
5278 }
5279 }
5280 return null;
5281 };
5282 /**
5283 * Get the outer html of the given jquery object.
5284 * @param content The jquery object.
5285 * @returns The entire html representation of the object.
5286 */
5287 Utility.getOuterHtml = function (content) {
5288 return $('<div>').append(content).html();
5289 };
5290 /**
5291 * Comparison Method: Compares two integer numbers.
5292 * @param a An integer value.
5293 * @param b An integer value.
5294 * @returns The comparison result.
5295 */
5296 Utility.compareInt = function (a, b) {
5297 return a - b;
5298 };
5299 /**
5300 * Return the index of the smallest value in a numerical array.
5301 * @param a A numeric array.
5302 * @returns The index of the smallest value in the array.
5303 */
5304 Utility.getIndexOfMinValue = function (a) {
5305 var retValue = 0;
5306 var currentMinValue = a[0];
5307 for (var i = 0; i < a.length; i++) {
5308 if (a[i] < currentMinValue) {
5309 currentMinValue = a[i];
5310 retValue = i;
5311 }
5312 }
5313 return retValue;
5314 };
5315 /**
5316 * Extracts a url from a background image attribute in the format of: url('www.foobar.com/image.png').
5317 * @param input The value of the background-image attribute.
5318 * @returns The extracted url.
5319 */
5320 Utility.extractUrlFromCssBackgroundImage = function (input) {
5321 return input.replace(/"/g, "").replace(/url\(|\)$/ig, "");
5322 };
5323 /**
5324 * Verifies image data url of images.
5325 */
5326 Utility.isValidImageDataUrl = function (url) {
5327 var regex = new RegExp('data:(image\/(png|jpg|jpeg|gif|svg))');
5328 return regex.test(url);
5329 };
5330 Utility.isLocalUrl = function (url) {
5331 return _.startsWith(url, "data:") || _.startsWith(url, "blob:");
5332 };
5333 /**
5334 * Downloads a content string as a file.
5335 * @param content Content stream.
5336 * @param fileName File name to use.
5337 */
5338 Utility.saveAsFile = function (content, fileName) {
5339 var contentBlob = new Blob([content], { type: HttpConstants.ApplicationOctetStream });
5340 var url = window['webkitURL'] || URL;
5341 var urlLink = url.createObjectURL(contentBlob);
5342 var fileNameLink = fileName || urlLink;
5343 // IE support, use msSaveOrOpenBlob API
5344 if (window.navigator.msSaveOrOpenBlob) {
5345 window.navigator.msSaveOrOpenBlob(contentBlob, fileNameLink);
5346 return;
5347 }
5348 // WebKit-based browser support requires generating an anchor tag with
5349 // download attribute set to blob store and triggering a click event to invoke
5350 // a download to file action
5351 var hyperlink = document.createElement('a');
5352 hyperlink.href = urlLink;
5353 hyperlink.target = '_blank';
5354 hyperlink['download'] = fileNameLink;
5355 document.body.appendChild(hyperlink);
5356 hyperlink.click();
5357 document.body.removeChild(hyperlink);
5358 };
5359 /**
5360 * Helper method to get the simple type name from a typed object.
5361 * @param obj The typed object.
5362 * @returns The simple type name for the object.
5363 */
5364 Utility.getType = function (obj) {
5365 Utility.throwIfNullEmptyOrWhitespaceString(obj.__type, this, 'getType', 'obj');
5366 var parts = obj.__type.split(":");
5367 if (parts.length !== 2) {
5368 jsCommon.Errors.argument("obj.__type", "Type String not in expected format [Type]#[Namespace]: " + obj.__type);
5369 }
5370 if (parts[1] !== Utility.TypeNamespace) {
5371 jsCommon.Errors.argument("obj.__type", "Type Namespace not expected: " + parts[1]);
5372 }
5373 return parts[0];
5374 };
5375 /**
5376 * Check if an element supports a specific event type.
5377 * @param eventName The name of the event.
5378 * @param element The element to test for event support.
5379 * @returns Whether the even is supported on the provided element.
5380 */
5381 Utility.isEventSupported = function (eventName, element) {
5382 eventName = 'on' + eventName;
5383 var isSupported = (eventName in element);
5384 if (!isSupported) {
5385 // if we can't use setAttribute try a generic element
5386 if (!element.setAttribute) {
5387 element = document.createElement('div');
5388 }
5389 if (element.setAttribute && element.removeAttribute) {
5390 element.setAttribute(eventName, '');
5391 isSupported = typeof element[eventName] === 'function';
5392 // if the property was created - remove it
5393 if (typeof element[eventName] !== 'undefined') {
5394 element[eventName] = null;
5395 }
5396 element.removeAttribute(eventName);
5397 }
5398 }
5399 element = null;
5400 return isSupported;
5401 };
5402 Utility.toPixel = function (pixelAmount) {
5403 Utility.throwIfNullOrUndefined(pixelAmount, this, "toPixel", "pixelAmount");
5404 return pixelAmount.toString() + jsCommon.CssConstants.pixelUnits;
5405 };
5406 Utility.getPropertyCount = function (object) {
5407 Utility.throwIfNullOrUndefined(object, this, "getPropertyCount", "object");
5408 return Object.getOwnPropertyNames(object).length;
5409 };
5410 /**
5411 * Check if an element supports a specific event type.
5412 * @param filePath File path.
5413 * @returns File extension.
5414 */
5415 Utility.getFileExtension = function (filePath) {
5416 if (filePath) {
5417 var index = filePath.lastIndexOf('.');
5418 if (index >= 0)
5419 return filePath.substr(index + 1);
5420 }
5421 return '';
5422 };
5423 /**
5424 * Extract the filename out of a full path delimited by '\' or '/'.
5425 * @param filePath File path.
5426 * @returns filename File name.
5427 */
5428 Utility.extractFileNameFromPath = function (filePath) {
5429 return filePath.replace(/^.*[\\\/]/, '');
5430 };
5431 /**
5432 * This method indicates whether window.clipboardData is supported.
5433 * For example, clipboard support for Windows Store apps is currently disabled
5434 * since window.clipboardData is unsupported (it raises access denied error)
5435 * since clipboard in Windows Store is being
5436 * achieved through Windows.ApplicationModel.DataTransfer.Clipboard class.
5437 */
5438 Utility.canUseClipboard = function () {
5439 return (typeof MSApp === "undefined");
5440 };
5441 Utility.is64BitOperatingSystem = function () {
5442 return navigator.userAgent.indexOf("WOW64") !== -1 ||
5443 navigator.userAgent.indexOf("Win64") !== -1;
5444 };
5445 Utility.parseNumber = function (value, defaultValue) {
5446 if (value === null)
5447 return null;
5448 if (value === undefined)
5449 return defaultValue;
5450 var result = Number(value);
5451 if (isFinite(result))
5452 return result;
5453 if (isNaN(result) && !(typeof value === "number" || value === "NaN"))
5454 return defaultValue;
5455 return result;
5456 };
5457 Utility.getURLParamValue = function (name) {
5458 var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
5459 if (results == null) {
5460 return null;
5461 }
5462 else {
5463 return results[1] || 0;
5464 }
5465 };
5466 /**
5467 * Return local timezone.
5468 * This function uses summer and winter offset to determine local time zone.
5469 * The result localTimeZoneString must be a subset of the strings used by server,
5470 * as documented here: https://msdn.microsoft.com/en-us/library/gg154758.aspx (Dynamic Daylight Savings Time (Compact 2013)).
5471 * @return Local timezone string or UTC if timezone cannot be found.
5472 */
5473 Utility.getLocalTimeZoneString = function () {
5474 var timeSummer = new Date(Date.UTC(2005, 6, 30, 0, 0, 0, 0));
5475 var summerOffset = -1 * timeSummer.getTimezoneOffset();
5476 var timeWinter = new Date(Date.UTC(2005, 12, 30, 0, 0, 0, 0));
5477 var winterOffset = -1 * timeWinter.getTimezoneOffset();
5478 var localTimeZoneString;
5479 if (-720 === summerOffset && -720 === winterOffset) {
5480 localTimeZoneString = 'Dateline Standard Time';
5481 }
5482 else if (-660 === summerOffset && -660 === winterOffset) {
5483 localTimeZoneString = 'UTC-11';
5484 }
5485 else if (-660 === summerOffset && -660 === winterOffset) {
5486 localTimeZoneString = 'Samoa Standard Time';
5487 }
5488 else if (-600 === summerOffset && -600 === winterOffset) {
5489 localTimeZoneString = 'Hawaiian Standard Time';
5490 }
5491 else if (-480 === summerOffset && -540 === winterOffset) {
5492 localTimeZoneString = 'Alaskan Standard Time';
5493 }
5494 else if (-420 === summerOffset && -480 === winterOffset) {
5495 localTimeZoneString = 'Pacific Standard Time';
5496 }
5497 else if (-420 === summerOffset && -420 === winterOffset) {
5498 localTimeZoneString = 'US Mountain Standard Time';
5499 }
5500 else if (-360 === summerOffset && -420 === winterOffset) {
5501 localTimeZoneString = 'Mountain Standard Time';
5502 }
5503 else if (-360 === summerOffset && -360 === winterOffset) {
5504 localTimeZoneString = 'Central America Standard Time';
5505 }
5506 else if (-300 === summerOffset && -360 === winterOffset) {
5507 localTimeZoneString = 'Central Standard Time';
5508 }
5509 else if (-300 === summerOffset && -300 === winterOffset) {
5510 localTimeZoneString = 'SA Pacific Standard Time';
5511 }
5512 else if (-240 === summerOffset && -300 === winterOffset) {
5513 localTimeZoneString = 'Eastern Standard Time';
5514 }
5515 else if (-270 === summerOffset && -270 === winterOffset) {
5516 localTimeZoneString = 'Venezuela Standard Time';
5517 }
5518 else if (-240 === summerOffset && -240 === winterOffset) {
5519 localTimeZoneString = 'SA Western Standard Time';
5520 }
5521 else if (-240 === summerOffset && -180 === winterOffset) {
5522 localTimeZoneString = 'Central Brazilian Standard Time';
5523 }
5524 else if (-180 === summerOffset && -240 === winterOffset) {
5525 localTimeZoneString = 'Atlantic Standard Time';
5526 }
5527 else if (-180 === summerOffset && -180 === winterOffset) {
5528 localTimeZoneString = 'Montevideo Standard Time';
5529 }
5530 else if (-180 === summerOffset && -120 === winterOffset) {
5531 localTimeZoneString = 'E. South America Standard Time';
5532 }
5533 else if (-150 === summerOffset && -210 === winterOffset) {
5534 localTimeZoneString = 'Mid-Atlantic Standard Time';
5535 }
5536 else if (-120 === summerOffset && -120 === winterOffset) {
5537 localTimeZoneString = 'SA Eastern Standard Time';
5538 }
5539 else if (0 === summerOffset && 0 === winterOffset) {
5540 localTimeZoneString = 'UTC';
5541 }
5542 else if (60 === summerOffset && 0 === winterOffset) {
5543 localTimeZoneString = 'GMT Standard Time';
5544 }
5545 else if (60 === summerOffset && 120 === winterOffset) {
5546 localTimeZoneString = 'Namibia Standard Time';
5547 }
5548 else if (120 === summerOffset && 60 === winterOffset) {
5549 localTimeZoneString = 'Romance Standard Time';
5550 }
5551 else if (120 === summerOffset && 120 === winterOffset) {
5552 localTimeZoneString = 'South Africa Standard Time';
5553 }
5554 else if (180 === summerOffset && 120 === winterOffset) {
5555 localTimeZoneString = 'GTB Standard Time';
5556 }
5557 else if (180 === summerOffset && 180 === winterOffset) {
5558 localTimeZoneString = 'E. Africa Standard Time';
5559 }
5560 else if (240 === summerOffset && 180 === winterOffset) {
5561 localTimeZoneString = 'Russian Standard Time';
5562 }
5563 else if (240 === summerOffset && 240 === winterOffset) {
5564 localTimeZoneString = 'Arabian Standard Time';
5565 }
5566 else if (270 === summerOffset && 210 === winterOffset) {
5567 localTimeZoneString = 'Iran Standard Time';
5568 }
5569 else if (270 === summerOffset && 270 === winterOffset) {
5570 localTimeZoneString = 'Afghanistan Standard Time';
5571 }
5572 else if (300 === summerOffset && 240 === winterOffset) {
5573 localTimeZoneString = 'Pakistan Standard Time';
5574 }
5575 else if (300 === summerOffset && 300 === winterOffset) {
5576 localTimeZoneString = 'West Asia Standard Time';
5577 }
5578 else if (330 === summerOffset && 330 === winterOffset) {
5579 localTimeZoneString = 'India Standard Time';
5580 }
5581 else if (345 === summerOffset && 345 === winterOffset) {
5582 localTimeZoneString = 'Nepal Standard Time';
5583 }
5584 else if (360 === summerOffset && 300 === winterOffset) {
5585 localTimeZoneString = 'N. Central Asia Standard Time';
5586 }
5587 else if (360 === summerOffset && 360 === winterOffset) {
5588 localTimeZoneString = 'Central Asia Standard Time';
5589 }
5590 else if (390 === summerOffset && 390 === winterOffset) {
5591 localTimeZoneString = 'Myanmar Standard Time';
5592 }
5593 else if (420 === summerOffset && 360 === winterOffset) {
5594 localTimeZoneString = 'North Asia Standard Time';
5595 }
5596 else if (420 === summerOffset && 420 === winterOffset) {
5597 localTimeZoneString = 'SE Asia Standard Time';
5598 }
5599 else if (480 === summerOffset && 420 === winterOffset) {
5600 localTimeZoneString = 'North Asia East Standard Time';
5601 }
5602 else if (480 === summerOffset && 480 === winterOffset) {
5603 localTimeZoneString = 'China Standard Time';
5604 }
5605 else if (540 === summerOffset && 480 === winterOffset) {
5606 localTimeZoneString = 'Yakutsk Standard Time';
5607 }
5608 else if (540 === summerOffset && 540 === winterOffset) {
5609 localTimeZoneString = 'Tokyo Standard Time';
5610 }
5611 else if (570 === summerOffset && 570 === winterOffset) {
5612 localTimeZoneString = 'Cen. Australia Standard Time';
5613 }
5614 else if (600 === summerOffset && 600 === winterOffset) {
5615 localTimeZoneString = 'E. Australia Standard Time';
5616 }
5617 else if (600 === summerOffset && 660 === winterOffset) {
5618 localTimeZoneString = 'AUS Eastern Standard Time';
5619 }
5620 else if (660 === summerOffset && 600 === winterOffset) {
5621 localTimeZoneString = 'Tasmania Standard Time';
5622 }
5623 else if (660 === summerOffset && 660 === winterOffset) {
5624 localTimeZoneString = 'West Pacific Standard Time';
5625 }
5626 else if (690 === summerOffset && 690 === winterOffset) {
5627 localTimeZoneString = 'Central Pacific Standard Time';
5628 }
5629 else if (720 === summerOffset && 660 === winterOffset) {
5630 localTimeZoneString = 'Magadan Standard Time';
5631 }
5632 else if (720 === summerOffset && 720 === winterOffset) {
5633 localTimeZoneString = 'Fiji Standard Time';
5634 }
5635 else if (720 === summerOffset && 780 === winterOffset) {
5636 localTimeZoneString = 'New Zealand Standard Time';
5637 }
5638 else if (780 === summerOffset && 780 === winterOffset) {
5639 localTimeZoneString = 'Tonga Standard Time';
5640 }
5641 else {
5642 localTimeZoneString = 'UTC';
5643 }
5644 return localTimeZoneString;
5645 };
5646 Utility.TypeNamespace = 'http://schemas.microsoft.com/sqlbi/2013/01/NLRuntimeService';
5647 Utility.JsonContentType = 'application/json';
5648 Utility.JpegContentType = 'image/jpeg';
5649 Utility.XJavascriptContentType = 'application/x-javascript';
5650 Utility.JsonDataType = 'json';
5651 Utility.BlobDataType = 'blob';
5652 Utility.HttpGetMethod = 'GET';
5653 Utility.HttpPostMethod = 'POST';
5654 Utility.HttpPutMethod = 'PUT';
5655 Utility.HttpDeleteMethod = 'DELETE';
5656 Utility.HttpContentTypeHeader = 'Content-Type';
5657 Utility.HttpAcceptHeader = 'Accept';
5658 Utility.Undefined = 'undefined';
5659 Utility.staticContentLocation = window.location.protocol + '//' + window.location.host;
5660 return Utility;
5661 }());
5662 jsCommon.Utility = Utility;
5663 var VersionUtility = (function () {
5664 function VersionUtility() {
5665 }
5666 /**
5667 * Compares 2 version strings.
5668 * @param versionA The first version string.
5669 * @param versionB The second version string.
5670 * @returns A result for the comparison.
5671 */
5672 VersionUtility.compareVersions = function (versionA, versionB) {
5673 var a = versionA.split('.').map(parseFloat);
5674 var b = versionB.split('.').map(parseFloat);
5675 var versionParts = Math.max(a.length, b.length);
5676 for (var i = 0; i < versionParts; i++) {
5677 var partA = a[i] || 0;
5678 var partB = b[i] || 0;
5679 if (partA > partB)
5680 return 1;
5681 if (partA < partB)
5682 return -1;
5683 }
5684 return 0;
5685 };
5686 return VersionUtility;
5687 }());
5688 jsCommon.VersionUtility = VersionUtility;
5689 var PerformanceUtil;
5690 (function (PerformanceUtil) {
5691 var PerfMarker = (function () {
5692 function PerfMarker(name) {
5693 this._name = name;
5694 this._start = PerfMarker.begin(name);
5695 }
5696 PerfMarker.begin = function (name) {
5697 if (window.performance === undefined || performance.mark === undefined)
5698 return;
5699 if (console.time) {
5700 console.time(name);
5701 }
5702 name = 'Begin ' + name;
5703 performance.mark(name);
5704 return name;
5705 };
5706 PerfMarker.prototype.end = function () {
5707 if (window.performance === undefined || performance.mark === undefined || performance.measure === undefined)
5708 return;
5709 var name = this._name;
5710 var end = 'End ' + name;
5711 performance.mark(end);
5712 performance.measure(name, this._start, end);
5713 if (console.timeEnd) {
5714 console.timeEnd(name);
5715 }
5716 };
5717 return PerfMarker;
5718 }());
5719 PerformanceUtil.PerfMarker = PerfMarker;
5720 function create(name) {
5721 return new PerfMarker(name);
5722 }
5723 PerformanceUtil.create = create;
5724 })(PerformanceUtil = jsCommon.PerformanceUtil || (jsCommon.PerformanceUtil = {}));
5725 var DeferUtility;
5726 (function (DeferUtility) {
5727 /**
5728 * Wraps a callback and returns a new function.
5729 * The function can be called many times but the callback
5730 * will only be executed once on the next frame.
5731 * Use this to throttle big UI updates and access to DOM.
5732 */
5733 function deferUntilNextFrame(callback) {
5734 var isWaiting, args, context;
5735 if (!window.requestAnimationFrame) {
5736 window.requestAnimationFrame = function (func) { return setTimeout(func, 1000 / 50); };
5737 }
5738 return function () {
5739 if (!isWaiting) {
5740 isWaiting = true;
5741 args = arguments;
5742 context = this;
5743 window.requestAnimationFrame(function () {
5744 isWaiting = false;
5745 callback.apply(context, args);
5746 });
5747 }
5748 };
5749 }
5750 DeferUtility.deferUntilNextFrame = deferUntilNextFrame;
5751 })(DeferUtility = jsCommon.DeferUtility || (jsCommon.DeferUtility = {}));
5752})(jsCommon || (jsCommon = {}));
5753/*
5754 * Power BI Visualizations
5755 *
5756 * Copyright (c) Microsoft Corporation
5757 * All rights reserved.
5758 * MIT License
5759 *
5760 * Permission is hereby granted, free of charge, to any person obtaining a copy
5761 * of this software and associated documentation files (the ""Software""), to deal
5762 * in the Software without restriction, including without limitation the rights
5763 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5764 * copies of the Software, and to permit persons to whom the Software is
5765 * furnished to do so, subject to the following conditions:
5766 *
5767 * The above copyright notice and this permission notice shall be included in
5768 * all copies or substantial portions of the Software.
5769 *
5770 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5771 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5772 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5773 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5774 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5775 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5776 * THE SOFTWARE.
5777 */
5778var jsCommon;
5779(function (jsCommon) {
5780 var TraceItem = (function () {
5781 function TraceItem(text, type, sessionId, requestId) {
5782 this.text = text;
5783 this.type = type;
5784 this.sessionId = sessionId;
5785 this.requestId = requestId;
5786 this.timeStamp = new Date();
5787 }
5788 TraceItem.prototype.toString = function () {
5789 var resultString = '';
5790 resultString += (jsCommon.StringExtensions.format('{0} ({1}): {2}', TraceItem.traceTypeStrings[this.type], this.timeStamp.toUTCString(), this.text));
5791 if (this.requestId)
5792 resultString += ('\n(Request id: ' + this.requestId + ')');
5793 return resultString;
5794 };
5795 TraceItem.traceTypeStrings = [
5796 'INFORMATION',
5797 'VERBOSE',
5798 'WARNING',
5799 'ERROR',
5800 'EXPECTEDERROR',
5801 'UNEXPECTEDERROR',
5802 'FATAL',
5803 ];
5804 return TraceItem;
5805 }());
5806 jsCommon.TraceItem = TraceItem;
5807})(jsCommon || (jsCommon = {}));
5808/*
5809 * Power BI Visualizations
5810 *
5811 * Copyright (c) Microsoft Corporation
5812 * All rights reserved.
5813 * MIT License
5814 *
5815 * Permission is hereby granted, free of charge, to any person obtaining a copy
5816 * of this software and associated documentation files (the ""Software""), to deal
5817 * in the Software without restriction, including without limitation the rights
5818 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5819 * copies of the Software, and to permit persons to whom the Software is
5820 * furnished to do so, subject to the following conditions:
5821 *
5822 * The above copyright notice and this permission notice shall be included in
5823 * all copies or substantial portions of the Software.
5824 *
5825 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5826 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5827 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5828 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5829 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5830 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5831 * THE SOFTWARE.
5832 */
5833var jsCommon;
5834(function (jsCommon) {
5835 var UrlUtils;
5836 (function (UrlUtils) {
5837 var urlRegex = /http[s]?:\/\/(\S)+/gi;
5838 function isValidUrl(value) {
5839 if (jsCommon.StringExtensions.isNullOrEmpty(value))
5840 return false;
5841 var match = jsCommon.RegExpExtensions.run(urlRegex, value);
5842 if (!!match && match.index === 0)
5843 return true;
5844 return false;
5845 }
5846 UrlUtils.isValidUrl = isValidUrl;
5847 /* Tests whether a URL is valid.
5848 * @param url The url to be tested.
5849 * @returns Whether the provided url is valid.
5850 **/
5851 function isValidImageUrl(url) {
5852 // VSTS: 7252099 / 7112236
5853 // For now, passes for any valid Url
5854 return isValidUrl(url);
5855 }
5856 UrlUtils.isValidImageUrl = isValidImageUrl;
5857 function findAllValidUrls(text) {
5858 if (jsCommon.StringExtensions.isNullOrEmpty(text))
5859 return [];
5860 // Find all urls in the text.
5861 // TODO: This could potentially be expensive, maybe include a cap here for text with many urls?
5862 var urlRanges = [];
5863 var matches;
5864 var start = 0;
5865 while ((matches = jsCommon.RegExpExtensions.run(urlRegex, text, start)) !== null) {
5866 var url = matches[0];
5867 var end = matches.index + url.length;
5868 urlRanges.push({
5869 start: matches.index,
5870 end: end,
5871 text: url,
5872 });
5873 start = end;
5874 }
5875 return urlRanges;
5876 }
5877 UrlUtils.findAllValidUrls = findAllValidUrls;
5878 function getBase64ContentFromDataUri(uri) {
5879 if (uri.indexOf('data:') !== 0)
5880 throw new Error("Expected data uri");
5881 // Locate the base 64 content from the URL (e.g. "data:image/png;base64,xxxxx=")
5882 var base64Token = ";base64,";
5883 var indexBase64TokenStart = uri.indexOf(base64Token);
5884 if (indexBase64TokenStart < 0)
5885 throw new Error("Expected base 64 content in data url");
5886 var indexBase64Start = indexBase64TokenStart + base64Token.length;
5887 return uri.substr(indexBase64Start, uri.length - indexBase64Start);
5888 }
5889 UrlUtils.getBase64ContentFromDataUri = getBase64ContentFromDataUri;
5890 })(UrlUtils = jsCommon.UrlUtils || (jsCommon.UrlUtils = {}));
5891})(jsCommon || (jsCommon = {}));
5892/*
5893 * Power BI Visualizations
5894 *
5895 * Copyright (c) Microsoft Corporation
5896 * All rights reserved.
5897 * MIT License
5898 *
5899 * Permission is hereby granted, free of charge, to any person obtaining a copy
5900 * of this software and associated documentation files (the ""Software""), to deal
5901 * in the Software without restriction, including without limitation the rights
5902 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5903 * copies of the Software, and to permit persons to whom the Software is
5904 * furnished to do so, subject to the following conditions:
5905 *
5906 * The above copyright notice and this permission notice shall be included in
5907 * all copies or substantial portions of the Software.
5908 *
5909 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5910 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5911 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5912 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5913 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5914 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5915 * THE SOFTWARE.
5916 */
5917var jsCommon;
5918(function (jsCommon) {
5919 var BrowserUtils;
5920 (function (BrowserUtils) {
5921 function isChrome() {
5922 var vendorName = window.navigator.vendor || "";
5923 var userAgent = window.navigator.userAgent.toLowerCase();
5924 return vendorName.toLowerCase().indexOf('google') > -1 &&
5925 userAgent.indexOf('chrome') > -1 &&
5926 userAgent.indexOf('edge') === -1 &&
5927 userAgent.indexOf('opr') === -1;
5928 }
5929 BrowserUtils.isChrome = isChrome;
5930 function isInternetExplorerOrEdge() {
5931 var userAgent = window.navigator.userAgent.toLowerCase();
5932 return userAgent.indexOf('msie') > -1
5933 || userAgent.indexOf('trident') > -1
5934 || userAgent.indexOf('edge') > -1;
5935 }
5936 BrowserUtils.isInternetExplorerOrEdge = isInternetExplorerOrEdge;
5937 /**
5938 * Get the current version of IE
5939 * @returns The version of Internet Explorer or a 0 (indicating the use of another browser).
5940 */
5941 function getInternetExplorerVersion() {
5942 var retValue = 0;
5943 if (navigator.appName === 'Microsoft Internet Explorer' || window.navigator.userAgent.indexOf('MSIE') >= 0) {
5944 var re = new RegExp('MSIE ([0-9]{1,}[\\.0-9]{0,})');
5945 var result = re.exec(window.navigator.userAgent);
5946 if (result) {
5947 retValue = parseFloat(result[1]);
5948 }
5949 }
5950 return retValue;
5951 }
5952 BrowserUtils.getInternetExplorerVersion = getInternetExplorerVersion;
5953 })(BrowserUtils = jsCommon.BrowserUtils || (jsCommon.BrowserUtils = {}));
5954})(jsCommon || (jsCommon = {}));
5955/*
5956 * Power BI Visualizations
5957 *
5958 * Copyright (c) Microsoft Corporation
5959 * All rights reserved.
5960 * MIT License
5961 *
5962 * Permission is hereby granted, free of charge, to any person obtaining a copy
5963 * of this software and associated documentation files (the ""Software""), to deal
5964 * in the Software without restriction, including without limitation the rights
5965 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5966 * copies of the Software, and to permit persons to whom the Software is
5967 * furnished to do so, subject to the following conditions:
5968 *
5969 * The above copyright notice and this permission notice shall be included in
5970 * all copies or substantial portions of the Software.
5971 *
5972 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5973 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5974 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5975 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5976 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5977 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5978 * THE SOFTWARE.
5979 */
5980var jsCommon;
5981(function (jsCommon) {
5982 /**
5983 * Extensions for Enumerations.
5984 */
5985 var EnumExtensions;
5986 (function (EnumExtensions) {
5987 /**
5988 * Gets a value indicating whether the value has the bit flags set.
5989 */
5990 function hasFlag(value, flag) {
5991 debug.assert(!!flag, 'flag must be specified and nonzero.');
5992 return (value & flag) === flag;
5993 }
5994 EnumExtensions.hasFlag = hasFlag;
5995 /**
5996 * Sets a value of a flag without modifying any other flags.
5997 */
5998 function setFlag(value, flag) {
5999 debug.assert(!!flag, "flag must be specified and nonzero.");
6000 return value |= flag;
6001 }
6002 EnumExtensions.setFlag = setFlag;
6003 /**
6004 * Resets a value of a flag without modifying any other flags.
6005 */
6006 function resetFlag(value, flag) {
6007 debug.assert(!!flag, "flag must be specified and nonzero.");
6008 return value &= ~flag;
6009 }
6010 EnumExtensions.resetFlag = resetFlag;
6011 /**
6012 * According to the TypeScript Handbook, this is safe to do.
6013 */
6014 function toString(enumType, value) {
6015 return enumType[value];
6016 }
6017 EnumExtensions.toString = toString;
6018 })(EnumExtensions = jsCommon.EnumExtensions || (jsCommon.EnumExtensions = {}));
6019 /**
6020 * Extensions to String class.
6021 */
6022 var StringExtensions;
6023 (function (StringExtensions) {
6024 /**
6025 * Checks if a string ends with a sub-string.
6026 */
6027 function endsWith(str, suffix) {
6028 debug.assertValue(str, 'str');
6029 debug.assertValue(suffix, 'suffix');
6030 return str.indexOf(suffix, str.length - suffix.length) !== -1;
6031 }
6032 StringExtensions.endsWith = endsWith;
6033 })(StringExtensions = jsCommon.StringExtensions || (jsCommon.StringExtensions = {}));
6034 var LogicExtensions;
6035 (function (LogicExtensions) {
6036 function XOR(a, b) {
6037 return (a || b) && !(a && b);
6038 }
6039 LogicExtensions.XOR = XOR;
6040 })(LogicExtensions = jsCommon.LogicExtensions || (jsCommon.LogicExtensions = {}));
6041 var JsonComparer;
6042 (function (JsonComparer) {
6043 /**
6044 * Performs JSON-style comparison of two objects.
6045 */
6046 function equals(x, y) {
6047 if (x === y)
6048 return true;
6049 return JSON.stringify(x) === JSON.stringify(y);
6050 }
6051 JsonComparer.equals = equals;
6052 })(JsonComparer = jsCommon.JsonComparer || (jsCommon.JsonComparer = {}));
6053 /**
6054 * Values are in terms of 'pt'
6055 * Convert to pixels using PixelConverter.fromPoint
6056 */
6057 var TextSizeDefaults;
6058 (function (TextSizeDefaults) {
6059 /**
6060 * Stored in terms of 'pt'
6061 * Convert to pixels using PixelConverter.fromPoint
6062 */
6063 TextSizeDefaults.TextSizeMin = 8;
6064 /**
6065 * Stored in terms of 'pt'
6066 * Convert to pixels using PixelConverter.fromPoint
6067 */
6068 TextSizeDefaults.TextSizeMax = 40;
6069 var TextSizeRange = TextSizeDefaults.TextSizeMax - TextSizeDefaults.TextSizeMin;
6070 /**
6071 * Returns the percentage of this value relative to the TextSizeMax
6072 * @param textSize - should be given in terms of 'pt'
6073 */
6074 function getScale(textSize) {
6075 return (textSize - TextSizeDefaults.TextSizeMin) / TextSizeRange;
6076 }
6077 TextSizeDefaults.getScale = getScale;
6078 })(TextSizeDefaults = jsCommon.TextSizeDefaults || (jsCommon.TextSizeDefaults = {}));
6079 var PixelConverter;
6080 (function (PixelConverter) {
6081 var PxPtRatio = 4 / 3;
6082 var PixelString = 'px';
6083 /**
6084 * Appends 'px' to the end of number value for use as pixel string in styles
6085 */
6086 function toString(px) {
6087 return px + PixelString;
6088 }
6089 PixelConverter.toString = toString;
6090 /**
6091 * Converts point value (pt) to pixels
6092 * Returns a string for font-size property
6093 * e.g. fromPoint(8) => '24px'
6094 */
6095 function fromPoint(pt) {
6096 return toString(fromPointToPixel(pt));
6097 }
6098 PixelConverter.fromPoint = fromPoint;
6099 /**
6100 * Converts point value (pt) to pixels
6101 * Returns a number for font-size property
6102 * e.g. fromPoint(8) => 24px
6103 */
6104 function fromPointToPixel(pt) {
6105 return (PxPtRatio * pt);
6106 }
6107 PixelConverter.fromPointToPixel = fromPointToPixel;
6108 /**
6109 * Converts pixel value (px) to pt
6110 * e.g. toPoint(24) => 8
6111 */
6112 function toPoint(px) {
6113 return px / PxPtRatio;
6114 }
6115 PixelConverter.toPoint = toPoint;
6116 })(PixelConverter = jsCommon.PixelConverter || (jsCommon.PixelConverter = {}));
6117 var RegExpExtensions;
6118 (function (RegExpExtensions) {
6119 /**
6120 * Runs exec on regex starting from 0 index
6121 * This is the expected behavior but RegExp actually remember
6122 * the last index they stopped at (found match at) and will
6123 * return unexpected results when run in sequence.
6124 * @param regex - regular expression object
6125 * @param value - string to search wiht regex
6126 * @param start - index within value to start regex
6127 */
6128 function run(regex, value, start) {
6129 debug.assertValue(regex, 'regex');
6130 regex.lastIndex = start || 0;
6131 return regex.exec(value);
6132 }
6133 RegExpExtensions.run = run;
6134 })(RegExpExtensions = jsCommon.RegExpExtensions || (jsCommon.RegExpExtensions = {}));
6135})(jsCommon || (jsCommon = {}));
6136/*
6137 * Power BI Visualizations
6138 *
6139 * Copyright (c) Microsoft Corporation
6140 * All rights reserved.
6141 * MIT License
6142 *
6143 * Permission is hereby granted, free of charge, to any person obtaining a copy
6144 * of this software and associated documentation files (the ""Software""), to deal
6145 * in the Software without restriction, including without limitation the rights
6146 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6147 * copies of the Software, and to permit persons to whom the Software is
6148 * furnished to do so, subject to the following conditions:
6149 *
6150 * The above copyright notice and this permission notice shall be included in
6151 * all copies or substantial portions of the Software.
6152 *
6153 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6154 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6155 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6156 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6157 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6158 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6159 * THE SOFTWARE.
6160 */
6161var powerbi;
6162(function (powerbi) {
6163 var visuals;
6164 (function (visuals) {
6165 var utility;
6166 (function (utility) {
6167 var StyleUtils;
6168 (function (StyleUtils) {
6169 function getRotateAngleFromElement(element) {
6170 var rawElemStyle = element.get(0).style;
6171 var transformString = rawElemStyle.transform || rawElemStyle.webkitTransform;
6172 if (transformString) {
6173 var transform = transformString.match(/rotate\((-?\d+(?:\.\d*)?)deg\)/);
6174 if (transform) {
6175 return parseFloat(transform[1]);
6176 }
6177 }
6178 return 0;
6179 }
6180 StyleUtils.getRotateAngleFromElement = getRotateAngleFromElement;
6181 function getTranslateTransformFromElement(element) {
6182 var rawElemStyle = element.get(0).style;
6183 // IE will recognize "webkitTransform" as "WebkitTransform" and set that as style property.
6184 // This means transform property is not read.
6185 // We put the "transform" before the "webkitTransform" to counteract the weirdness of IE.
6186 var transformString = rawElemStyle.transform || rawElemStyle.webkitTransform;
6187 var retValue = { x: 0, y: 0 };
6188 if (transformString && transformString.length > 0) {
6189 var transform = transformString.match(/translate\((-?\d+(?:\.\d*)?)px, (-?\d+(?:\.\d*)?)px\)/);
6190 if (transform) {
6191 retValue.x = parseFloat(transform[1]);
6192 retValue.y = parseFloat(transform[2]);
6193 }
6194 }
6195 return retValue;
6196 }
6197 StyleUtils.getTranslateTransformFromElement = getTranslateTransformFromElement;
6198 function getPadding(element) {
6199 if (!element)
6200 return;
6201 return {
6202 left: parseFloat(element.css('padding-left')) || 0,
6203 right: parseFloat(element.css('padding-right')) || 0,
6204 top: parseFloat(element.css('padding-top')) || 0,
6205 bottom: parseFloat(element.css('padding-bottom')) || 0,
6206 };
6207 }
6208 StyleUtils.getPadding = getPadding;
6209 })(StyleUtils = utility.StyleUtils || (utility.StyleUtils = {}));
6210 })(utility = visuals.utility || (visuals.utility = {}));
6211 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
6212})(powerbi || (powerbi = {}));
6213/*
6214 * Power BI Visualizations
6215 *
6216 * Copyright (c) Microsoft Corporation
6217 * All rights reserved.
6218 * MIT License
6219 *
6220 * Permission is hereby granted, free of charge, to any person obtaining a copy
6221 * of this software and associated documentation files (the ""Software""), to deal
6222 * in the Software without restriction, including without limitation the rights
6223 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6224 * copies of the Software, and to permit persons to whom the Software is
6225 * furnished to do so, subject to the following conditions:
6226 *
6227 * The above copyright notice and this permission notice shall be included in
6228 * all copies or substantial portions of the Software.
6229 *
6230 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6231 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6232 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6233 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6234 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6235 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6236 * THE SOFTWARE.
6237 */
6238var jsCommon;
6239(function (jsCommon) {
6240 var ConsoleTracer = (function () {
6241 function ConsoleTracer() {
6242 }
6243 ConsoleTracer.prototype.logTrace = function (trace) {
6244 if (DEBUG) {
6245 switch (trace.type) {
6246 case jsCommon.TraceType.Information:
6247 console.info(trace.toString());
6248 break;
6249 case jsCommon.TraceType.UnexpectedError:
6250 case jsCommon.TraceType.Error:
6251 case jsCommon.TraceType.Fatal:
6252 console.error(trace.toString());
6253 break;
6254 case jsCommon.TraceType.ExpectedError:
6255 case jsCommon.TraceType.Warning:
6256 console.warn(trace.toString());
6257 break;
6258 case jsCommon.TraceType.Verbose:
6259 console.log(trace.toString());
6260 break;
6261 default:
6262 console.log(trace.toString());
6263 break;
6264 }
6265 }
6266 };
6267 return ConsoleTracer;
6268 }());
6269 jsCommon.ConsoleTracer = ConsoleTracer;
6270 var Trace;
6271 (function (Trace) {
6272 var traceMaxCount = 1000;
6273 var traces = new Array(traceMaxCount);
6274 var lastTraceIndex = -1;
6275 var defaultListener = new ConsoleTracer();
6276 var listeners = new Array(defaultListener);
6277 /**
6278 * Trace a warning. Please ensure that no PII is being logged.
6279 */
6280 function warning(text, requestId) {
6281 debug.assertValue(text, 'text');
6282 logTraceInternal(new jsCommon.TraceItem(text, jsCommon.TraceType.Warning, requestId));
6283 }
6284 Trace.warning = warning;
6285 /**
6286 * Trace an error. Please ensure that no PII is being logged.
6287 */
6288 function error(text, includeStackTrace, requestId) {
6289 debug.assertValue(text, 'text');
6290 if (includeStackTrace)
6291 text = jsCommon.StringExtensions.format("{0}.\nStack:\n{1}", text, jsCommon.getStackTrace());
6292 logTraceInternal(new jsCommon.TraceItem(text, jsCommon.TraceType.Error, requestId));
6293 }
6294 Trace.error = error;
6295 /**
6296 * Trace an information. Please ensure that no PII is being logged.
6297 */
6298 function verbose(text, requestId) {
6299 debug.assertValue(text, 'text');
6300 logTraceInternal(new jsCommon.TraceItem(text, jsCommon.TraceType.Verbose, requestId));
6301 }
6302 Trace.verbose = verbose;
6303 function addListener(listener) {
6304 debug.assertValue(listener, 'listener');
6305 listeners.push(listener);
6306 }
6307 Trace.addListener = addListener;
6308 function removeListener(listener) {
6309 debug.assertValue(listener, 'listener');
6310 var index = listeners.indexOf(listener);
6311 if (index >= 0)
6312 listeners.splice(index, 1);
6313 }
6314 Trace.removeListener = removeListener;
6315 function resetListeners() {
6316 listeners = new Array(defaultListener);
6317 }
6318 Trace.resetListeners = resetListeners;
6319 function reset() {
6320 lastTraceIndex = -1;
6321 }
6322 Trace.reset = reset;
6323 function getTraces() {
6324 if (lastTraceIndex < 0)
6325 return;
6326 var result = new Array(lastTraceIndex + 1);
6327 for (var i = 0; i <= lastTraceIndex; i++)
6328 result[i] = traces[i];
6329 return result;
6330 }
6331 Trace.getTraces = getTraces;
6332 /**
6333 * Note: Used for unit-test only.
6334 */
6335 function disableDefaultListener() {
6336 removeListener(defaultListener);
6337 }
6338 Trace.disableDefaultListener = disableDefaultListener;
6339 function enableDefaultListener() {
6340 addListener(defaultListener);
6341 }
6342 Trace.enableDefaultListener = enableDefaultListener;
6343 function logTraceInternal(trace) {
6344 if ((lastTraceIndex + 1) >= traceMaxCount)
6345 reset();
6346 traces[++lastTraceIndex] = trace;
6347 for (var i = 0, len = listeners.length; i < len; i++)
6348 listeners[i].logTrace(trace);
6349 }
6350 })(Trace = jsCommon.Trace || (jsCommon.Trace = {}));
6351})(jsCommon || (jsCommon = {}));
6352/*
6353 * Power BI Visualizations
6354 *
6355 * Copyright (c) Microsoft Corporation
6356 * All rights reserved.
6357 * MIT License
6358 *
6359 * Permission is hereby granted, free of charge, to any person obtaining a copy
6360 * of this software and associated documentation files (the ""Software""), to deal
6361 * in the Software without restriction, including without limitation the rights
6362 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6363 * copies of the Software, and to permit persons to whom the Software is
6364 * furnished to do so, subject to the following conditions:
6365 *
6366 * The above copyright notice and this permission notice shall be included in
6367 * all copies or substantial portions of the Software.
6368 *
6369 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6370 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6371 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6372 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6373 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6374 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6375 * THE SOFTWARE.
6376 */
6377var jsCommon;
6378(function (jsCommon) {
6379 /**
6380 * The types of possible traces within the system, this aligns to the traces available in Cloud Platform.
6381 */
6382 (function (TraceType) {
6383 TraceType[TraceType["Information"] = 0] = "Information";
6384 TraceType[TraceType["Verbose"] = 1] = "Verbose";
6385 TraceType[TraceType["Warning"] = 2] = "Warning";
6386 TraceType[TraceType["Error"] = 3] = "Error";
6387 TraceType[TraceType["ExpectedError"] = 4] = "ExpectedError";
6388 TraceType[TraceType["UnexpectedError"] = 5] = "UnexpectedError";
6389 TraceType[TraceType["Fatal"] = 6] = "Fatal";
6390 })(jsCommon.TraceType || (jsCommon.TraceType = {}));
6391 var TraceType = jsCommon.TraceType;
6392})(jsCommon || (jsCommon = {}));
6393/*
6394 * Power BI Visualizations
6395 *
6396 * Copyright (c) Microsoft Corporation
6397 * All rights reserved.
6398 * MIT License
6399 *
6400 * Permission is hereby granted, free of charge, to any person obtaining a copy
6401 * of this software and associated documentation files (the ""Software""), to deal
6402 * in the Software without restriction, including without limitation the rights
6403 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6404 * copies of the Software, and to permit persons to whom the Software is
6405 * furnished to do so, subject to the following conditions:
6406 *
6407 * The above copyright notice and this permission notice shall be included in
6408 * all copies or substantial portions of the Software.
6409 *
6410 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6411 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6412 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6413 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6414 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6415 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6416 * THE SOFTWARE.
6417 */
6418var jsCommon;
6419(function (jsCommon) {
6420 /**
6421 * JavaScript files.
6422 */
6423 var MSMapcontrol = 'https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&s=1&onscriptload=globalMapControlLoaded';
6424 /**
6425 * Map loading logic.
6426 */
6427 var MSMapcontrolLoaded = false;
6428 var WaitForMSMapLoad = null;
6429 var PowerViewPackage = {
6430 javaScriptFiles: [
6431 powerbi.build + '/externals/pv/webclient.js'
6432 ],
6433 cssFiles: [
6434 powerbi.build + '/externals/pv/Styles/_all.css'
6435 ],
6436 javaScriptFilesWithCallback: [
6437 { javascriptFile: MSMapcontrol, onLoadCallback: waitForMapControlLoaded }
6438 ]
6439 };
6440 function ensurePowerView(action) {
6441 if (action === void 0) { action = _.noop; }
6442 jsCommon.requires(PowerViewPackage, action);
6443 }
6444 jsCommon.ensurePowerView = ensurePowerView;
6445 var MapPackage = {
6446 javaScriptFilesWithCallback: [
6447 { javascriptFile: MSMapcontrol, onLoadCallback: waitForMapControlLoaded }
6448 ]
6449 };
6450 function ensureMap(locale, action) {
6451 var mapPackageWithLocale = powerbi.Prototype.inherit(MapPackage);
6452 if (!_.isEmpty(locale)) {
6453 mapPackageWithLocale.javaScriptFilesWithCallback[0].javascriptFile = MSMapcontrol.concat('&mkt=' + locale);
6454 }
6455 jsCommon.requires(mapPackageWithLocale, action);
6456 }
6457 jsCommon.ensureMap = ensureMap;
6458 function mapControlLoaded() {
6459 MSMapcontrolLoaded = true;
6460 if (WaitForMSMapLoad) {
6461 WaitForMSMapLoad.resolve();
6462 WaitForMSMapLoad = undefined;
6463 }
6464 }
6465 jsCommon.mapControlLoaded = mapControlLoaded;
6466 function waitForMapControlLoaded() {
6467 var task;
6468 if (!MSMapcontrolLoaded) {
6469 task = WaitForMSMapLoad = $.Deferred();
6470 }
6471 else {
6472 task = $.Deferred();
6473 task.resolve();
6474 }
6475 return task.promise();
6476 }
6477 jsCommon.waitForMapControlLoaded = waitForMapControlLoaded;
6478})(jsCommon || (jsCommon = {}));
6479/* tslint:disable:no-unused-variable */
6480var globalMapControlLoaded = function () {
6481 // Map requires a function in the global namespace to callback once loaded
6482 jsCommon.mapControlLoaded();
6483};
6484/* tslint:enable:no-unused-variable */
6485/*
6486 * Power BI Visualizations
6487 *
6488 * Copyright (c) Microsoft Corporation
6489 * All rights reserved.
6490 * MIT License
6491 *
6492 * Permission is hereby granted, free of charge, to any person obtaining a copy
6493 * of this software and associated documentation files (the ""Software""), to deal
6494 * in the Software without restriction, including without limitation the rights
6495 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6496 * copies of the Software, and to permit persons to whom the Software is
6497 * furnished to do so, subject to the following conditions:
6498 *
6499 * The above copyright notice and this permission notice shall be included in
6500 * all copies or substantial portions of the Software.
6501 *
6502 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6503 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6504 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6505 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6506 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6507 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6508 * THE SOFTWARE.
6509 */
6510var InJs;
6511(function (InJs) {
6512 /**
6513 * The types of possible traces within the system, this aligns to the traces available in Cloud Platform.
6514 */
6515 (function (TraceType) {
6516 TraceType[TraceType["information"] = 0] = "information";
6517 TraceType[TraceType["verbose"] = 1] = "verbose";
6518 TraceType[TraceType["warning"] = 2] = "warning";
6519 TraceType[TraceType["error"] = 3] = "error";
6520 TraceType[TraceType["expectedError"] = 4] = "expectedError";
6521 TraceType[TraceType["unexpectedError"] = 5] = "unexpectedError";
6522 TraceType[TraceType["fatal"] = 6] = "fatal";
6523 })(InJs.TraceType || (InJs.TraceType = {}));
6524 var TraceType = InJs.TraceType;
6525})(InJs || (InJs = {}));
6526
6527
6528;var __extends = (this && this.__extends) || function (d, b) {
6529 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
6530 function __() { this.constructor = d; }
6531 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
6532};
6533/*
6534 * Power BI Visualizations
6535 *
6536 * Copyright (c) Microsoft Corporation
6537 * All rights reserved.
6538 * MIT License
6539 *
6540 * Permission is hereby granted, free of charge, to any person obtaining a copy
6541 * of this software and associated documentation files (the ""Software""), to deal
6542 * in the Software without restriction, including without limitation the rights
6543 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6544 * copies of the Software, and to permit persons to whom the Software is
6545 * furnished to do so, subject to the following conditions:
6546 *
6547 * The above copyright notice and this permission notice shall be included in
6548 * all copies or substantial portions of the Software.
6549 *
6550 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6551 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6552 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6553 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6554 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6555 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6556 * THE SOFTWARE.
6557 */
6558///<reference path="../../Typedefs/jquery/jquery.d.ts"/>
6559///<reference path="../../Typedefs/globalize/globalize.d.ts"/>
6560///<reference path="../../Typedefs/lodash/lodash.d.ts"/>
6561/*
6562 * Power BI Visualizations
6563 *
6564 * Copyright (c) Microsoft Corporation
6565 * All rights reserved.
6566 * MIT License
6567 *
6568 * Permission is hereby granted, free of charge, to any person obtaining a copy
6569 * of this software and associated documentation files (the ""Software""), to deal
6570 * in the Software without restriction, including without limitation the rights
6571 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6572 * copies of the Software, and to permit persons to whom the Software is
6573 * furnished to do so, subject to the following conditions:
6574 *
6575 * The above copyright notice and this permission notice shall be included in
6576 * all copies or substantial portions of the Software.
6577 *
6578 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6579 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6580 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6581 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6582 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6583 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6584 * THE SOFTWARE.
6585 */
6586var powerbi;
6587(function (powerbi) {
6588 var data;
6589 (function (data) {
6590 /** Default IQueryExprVisitorWithArg implementation that others may derive from. */
6591 var DefaultSQExprVisitorWithArg = (function () {
6592 function DefaultSQExprVisitorWithArg() {
6593 }
6594 DefaultSQExprVisitorWithArg.prototype.visitEntity = function (expr, arg) {
6595 return this.visitDefault(expr, arg);
6596 };
6597 DefaultSQExprVisitorWithArg.prototype.visitColumnRef = function (expr, arg) {
6598 return this.visitDefault(expr, arg);
6599 };
6600 DefaultSQExprVisitorWithArg.prototype.visitMeasureRef = function (expr, arg) {
6601 return this.visitDefault(expr, arg);
6602 };
6603 DefaultSQExprVisitorWithArg.prototype.visitAggr = function (expr, arg) {
6604 return this.visitDefault(expr, arg);
6605 };
6606 DefaultSQExprVisitorWithArg.prototype.visitPercentile = function (expr, arg) {
6607 return this.visitDefault(expr, arg);
6608 };
6609 DefaultSQExprVisitorWithArg.prototype.visitHierarchy = function (expr, arg) {
6610 return this.visitDefault(expr, arg);
6611 };
6612 DefaultSQExprVisitorWithArg.prototype.visitHierarchyLevel = function (expr, arg) {
6613 return this.visitDefault(expr, arg);
6614 };
6615 DefaultSQExprVisitorWithArg.prototype.visitPropertyVariationSource = function (expr, arg) {
6616 return this.visitDefault(expr, arg);
6617 };
6618 DefaultSQExprVisitorWithArg.prototype.visitSelectRef = function (expr, arg) {
6619 return this.visitDefault(expr, arg);
6620 };
6621 DefaultSQExprVisitorWithArg.prototype.visitBetween = function (expr, arg) {
6622 return this.visitDefault(expr, arg);
6623 };
6624 DefaultSQExprVisitorWithArg.prototype.visitIn = function (expr, arg) {
6625 return this.visitDefault(expr, arg);
6626 };
6627 DefaultSQExprVisitorWithArg.prototype.visitAnd = function (expr, arg) {
6628 return this.visitDefault(expr, arg);
6629 };
6630 DefaultSQExprVisitorWithArg.prototype.visitOr = function (expr, arg) {
6631 return this.visitDefault(expr, arg);
6632 };
6633 DefaultSQExprVisitorWithArg.prototype.visitCompare = function (expr, arg) {
6634 return this.visitDefault(expr, arg);
6635 };
6636 DefaultSQExprVisitorWithArg.prototype.visitContains = function (expr, arg) {
6637 return this.visitDefault(expr, arg);
6638 };
6639 DefaultSQExprVisitorWithArg.prototype.visitExists = function (expr, arg) {
6640 return this.visitDefault(expr, arg);
6641 };
6642 DefaultSQExprVisitorWithArg.prototype.visitNot = function (expr, arg) {
6643 return this.visitDefault(expr, arg);
6644 };
6645 DefaultSQExprVisitorWithArg.prototype.visitStartsWith = function (expr, arg) {
6646 return this.visitDefault(expr, arg);
6647 };
6648 DefaultSQExprVisitorWithArg.prototype.visitConstant = function (expr, arg) {
6649 return this.visitDefault(expr, arg);
6650 };
6651 DefaultSQExprVisitorWithArg.prototype.visitDateSpan = function (expr, arg) {
6652 return this.visitDefault(expr, arg);
6653 };
6654 DefaultSQExprVisitorWithArg.prototype.visitDateAdd = function (expr, arg) {
6655 return this.visitDefault(expr, arg);
6656 };
6657 DefaultSQExprVisitorWithArg.prototype.visitNow = function (expr, arg) {
6658 return this.visitDefault(expr, arg);
6659 };
6660 DefaultSQExprVisitorWithArg.prototype.visitDefaultValue = function (expr, arg) {
6661 return this.visitDefault(expr, arg);
6662 };
6663 DefaultSQExprVisitorWithArg.prototype.visitAnyValue = function (expr, arg) {
6664 return this.visitDefault(expr, arg);
6665 };
6666 DefaultSQExprVisitorWithArg.prototype.visitArithmetic = function (expr, arg) {
6667 return this.visitDefault(expr, arg);
6668 };
6669 DefaultSQExprVisitorWithArg.prototype.visitFillRule = function (expr, arg) {
6670 return this.visitDefault(expr, arg);
6671 };
6672 DefaultSQExprVisitorWithArg.prototype.visitResourcePackageItem = function (expr, arg) {
6673 return this.visitDefault(expr, arg);
6674 };
6675 DefaultSQExprVisitorWithArg.prototype.visitScopedEval = function (expr, arg) {
6676 return this.visitDefault(expr, arg);
6677 };
6678 DefaultSQExprVisitorWithArg.prototype.visitDefault = function (expr, arg) {
6679 return;
6680 };
6681 return DefaultSQExprVisitorWithArg;
6682 }());
6683 data.DefaultSQExprVisitorWithArg = DefaultSQExprVisitorWithArg;
6684 /** Default ISQExprVisitor implementation that others may derive from. */
6685 var DefaultSQExprVisitor = (function (_super) {
6686 __extends(DefaultSQExprVisitor, _super);
6687 function DefaultSQExprVisitor() {
6688 _super.apply(this, arguments);
6689 }
6690 return DefaultSQExprVisitor;
6691 }(DefaultSQExprVisitorWithArg));
6692 data.DefaultSQExprVisitor = DefaultSQExprVisitor;
6693 /** Default ISQExprVisitor implementation that implements default traversal and that others may derive from. */
6694 var DefaultSQExprVisitorWithTraversal = (function () {
6695 function DefaultSQExprVisitorWithTraversal() {
6696 }
6697 DefaultSQExprVisitorWithTraversal.prototype.visitEntity = function (expr) {
6698 this.visitDefault(expr);
6699 };
6700 DefaultSQExprVisitorWithTraversal.prototype.visitColumnRef = function (expr) {
6701 expr.source.accept(this);
6702 };
6703 DefaultSQExprVisitorWithTraversal.prototype.visitMeasureRef = function (expr) {
6704 expr.source.accept(this);
6705 };
6706 DefaultSQExprVisitorWithTraversal.prototype.visitAggr = function (expr) {
6707 expr.arg.accept(this);
6708 };
6709 DefaultSQExprVisitorWithTraversal.prototype.visitPercentile = function (expr) {
6710 expr.arg.accept(this);
6711 };
6712 DefaultSQExprVisitorWithTraversal.prototype.visitHierarchy = function (expr) {
6713 expr.arg.accept(this);
6714 };
6715 DefaultSQExprVisitorWithTraversal.prototype.visitHierarchyLevel = function (expr) {
6716 expr.arg.accept(this);
6717 };
6718 DefaultSQExprVisitorWithTraversal.prototype.visitPropertyVariationSource = function (expr) {
6719 expr.arg.accept(this);
6720 };
6721 DefaultSQExprVisitorWithTraversal.prototype.visitSelectRef = function (expr) {
6722 this.visitDefault(expr);
6723 };
6724 DefaultSQExprVisitorWithTraversal.prototype.visitBetween = function (expr) {
6725 expr.arg.accept(this);
6726 expr.lower.accept(this);
6727 expr.upper.accept(this);
6728 };
6729 DefaultSQExprVisitorWithTraversal.prototype.visitIn = function (expr) {
6730 var args = expr.args;
6731 for (var i = 0, len = args.length; i < len; i++)
6732 args[i].accept(this);
6733 var values = expr.values;
6734 for (var i = 0, len = values.length; i < len; i++) {
6735 var valueTuple = values[i];
6736 for (var j = 0, jlen = valueTuple.length; j < jlen; j++)
6737 valueTuple[j].accept(this);
6738 }
6739 };
6740 DefaultSQExprVisitorWithTraversal.prototype.visitAnd = function (expr) {
6741 expr.left.accept(this);
6742 expr.right.accept(this);
6743 };
6744 DefaultSQExprVisitorWithTraversal.prototype.visitOr = function (expr) {
6745 expr.left.accept(this);
6746 expr.right.accept(this);
6747 };
6748 DefaultSQExprVisitorWithTraversal.prototype.visitCompare = function (expr) {
6749 expr.left.accept(this);
6750 expr.right.accept(this);
6751 };
6752 DefaultSQExprVisitorWithTraversal.prototype.visitContains = function (expr) {
6753 expr.left.accept(this);
6754 expr.right.accept(this);
6755 };
6756 DefaultSQExprVisitorWithTraversal.prototype.visitExists = function (expr) {
6757 expr.arg.accept(this);
6758 };
6759 DefaultSQExprVisitorWithTraversal.prototype.visitNot = function (expr) {
6760 expr.arg.accept(this);
6761 };
6762 DefaultSQExprVisitorWithTraversal.prototype.visitStartsWith = function (expr) {
6763 expr.left.accept(this);
6764 expr.right.accept(this);
6765 };
6766 DefaultSQExprVisitorWithTraversal.prototype.visitConstant = function (expr) {
6767 this.visitDefault(expr);
6768 };
6769 DefaultSQExprVisitorWithTraversal.prototype.visitDateSpan = function (expr) {
6770 expr.arg.accept(this);
6771 };
6772 DefaultSQExprVisitorWithTraversal.prototype.visitDateAdd = function (expr) {
6773 expr.arg.accept(this);
6774 };
6775 DefaultSQExprVisitorWithTraversal.prototype.visitNow = function (expr) {
6776 this.visitDefault(expr);
6777 };
6778 DefaultSQExprVisitorWithTraversal.prototype.visitDefaultValue = function (expr) {
6779 this.visitDefault(expr);
6780 };
6781 DefaultSQExprVisitorWithTraversal.prototype.visitAnyValue = function (expr) {
6782 this.visitDefault(expr);
6783 };
6784 DefaultSQExprVisitorWithTraversal.prototype.visitArithmetic = function (expr) {
6785 expr.left.accept(this);
6786 expr.right.accept(this);
6787 };
6788 DefaultSQExprVisitorWithTraversal.prototype.visitFillRule = function (expr) {
6789 expr.input.accept(this);
6790 var rule = expr.rule, gradient2 = rule.linearGradient2, gradient3 = rule.linearGradient3;
6791 if (gradient2) {
6792 this.visitLinearGradient2(gradient2);
6793 }
6794 if (gradient3) {
6795 this.visitLinearGradient3(gradient3);
6796 }
6797 };
6798 DefaultSQExprVisitorWithTraversal.prototype.visitLinearGradient2 = function (gradient2) {
6799 debug.assertValue(gradient2, 'gradient2');
6800 this.visitFillRuleStop(gradient2.min);
6801 this.visitFillRuleStop(gradient2.max);
6802 };
6803 DefaultSQExprVisitorWithTraversal.prototype.visitLinearGradient3 = function (gradient3) {
6804 debug.assertValue(gradient3, 'gradient3');
6805 this.visitFillRuleStop(gradient3.min);
6806 this.visitFillRuleStop(gradient3.mid);
6807 this.visitFillRuleStop(gradient3.max);
6808 };
6809 DefaultSQExprVisitorWithTraversal.prototype.visitResourcePackageItem = function (expr) {
6810 this.visitDefault(expr);
6811 };
6812 DefaultSQExprVisitorWithTraversal.prototype.visitScopedEval = function (expr) {
6813 expr.expression.accept(this);
6814 for (var _i = 0, _a = expr.scope; _i < _a.length; _i++) {
6815 var scopeExpr = _a[_i];
6816 scopeExpr.accept(this);
6817 }
6818 };
6819 DefaultSQExprVisitorWithTraversal.prototype.visitDefault = function (expr) {
6820 return;
6821 };
6822 DefaultSQExprVisitorWithTraversal.prototype.visitFillRuleStop = function (stop) {
6823 debug.assertValue(stop, 'stop');
6824 stop.color.accept(this);
6825 var value = stop.value;
6826 if (value)
6827 value.accept(this);
6828 };
6829 return DefaultSQExprVisitorWithTraversal;
6830 }());
6831 data.DefaultSQExprVisitorWithTraversal = DefaultSQExprVisitorWithTraversal;
6832 })(data = powerbi.data || (powerbi.data = {}));
6833})(powerbi || (powerbi = {}));
6834/*
6835 * Power BI Visualizations
6836 *
6837 * Copyright (c) Microsoft Corporation
6838 * All rights reserved.
6839 * MIT License
6840 *
6841 * Permission is hereby granted, free of charge, to any person obtaining a copy
6842 * of this software and associated documentation files (the ""Software""), to deal
6843 * in the Software without restriction, including without limitation the rights
6844 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6845 * copies of the Software, and to permit persons to whom the Software is
6846 * furnished to do so, subject to the following conditions:
6847 *
6848 * The above copyright notice and this permission notice shall be included in
6849 * all copies or substantial portions of the Software.
6850 *
6851 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6852 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6853 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6854 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6855 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6856 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6857 * THE SOFTWARE.
6858 */
6859var powerbi;
6860(function (powerbi) {
6861 function createEnumType(members) {
6862 return new EnumType(members);
6863 }
6864 powerbi.createEnumType = createEnumType;
6865 var EnumType = (function () {
6866 function EnumType(allMembers) {
6867 debug.assertValue(allMembers, 'allMembers');
6868 this.allMembers = allMembers;
6869 }
6870 EnumType.prototype.members = function (validMembers) {
6871 var allMembers = this.allMembers;
6872 if (!validMembers)
6873 return allMembers;
6874 var membersToReturn = [];
6875 for (var _i = 0, allMembers_1 = allMembers; _i < allMembers_1.length; _i++) {
6876 var member = allMembers_1[_i];
6877 if (_.contains(validMembers, member.value))
6878 membersToReturn.push(member);
6879 }
6880 return membersToReturn;
6881 };
6882 return EnumType;
6883 }());
6884})(powerbi || (powerbi = {}));
6885/*
6886 * Power BI Visualizations
6887 *
6888 * Copyright (c) Microsoft Corporation
6889 * All rights reserved.
6890 * MIT License
6891 *
6892 * Permission is hereby granted, free of charge, to any person obtaining a copy
6893 * of this software and associated documentation files (the ""Software""), to deal
6894 * in the Software without restriction, including without limitation the rights
6895 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6896 * copies of the Software, and to permit persons to whom the Software is
6897 * furnished to do so, subject to the following conditions:
6898 *
6899 * The above copyright notice and this permission notice shall be included in
6900 * all copies or substantial portions of the Software.
6901 *
6902 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6903 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6904 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6905 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6906 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6907 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6908 * THE SOFTWARE.
6909 */
6910var powerbi;
6911(function (powerbi) {
6912 var FillSolidColorTypeDescriptor;
6913 (function (FillSolidColorTypeDescriptor) {
6914 /** Gets a value indicating whether the descriptor is nullable or not. */
6915 function nullable(descriptor) {
6916 debug.assertValue(descriptor, 'descriptor');
6917 if (descriptor === true)
6918 return false;
6919 var advancedDescriptor = descriptor;
6920 return !!advancedDescriptor.nullable;
6921 }
6922 FillSolidColorTypeDescriptor.nullable = nullable;
6923 })(FillSolidColorTypeDescriptor = powerbi.FillSolidColorTypeDescriptor || (powerbi.FillSolidColorTypeDescriptor = {}));
6924})(powerbi || (powerbi = {}));
6925/*
6926 * Power BI Visualizations
6927 *
6928 * Copyright (c) Microsoft Corporation
6929 * All rights reserved.
6930 * MIT License
6931 *
6932 * Permission is hereby granted, free of charge, to any person obtaining a copy
6933 * of this software and associated documentation files (the ""Software""), to deal
6934 * in the Software without restriction, including without limitation the rights
6935 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6936 * copies of the Software, and to permit persons to whom the Software is
6937 * furnished to do so, subject to the following conditions:
6938 *
6939 * The above copyright notice and this permission notice shall be included in
6940 * all copies or substantial portions of the Software.
6941 *
6942 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6943 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6944 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6945 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6946 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6947 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6948 * THE SOFTWARE.
6949 */
6950/*
6951 * Power BI Visualizations
6952 *
6953 * Copyright (c) Microsoft Corporation
6954 * All rights reserved.
6955 * MIT License
6956 *
6957 * Permission is hereby granted, free of charge, to any person obtaining a copy
6958 * of this software and associated documentation files (the ""Software""), to deal
6959 * in the Software without restriction, including without limitation the rights
6960 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6961 * copies of the Software, and to permit persons to whom the Software is
6962 * furnished to do so, subject to the following conditions:
6963 *
6964 * The above copyright notice and this permission notice shall be included in
6965 * all copies or substantial portions of the Software.
6966 *
6967 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6968 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6969 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6970 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6971 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6972 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6973 * THE SOFTWARE.
6974 */
6975var powerbi;
6976(function (powerbi) {
6977 var ImageDefinition;
6978 (function (ImageDefinition) {
6979 ImageDefinition.urlType = { misc: { imageUrl: true } };
6980 })(ImageDefinition = powerbi.ImageDefinition || (powerbi.ImageDefinition = {}));
6981})(powerbi || (powerbi = {}));
6982/*
6983 * Power BI Visualizations
6984 *
6985 * Copyright (c) Microsoft Corporation
6986 * All rights reserved.
6987 * MIT License
6988 *
6989 * Permission is hereby granted, free of charge, to any person obtaining a copy
6990 * of this software and associated documentation files (the ""Software""), to deal
6991 * in the Software without restriction, including without limitation the rights
6992 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6993 * copies of the Software, and to permit persons to whom the Software is
6994 * furnished to do so, subject to the following conditions:
6995 *
6996 * The above copyright notice and this permission notice shall be included in
6997 * all copies or substantial portions of the Software.
6998 *
6999 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7000 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7001 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7002 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7003 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7004 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7005 * THE SOFTWARE.
7006 */
7007/*
7008 * Power BI Visualizations
7009 *
7010 * Copyright (c) Microsoft Corporation
7011 * All rights reserved.
7012 * MIT License
7013 *
7014 * Permission is hereby granted, free of charge, to any person obtaining a copy
7015 * of this software and associated documentation files (the ""Software""), to deal
7016 * in the Software without restriction, including without limitation the rights
7017 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7018 * copies of the Software, and to permit persons to whom the Software is
7019 * furnished to do so, subject to the following conditions:
7020 *
7021 * The above copyright notice and this permission notice shall be included in
7022 * all copies or substantial portions of the Software.
7023 *
7024 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7025 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7026 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7027 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7028 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7029 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7030 * THE SOFTWARE.
7031 */
7032var powerbi;
7033(function (powerbi) {
7034 var StructuralTypeDescriptor;
7035 (function (StructuralTypeDescriptor) {
7036 function isValid(type) {
7037 debug.assertValue(type, 'type');
7038 if (type.fill ||
7039 type.fillRule ||
7040 type.filter ||
7041 type.expression ||
7042 type.image ||
7043 type.paragraphs) {
7044 return true;
7045 }
7046 return false;
7047 }
7048 StructuralTypeDescriptor.isValid = isValid;
7049 })(StructuralTypeDescriptor = powerbi.StructuralTypeDescriptor || (powerbi.StructuralTypeDescriptor = {}));
7050})(powerbi || (powerbi = {}));
7051/*
7052 * Power BI Visualizations
7053 *
7054 * Copyright (c) Microsoft Corporation
7055 * All rights reserved.
7056 * MIT License
7057 *
7058 * Permission is hereby granted, free of charge, to any person obtaining a copy
7059 * of this software and associated documentation files (the ""Software""), to deal
7060 * in the Software without restriction, including without limitation the rights
7061 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7062 * copies of the Software, and to permit persons to whom the Software is
7063 * furnished to do so, subject to the following conditions:
7064 *
7065 * The above copyright notice and this permission notice shall be included in
7066 * all copies or substantial portions of the Software.
7067 *
7068 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7069 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7070 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7071 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7072 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7073 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7074 * THE SOFTWARE.
7075 */
7076var powerbi;
7077(function (powerbi) {
7078 var EnumExtensions = jsCommon.EnumExtensions;
7079 /** Describes a data value type, including a primitive type and extended type if any (derived from data category). */
7080 var ValueType = (function () {
7081 /** Do not call the ValueType constructor directly. Use the ValueType.fromXXX methods. */
7082 function ValueType(type, category, enumType) {
7083 debug.assert((!!type && ExtendedType[type] != null) || type === ExtendedType.Null, 'type');
7084 debug.assert(!!category || category === null, 'category');
7085 debug.assert(type !== ExtendedType.Enumeration || !!enumType, 'enumType');
7086 this.underlyingType = type;
7087 this.category = category;
7088 if (EnumExtensions.hasFlag(type, ExtendedType.Temporal)) {
7089 this.temporalType = new TemporalType(type);
7090 }
7091 if (EnumExtensions.hasFlag(type, ExtendedType.Geography)) {
7092 this.geographyType = new GeographyType(type);
7093 }
7094 if (EnumExtensions.hasFlag(type, ExtendedType.Miscellaneous)) {
7095 this.miscType = new MiscellaneousType(type);
7096 }
7097 if (EnumExtensions.hasFlag(type, ExtendedType.Formatting)) {
7098 this.formattingType = new FormattingType(type);
7099 }
7100 if (EnumExtensions.hasFlag(type, ExtendedType.Enumeration)) {
7101 this.enumType = enumType;
7102 }
7103 if (EnumExtensions.hasFlag(type, ExtendedType.Scripting)) {
7104 this.scriptingType = new ScriptType(type);
7105 }
7106 }
7107 /** Creates or retrieves a ValueType object based on the specified ValueTypeDescriptor. */
7108 ValueType.fromDescriptor = function (descriptor) {
7109 descriptor = descriptor || {};
7110 // Simplified primitive types
7111 if (descriptor.text)
7112 return ValueType.fromExtendedType(ExtendedType.Text);
7113 if (descriptor.integer)
7114 return ValueType.fromExtendedType(ExtendedType.Integer);
7115 if (descriptor.numeric)
7116 return ValueType.fromExtendedType(ExtendedType.Double);
7117 if (descriptor.bool)
7118 return ValueType.fromExtendedType(ExtendedType.Boolean);
7119 if (descriptor.dateTime)
7120 return ValueType.fromExtendedType(ExtendedType.DateTime);
7121 if (descriptor.duration)
7122 return ValueType.fromExtendedType(ExtendedType.Duration);
7123 if (descriptor.binary)
7124 return ValueType.fromExtendedType(ExtendedType.Binary);
7125 if (descriptor.none)
7126 return ValueType.fromExtendedType(ExtendedType.None);
7127 // Extended types
7128 if (descriptor.scripting) {
7129 if (descriptor.scripting.source)
7130 return ValueType.fromExtendedType(ExtendedType.ScriptSource);
7131 }
7132 if (descriptor.enumeration)
7133 return ValueType.fromEnum(descriptor.enumeration);
7134 if (descriptor.temporal) {
7135 if (descriptor.temporal.year)
7136 return ValueType.fromExtendedType(ExtendedType.Year_Integer);
7137 if (descriptor.temporal.month)
7138 return ValueType.fromExtendedType(ExtendedType.Month_Integer);
7139 }
7140 if (descriptor.geography) {
7141 if (descriptor.geography.address)
7142 return ValueType.fromExtendedType(ExtendedType.Address);
7143 if (descriptor.geography.city)
7144 return ValueType.fromExtendedType(ExtendedType.City);
7145 if (descriptor.geography.continent)
7146 return ValueType.fromExtendedType(ExtendedType.Continent);
7147 if (descriptor.geography.country)
7148 return ValueType.fromExtendedType(ExtendedType.Country);
7149 if (descriptor.geography.county)
7150 return ValueType.fromExtendedType(ExtendedType.County);
7151 if (descriptor.geography.region)
7152 return ValueType.fromExtendedType(ExtendedType.Region);
7153 if (descriptor.geography.postalCode)
7154 return ValueType.fromExtendedType(ExtendedType.PostalCode_Text);
7155 if (descriptor.geography.stateOrProvince)
7156 return ValueType.fromExtendedType(ExtendedType.StateOrProvince);
7157 if (descriptor.geography.place)
7158 return ValueType.fromExtendedType(ExtendedType.Place);
7159 if (descriptor.geography.latitude)
7160 return ValueType.fromExtendedType(ExtendedType.Latitude_Double);
7161 if (descriptor.geography.longitude)
7162 return ValueType.fromExtendedType(ExtendedType.Longitude_Double);
7163 }
7164 if (descriptor.misc) {
7165 if (descriptor.misc.image)
7166 return ValueType.fromExtendedType(ExtendedType.Image);
7167 if (descriptor.misc.imageUrl)
7168 return ValueType.fromExtendedType(ExtendedType.ImageUrl);
7169 if (descriptor.misc.webUrl)
7170 return ValueType.fromExtendedType(ExtendedType.WebUrl);
7171 if (descriptor.misc.barcode)
7172 return ValueType.fromExtendedType(ExtendedType.Barcode_Text);
7173 }
7174 if (descriptor.formatting) {
7175 if (descriptor.formatting.color)
7176 return ValueType.fromExtendedType(ExtendedType.Color);
7177 if (descriptor.formatting.formatString)
7178 return ValueType.fromExtendedType(ExtendedType.FormatString);
7179 if (descriptor.formatting.alignment)
7180 return ValueType.fromExtendedType(ExtendedType.Alignment);
7181 if (descriptor.formatting.labelDisplayUnits)
7182 return ValueType.fromExtendedType(ExtendedType.LabelDisplayUnits);
7183 if (descriptor.formatting.fontSize)
7184 return ValueType.fromExtendedType(ExtendedType.FontSize);
7185 if (descriptor.formatting.labelDensity)
7186 return ValueType.fromExtendedType(ExtendedType.LabelDensity);
7187 }
7188 if (descriptor.extendedType) {
7189 return ValueType.fromExtendedType(descriptor.extendedType);
7190 }
7191 return ValueType.fromExtendedType(ExtendedType.Null);
7192 };
7193 /** Advanced: Generally use fromDescriptor instead. Creates or retrieves a ValueType object for the specified ExtendedType. */
7194 ValueType.fromExtendedType = function (extendedType) {
7195 extendedType = extendedType || ExtendedType.Null;
7196 var primitiveType = getPrimitiveType(extendedType), category = getCategoryFromExtendedType(extendedType);
7197 debug.assert(primitiveType !== PrimitiveType.Null || extendedType === ExtendedType.Null, 'Cannot create ValueType for abstract extended type. Consider using fromDescriptor instead.');
7198 return ValueType.fromPrimitiveTypeAndCategory(primitiveType, category);
7199 };
7200 /** Creates or retrieves a ValueType object for the specified PrimitiveType and data category. */
7201 ValueType.fromPrimitiveTypeAndCategory = function (primitiveType, category) {
7202 primitiveType = primitiveType || PrimitiveType.Null;
7203 category = category || null;
7204 var id = primitiveType.toString();
7205 if (category)
7206 id += '|' + category;
7207 return ValueType.typeCache[id] || (ValueType.typeCache[id] = new ValueType(toExtendedType(primitiveType, category), category));
7208 };
7209 /** Creates a ValueType to describe the given IEnumType. */
7210 ValueType.fromEnum = function (enumType) {
7211 debug.assertValue(enumType, 'enumType');
7212 return new ValueType(ExtendedType.Enumeration, null, enumType);
7213 };
7214 /** Determines if the specified type is compatible from at least one of the otherTypes. */
7215 ValueType.isCompatibleTo = function (type, otherTypes) {
7216 debug.assertValue(type, 'type');
7217 debug.assertValue(otherTypes, 'otherTypes');
7218 var valueType = ValueType.fromDescriptor(type);
7219 for (var _i = 0, otherTypes_1 = otherTypes; _i < otherTypes_1.length; _i++) {
7220 var otherType = otherTypes_1[_i];
7221 var otherValueType = ValueType.fromDescriptor(otherType);
7222 if (otherValueType.isCompatibleFrom(valueType))
7223 return true;
7224 }
7225 return false;
7226 };
7227 /** Determines if the instance ValueType is convertable from the 'other' ValueType. */
7228 ValueType.prototype.isCompatibleFrom = function (other) {
7229 debug.assertValue(other, 'other');
7230 var otherPrimitiveType = other.primitiveType;
7231 if (this === other ||
7232 this.primitiveType === otherPrimitiveType ||
7233 otherPrimitiveType === PrimitiveType.Null)
7234 return true;
7235 return false;
7236 };
7237 /**
7238 * Determines if the instance ValueType is equal to the 'other' ValueType
7239 * @param {ValueType} other the other ValueType to check equality against
7240 * @returns True if the instance ValueType is equal to the 'other' ValueType
7241 */
7242 ValueType.prototype.equals = function (other) {
7243 return _.isEqual(this, other);
7244 };
7245 Object.defineProperty(ValueType.prototype, "primitiveType", {
7246 /** Gets the exact primitive type of this ValueType. */
7247 get: function () {
7248 return getPrimitiveType(this.underlyingType);
7249 },
7250 enumerable: true,
7251 configurable: true
7252 });
7253 Object.defineProperty(ValueType.prototype, "extendedType", {
7254 /** Gets the exact extended type of this ValueType. */
7255 get: function () {
7256 return this.underlyingType;
7257 },
7258 enumerable: true,
7259 configurable: true
7260 });
7261 Object.defineProperty(ValueType.prototype, "categoryString", {
7262 /** Gets the data category string (if any) for this ValueType. */
7263 get: function () {
7264 return this.category;
7265 },
7266 enumerable: true,
7267 configurable: true
7268 });
7269 Object.defineProperty(ValueType.prototype, "text", {
7270 // Simplified primitive types
7271 /** Indicates whether the type represents text values. */
7272 get: function () {
7273 return this.primitiveType === PrimitiveType.Text;
7274 },
7275 enumerable: true,
7276 configurable: true
7277 });
7278 Object.defineProperty(ValueType.prototype, "numeric", {
7279 /** Indicates whether the type represents any numeric value. */
7280 get: function () {
7281 return EnumExtensions.hasFlag(this.underlyingType, ExtendedType.Numeric);
7282 },
7283 enumerable: true,
7284 configurable: true
7285 });
7286 Object.defineProperty(ValueType.prototype, "integer", {
7287 /** Indicates whether the type represents integer numeric values. */
7288 get: function () {
7289 return this.primitiveType === PrimitiveType.Integer;
7290 },
7291 enumerable: true,
7292 configurable: true
7293 });
7294 Object.defineProperty(ValueType.prototype, "bool", {
7295 /** Indicates whether the type represents Boolean values. */
7296 get: function () {
7297 return this.primitiveType === PrimitiveType.Boolean;
7298 },
7299 enumerable: true,
7300 configurable: true
7301 });
7302 Object.defineProperty(ValueType.prototype, "dateTime", {
7303 /** Indicates whether the type represents any date/time values. */
7304 get: function () {
7305 return this.primitiveType === PrimitiveType.DateTime ||
7306 this.primitiveType === PrimitiveType.Date ||
7307 this.primitiveType === PrimitiveType.Time;
7308 },
7309 enumerable: true,
7310 configurable: true
7311 });
7312 Object.defineProperty(ValueType.prototype, "duration", {
7313 /** Indicates whether the type represents duration values. */
7314 get: function () {
7315 return this.primitiveType === PrimitiveType.Duration;
7316 },
7317 enumerable: true,
7318 configurable: true
7319 });
7320 Object.defineProperty(ValueType.prototype, "binary", {
7321 /** Indicates whether the type represents binary values. */
7322 get: function () {
7323 return this.primitiveType === PrimitiveType.Binary;
7324 },
7325 enumerable: true,
7326 configurable: true
7327 });
7328 Object.defineProperty(ValueType.prototype, "none", {
7329 /** Indicates whether the type represents none values. */
7330 get: function () {
7331 return this.primitiveType === PrimitiveType.None;
7332 },
7333 enumerable: true,
7334 configurable: true
7335 });
7336 Object.defineProperty(ValueType.prototype, "temporal", {
7337 // Extended types
7338 /** Returns an object describing temporal values represented by the type, if it represents a temporal type. */
7339 get: function () {
7340 return this.temporalType;
7341 },
7342 enumerable: true,
7343 configurable: true
7344 });
7345 Object.defineProperty(ValueType.prototype, "geography", {
7346 /** Returns an object describing geographic values represented by the type, if it represents a geographic type. */
7347 get: function () {
7348 return this.geographyType;
7349 },
7350 enumerable: true,
7351 configurable: true
7352 });
7353 Object.defineProperty(ValueType.prototype, "misc", {
7354 /** Returns an object describing the specific values represented by the type, if it represents a miscellaneous extended type. */
7355 get: function () {
7356 return this.miscType;
7357 },
7358 enumerable: true,
7359 configurable: true
7360 });
7361 Object.defineProperty(ValueType.prototype, "formatting", {
7362 /** Returns an object describing the formatting values represented by the type, if it represents a formatting type. */
7363 get: function () {
7364 return this.formattingType;
7365 },
7366 enumerable: true,
7367 configurable: true
7368 });
7369 Object.defineProperty(ValueType.prototype, "enum", {
7370 /** Returns an object describing the enum values represented by the type, if it represents an enumeration type. */
7371 get: function () {
7372 return this.enumType;
7373 },
7374 enumerable: true,
7375 configurable: true
7376 });
7377 Object.defineProperty(ValueType.prototype, "scripting", {
7378 get: function () {
7379 return this.scriptingType;
7380 },
7381 enumerable: true,
7382 configurable: true
7383 });
7384 ValueType.typeCache = {};
7385 return ValueType;
7386 }());
7387 powerbi.ValueType = ValueType;
7388 var ScriptType = (function () {
7389 function ScriptType(type) {
7390 debug.assert(!!type && EnumExtensions.hasFlag(type, ExtendedType.Scripting), 'type');
7391 this.underlyingType = type;
7392 }
7393 Object.defineProperty(ScriptType.prototype, "source", {
7394 get: function () {
7395 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.ScriptSource);
7396 },
7397 enumerable: true,
7398 configurable: true
7399 });
7400 return ScriptType;
7401 }());
7402 powerbi.ScriptType = ScriptType;
7403 var TemporalType = (function () {
7404 function TemporalType(type) {
7405 debug.assert(!!type && EnumExtensions.hasFlag(type, ExtendedType.Temporal), 'type');
7406 this.underlyingType = type;
7407 }
7408 Object.defineProperty(TemporalType.prototype, "year", {
7409 get: function () {
7410 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Year);
7411 },
7412 enumerable: true,
7413 configurable: true
7414 });
7415 Object.defineProperty(TemporalType.prototype, "month", {
7416 get: function () {
7417 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Month);
7418 },
7419 enumerable: true,
7420 configurable: true
7421 });
7422 return TemporalType;
7423 }());
7424 powerbi.TemporalType = TemporalType;
7425 var GeographyType = (function () {
7426 function GeographyType(type) {
7427 debug.assert(!!type && EnumExtensions.hasFlag(type, ExtendedType.Geography), 'type');
7428 this.underlyingType = type;
7429 }
7430 Object.defineProperty(GeographyType.prototype, "address", {
7431 get: function () {
7432 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Address);
7433 },
7434 enumerable: true,
7435 configurable: true
7436 });
7437 Object.defineProperty(GeographyType.prototype, "city", {
7438 get: function () {
7439 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.City);
7440 },
7441 enumerable: true,
7442 configurable: true
7443 });
7444 Object.defineProperty(GeographyType.prototype, "continent", {
7445 get: function () {
7446 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Continent);
7447 },
7448 enumerable: true,
7449 configurable: true
7450 });
7451 Object.defineProperty(GeographyType.prototype, "country", {
7452 get: function () {
7453 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Country);
7454 },
7455 enumerable: true,
7456 configurable: true
7457 });
7458 Object.defineProperty(GeographyType.prototype, "county", {
7459 get: function () {
7460 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.County);
7461 },
7462 enumerable: true,
7463 configurable: true
7464 });
7465 Object.defineProperty(GeographyType.prototype, "region", {
7466 get: function () {
7467 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Region);
7468 },
7469 enumerable: true,
7470 configurable: true
7471 });
7472 Object.defineProperty(GeographyType.prototype, "postalCode", {
7473 get: function () {
7474 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.PostalCode);
7475 },
7476 enumerable: true,
7477 configurable: true
7478 });
7479 Object.defineProperty(GeographyType.prototype, "stateOrProvince", {
7480 get: function () {
7481 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.StateOrProvince);
7482 },
7483 enumerable: true,
7484 configurable: true
7485 });
7486 Object.defineProperty(GeographyType.prototype, "place", {
7487 get: function () {
7488 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Place);
7489 },
7490 enumerable: true,
7491 configurable: true
7492 });
7493 Object.defineProperty(GeographyType.prototype, "latitude", {
7494 get: function () {
7495 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Latitude);
7496 },
7497 enumerable: true,
7498 configurable: true
7499 });
7500 Object.defineProperty(GeographyType.prototype, "longitude", {
7501 get: function () {
7502 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Longitude);
7503 },
7504 enumerable: true,
7505 configurable: true
7506 });
7507 return GeographyType;
7508 }());
7509 powerbi.GeographyType = GeographyType;
7510 var MiscellaneousType = (function () {
7511 function MiscellaneousType(type) {
7512 debug.assert(!!type && EnumExtensions.hasFlag(type, ExtendedType.Miscellaneous), 'type');
7513 this.underlyingType = type;
7514 }
7515 Object.defineProperty(MiscellaneousType.prototype, "image", {
7516 get: function () {
7517 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Image);
7518 },
7519 enumerable: true,
7520 configurable: true
7521 });
7522 Object.defineProperty(MiscellaneousType.prototype, "imageUrl", {
7523 get: function () {
7524 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.ImageUrl);
7525 },
7526 enumerable: true,
7527 configurable: true
7528 });
7529 Object.defineProperty(MiscellaneousType.prototype, "webUrl", {
7530 get: function () {
7531 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.WebUrl);
7532 },
7533 enumerable: true,
7534 configurable: true
7535 });
7536 Object.defineProperty(MiscellaneousType.prototype, "barcode", {
7537 get: function () {
7538 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Barcode);
7539 },
7540 enumerable: true,
7541 configurable: true
7542 });
7543 return MiscellaneousType;
7544 }());
7545 powerbi.MiscellaneousType = MiscellaneousType;
7546 var FormattingType = (function () {
7547 function FormattingType(type) {
7548 debug.assert(!!type && EnumExtensions.hasFlag(type, ExtendedType.Formatting), 'type');
7549 this.underlyingType = type;
7550 }
7551 Object.defineProperty(FormattingType.prototype, "color", {
7552 get: function () {
7553 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Color);
7554 },
7555 enumerable: true,
7556 configurable: true
7557 });
7558 Object.defineProperty(FormattingType.prototype, "formatString", {
7559 get: function () {
7560 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.FormatString);
7561 },
7562 enumerable: true,
7563 configurable: true
7564 });
7565 Object.defineProperty(FormattingType.prototype, "alignment", {
7566 get: function () {
7567 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.Alignment);
7568 },
7569 enumerable: true,
7570 configurable: true
7571 });
7572 Object.defineProperty(FormattingType.prototype, "labelDisplayUnits", {
7573 get: function () {
7574 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.LabelDisplayUnits);
7575 },
7576 enumerable: true,
7577 configurable: true
7578 });
7579 Object.defineProperty(FormattingType.prototype, "fontSize", {
7580 get: function () {
7581 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.FontSize);
7582 },
7583 enumerable: true,
7584 configurable: true
7585 });
7586 Object.defineProperty(FormattingType.prototype, "labelDensity", {
7587 get: function () {
7588 return matchesExtendedTypeWithAnyPrimitive(this.underlyingType, ExtendedType.LabelDensity);
7589 },
7590 enumerable: true,
7591 configurable: true
7592 });
7593 return FormattingType;
7594 }());
7595 powerbi.FormattingType = FormattingType;
7596 /** Defines primitive value types. Must be consistent with types defined by server conceptual schema. */
7597 (function (PrimitiveType) {
7598 PrimitiveType[PrimitiveType["Null"] = 0] = "Null";
7599 PrimitiveType[PrimitiveType["Text"] = 1] = "Text";
7600 PrimitiveType[PrimitiveType["Decimal"] = 2] = "Decimal";
7601 PrimitiveType[PrimitiveType["Double"] = 3] = "Double";
7602 PrimitiveType[PrimitiveType["Integer"] = 4] = "Integer";
7603 PrimitiveType[PrimitiveType["Boolean"] = 5] = "Boolean";
7604 PrimitiveType[PrimitiveType["Date"] = 6] = "Date";
7605 PrimitiveType[PrimitiveType["DateTime"] = 7] = "DateTime";
7606 PrimitiveType[PrimitiveType["DateTimeZone"] = 8] = "DateTimeZone";
7607 PrimitiveType[PrimitiveType["Time"] = 9] = "Time";
7608 PrimitiveType[PrimitiveType["Duration"] = 10] = "Duration";
7609 PrimitiveType[PrimitiveType["Binary"] = 11] = "Binary";
7610 PrimitiveType[PrimitiveType["None"] = 12] = "None";
7611 })(powerbi.PrimitiveType || (powerbi.PrimitiveType = {}));
7612 var PrimitiveType = powerbi.PrimitiveType;
7613 /** Defines extended value types, which include primitive types and known data categories constrained to expected primitive types. */
7614 (function (ExtendedType) {
7615 // Flags (1 << 8-15 range [0xFF00])
7616 // Important: Enum members must be declared before they are used in TypeScript.
7617 ExtendedType[ExtendedType["Numeric"] = 256] = "Numeric";
7618 ExtendedType[ExtendedType["Temporal"] = 512] = "Temporal";
7619 ExtendedType[ExtendedType["Geography"] = 1024] = "Geography";
7620 ExtendedType[ExtendedType["Miscellaneous"] = 2048] = "Miscellaneous";
7621 ExtendedType[ExtendedType["Formatting"] = 4096] = "Formatting";
7622 ExtendedType[ExtendedType["Scripting"] = 8192] = "Scripting";
7623 // Primitive types (0-255 range [0xFF] | flags)
7624 // The member names and base values must match those in PrimitiveType.
7625 ExtendedType[ExtendedType["Null"] = 0] = "Null";
7626 ExtendedType[ExtendedType["Text"] = 1] = "Text";
7627 ExtendedType[ExtendedType["Decimal"] = 258] = "Decimal";
7628 ExtendedType[ExtendedType["Double"] = 259] = "Double";
7629 ExtendedType[ExtendedType["Integer"] = 260] = "Integer";
7630 ExtendedType[ExtendedType["Boolean"] = 5] = "Boolean";
7631 ExtendedType[ExtendedType["Date"] = 518] = "Date";
7632 ExtendedType[ExtendedType["DateTime"] = 519] = "DateTime";
7633 ExtendedType[ExtendedType["DateTimeZone"] = 520] = "DateTimeZone";
7634 ExtendedType[ExtendedType["Time"] = 521] = "Time";
7635 ExtendedType[ExtendedType["Duration"] = 10] = "Duration";
7636 ExtendedType[ExtendedType["Binary"] = 11] = "Binary";
7637 ExtendedType[ExtendedType["None"] = 12] = "None";
7638 // Extended types (0-32767 << 16 range [0xFFFF0000] | corresponding primitive type | flags)
7639 // Temporal
7640 ExtendedType[ExtendedType["Year"] = 66048] = "Year";
7641 ExtendedType[ExtendedType["Year_Text"] = 66049] = "Year_Text";
7642 ExtendedType[ExtendedType["Year_Integer"] = 66308] = "Year_Integer";
7643 ExtendedType[ExtendedType["Year_Date"] = 66054] = "Year_Date";
7644 ExtendedType[ExtendedType["Year_DateTime"] = 66055] = "Year_DateTime";
7645 ExtendedType[ExtendedType["Month"] = 131584] = "Month";
7646 ExtendedType[ExtendedType["Month_Text"] = 131585] = "Month_Text";
7647 ExtendedType[ExtendedType["Month_Integer"] = 131844] = "Month_Integer";
7648 ExtendedType[ExtendedType["Month_Date"] = 131590] = "Month_Date";
7649 ExtendedType[ExtendedType["Month_DateTime"] = 131591] = "Month_DateTime";
7650 // Geography
7651 ExtendedType[ExtendedType["Address"] = 6554625] = "Address";
7652 ExtendedType[ExtendedType["City"] = 6620161] = "City";
7653 ExtendedType[ExtendedType["Continent"] = 6685697] = "Continent";
7654 ExtendedType[ExtendedType["Country"] = 6751233] = "Country";
7655 ExtendedType[ExtendedType["County"] = 6816769] = "County";
7656 ExtendedType[ExtendedType["Region"] = 6882305] = "Region";
7657 ExtendedType[ExtendedType["PostalCode"] = 6947840] = "PostalCode";
7658 ExtendedType[ExtendedType["PostalCode_Text"] = 6947841] = "PostalCode_Text";
7659 ExtendedType[ExtendedType["PostalCode_Integer"] = 6948100] = "PostalCode_Integer";
7660 ExtendedType[ExtendedType["StateOrProvince"] = 7013377] = "StateOrProvince";
7661 ExtendedType[ExtendedType["Place"] = 7078913] = "Place";
7662 ExtendedType[ExtendedType["Latitude"] = 7144448] = "Latitude";
7663 ExtendedType[ExtendedType["Latitude_Decimal"] = 7144706] = "Latitude_Decimal";
7664 ExtendedType[ExtendedType["Latitude_Double"] = 7144707] = "Latitude_Double";
7665 ExtendedType[ExtendedType["Longitude"] = 7209984] = "Longitude";
7666 ExtendedType[ExtendedType["Longitude_Decimal"] = 7210242] = "Longitude_Decimal";
7667 ExtendedType[ExtendedType["Longitude_Double"] = 7210243] = "Longitude_Double";
7668 // Miscellaneous
7669 ExtendedType[ExtendedType["Image"] = 13109259] = "Image";
7670 ExtendedType[ExtendedType["ImageUrl"] = 13174785] = "ImageUrl";
7671 ExtendedType[ExtendedType["WebUrl"] = 13240321] = "WebUrl";
7672 ExtendedType[ExtendedType["Barcode"] = 13305856] = "Barcode";
7673 ExtendedType[ExtendedType["Barcode_Text"] = 13305857] = "Barcode_Text";
7674 ExtendedType[ExtendedType["Barcode_Integer"] = 13306116] = "Barcode_Integer";
7675 // Formatting
7676 ExtendedType[ExtendedType["Color"] = 19664897] = "Color";
7677 ExtendedType[ExtendedType["FormatString"] = 19730433] = "FormatString";
7678 ExtendedType[ExtendedType["Alignment"] = 20058113] = "Alignment";
7679 ExtendedType[ExtendedType["LabelDisplayUnits"] = 20123649] = "LabelDisplayUnits";
7680 ExtendedType[ExtendedType["FontSize"] = 20189443] = "FontSize";
7681 ExtendedType[ExtendedType["LabelDensity"] = 20254979] = "LabelDensity";
7682 // Enumeration
7683 ExtendedType[ExtendedType["Enumeration"] = 26214401] = "Enumeration";
7684 // Scripting
7685 ExtendedType[ExtendedType["ScriptSource"] = 32776193] = "ScriptSource";
7686 })(powerbi.ExtendedType || (powerbi.ExtendedType = {}));
7687 var ExtendedType = powerbi.ExtendedType;
7688 var PrimitiveTypeMask = 0xFF;
7689 var PrimitiveTypeWithFlagsMask = 0xFFFF;
7690 var PrimitiveTypeFlagsExcludedMask = 0xFFFF0000;
7691 function getPrimitiveType(extendedType) {
7692 return extendedType & PrimitiveTypeMask;
7693 }
7694 function isPrimitiveType(extendedType) {
7695 return (extendedType & PrimitiveTypeWithFlagsMask) === extendedType;
7696 }
7697 function getCategoryFromExtendedType(extendedType) {
7698 if (isPrimitiveType(extendedType))
7699 return null;
7700 var category = ExtendedType[extendedType];
7701 if (category) {
7702 // Check for ExtendedType declaration without a primitive type.
7703 // If exists, use it as category (e.g. Longitude rather than Longitude_Double)
7704 // Otherwise use the ExtendedType declaration with a primitive type (e.g. Address)
7705 var delimIdx = category.lastIndexOf('_');
7706 if (delimIdx > 0) {
7707 var baseCategory = category.slice(0, delimIdx);
7708 if (ExtendedType[baseCategory]) {
7709 debug.assert((ExtendedType[baseCategory] & PrimitiveTypeFlagsExcludedMask) === (extendedType & PrimitiveTypeFlagsExcludedMask), 'Unexpected value for ExtendedType base member of ' + extendedType);
7710 category = baseCategory;
7711 }
7712 }
7713 }
7714 return category || null;
7715 }
7716 function toExtendedType(primitiveType, category) {
7717 var primitiveString = PrimitiveType[primitiveType];
7718 var t = ExtendedType[primitiveString];
7719 if (t == null) {
7720 debug.assertFail('Unexpected primitiveType ' + primitiveType);
7721 t = ExtendedType.Null;
7722 }
7723 if (primitiveType && category) {
7724 var categoryType = ExtendedType[category];
7725 if (categoryType) {
7726 var categoryPrimitiveType = getPrimitiveType(categoryType);
7727 if (categoryPrimitiveType === PrimitiveType.Null) {
7728 // Category supports multiple primitive types, check if requested primitive type is supported
7729 // (note: important to use t here rather than primitiveType as it may include primitive type flags)
7730 categoryType = t | categoryType;
7731 if (ExtendedType[categoryType]) {
7732 debug.assert(ExtendedType[categoryType] === (category + '_' + primitiveString), 'Unexpected name for ExtendedType member ' + categoryType);
7733 t = categoryType;
7734 }
7735 }
7736 else if (categoryPrimitiveType === primitiveType) {
7737 // Primitive type matches the single supported type for the category
7738 t = categoryType;
7739 }
7740 }
7741 }
7742 return t;
7743 }
7744 function matchesExtendedTypeWithAnyPrimitive(a, b) {
7745 return (a & PrimitiveTypeFlagsExcludedMask) === (b & PrimitiveTypeFlagsExcludedMask);
7746 }
7747})(powerbi || (powerbi = {}));
7748/*
7749 * Power BI Visualizations
7750 *
7751 * Copyright (c) Microsoft Corporation
7752 * All rights reserved.
7753 * MIT License
7754 *
7755 * Permission is hereby granted, free of charge, to any person obtaining a copy
7756 * of this software and associated documentation files (the ""Software""), to deal
7757 * in the Software without restriction, including without limitation the rights
7758 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7759 * copies of the Software, and to permit persons to whom the Software is
7760 * furnished to do so, subject to the following conditions:
7761 *
7762 * The above copyright notice and this permission notice shall be included in
7763 * all copies or substantial portions of the Software.
7764 *
7765 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7766 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7767 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7768 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7769 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7770 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7771 * THE SOFTWARE.
7772 */
7773var powerbi;
7774(function (powerbi) {
7775 var data;
7776 (function (data) {
7777 (function (DataShapeBindingLimitType) {
7778 DataShapeBindingLimitType[DataShapeBindingLimitType["Top"] = 0] = "Top";
7779 DataShapeBindingLimitType[DataShapeBindingLimitType["First"] = 1] = "First";
7780 DataShapeBindingLimitType[DataShapeBindingLimitType["Last"] = 2] = "Last";
7781 DataShapeBindingLimitType[DataShapeBindingLimitType["Sample"] = 3] = "Sample";
7782 DataShapeBindingLimitType[DataShapeBindingLimitType["Bottom"] = 4] = "Bottom";
7783 })(data.DataShapeBindingLimitType || (data.DataShapeBindingLimitType = {}));
7784 var DataShapeBindingLimitType = data.DataShapeBindingLimitType;
7785 (function (SubtotalType) {
7786 SubtotalType[SubtotalType["None"] = 0] = "None";
7787 SubtotalType[SubtotalType["Before"] = 1] = "Before";
7788 SubtotalType[SubtotalType["After"] = 2] = "After";
7789 })(data.SubtotalType || (data.SubtotalType = {}));
7790 var SubtotalType = data.SubtotalType;
7791 })(data = powerbi.data || (powerbi.data = {}));
7792})(powerbi || (powerbi = {}));
7793/*
7794 * Power BI Visualizations
7795 *
7796 * Copyright (c) Microsoft Corporation
7797 * All rights reserved.
7798 * MIT License
7799 *
7800 * Permission is hereby granted, free of charge, to any person obtaining a copy
7801 * of this software and associated documentation files (the ""Software""), to deal
7802 * in the Software without restriction, including without limitation the rights
7803 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7804 * copies of the Software, and to permit persons to whom the Software is
7805 * furnished to do so, subject to the following conditions:
7806 *
7807 * The above copyright notice and this permission notice shall be included in
7808 * all copies or substantial portions of the Software.
7809 *
7810 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7811 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7812 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7813 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7814 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7815 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7816 * THE SOFTWARE.
7817 */
7818var powerbi;
7819(function (powerbi) {
7820 var data;
7821 (function (data) {
7822 var DataShapeBindingDataReduction;
7823 (function (DataShapeBindingDataReduction) {
7824 function createFrom(reduction) {
7825 if (!reduction)
7826 return;
7827 var result;
7828 if (reduction.top) {
7829 result = {
7830 Top: {}
7831 };
7832 if (reduction.top.count)
7833 result.Top.Count = reduction.top.count;
7834 }
7835 if (reduction.bottom) {
7836 result = {
7837 Bottom: {}
7838 };
7839 if (reduction.bottom.count)
7840 result.Bottom.Count = reduction.bottom.count;
7841 }
7842 if (reduction.sample) {
7843 result = {
7844 Sample: {}
7845 };
7846 if (reduction.sample.count)
7847 result.Sample.Count = reduction.sample.count;
7848 }
7849 if (reduction.window) {
7850 result = {
7851 Window: {}
7852 };
7853 if (reduction.window.count)
7854 result.Window.Count = reduction.window.count;
7855 }
7856 return result;
7857 }
7858 DataShapeBindingDataReduction.createFrom = createFrom;
7859 })(DataShapeBindingDataReduction = data.DataShapeBindingDataReduction || (data.DataShapeBindingDataReduction = {}));
7860 })(data = powerbi.data || (powerbi.data = {}));
7861})(powerbi || (powerbi = {}));
7862/*
7863 * Power BI Visualizations
7864 *
7865 * Copyright (c) Microsoft Corporation
7866 * All rights reserved.
7867 * MIT License
7868 *
7869 * Permission is hereby granted, free of charge, to any person obtaining a copy
7870 * of this software and associated documentation files (the ""Software""), to deal
7871 * in the Software without restriction, including without limitation the rights
7872 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7873 * copies of the Software, and to permit persons to whom the Software is
7874 * furnished to do so, subject to the following conditions:
7875 *
7876 * The above copyright notice and this permission notice shall be included in
7877 * all copies or substantial portions of the Software.
7878 *
7879 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7880 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7881 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7882 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7883 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7884 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7885 * THE SOFTWARE.
7886 */
7887var powerbi;
7888(function (powerbi) {
7889 var data;
7890 (function (data) {
7891 /** Represents a federated conceptual schema. */
7892 var FederatedConceptualSchema = (function () {
7893 function FederatedConceptualSchema(options) {
7894 debug.assertValue(options, 'options');
7895 this.schemas = options.schemas;
7896 if (options.links)
7897 this.links = options.links;
7898 }
7899 FederatedConceptualSchema.prototype.schema = function (name) {
7900 return this.schemas[name];
7901 };
7902 return FederatedConceptualSchema;
7903 }());
7904 data.FederatedConceptualSchema = FederatedConceptualSchema;
7905 })(data = powerbi.data || (powerbi.data = {}));
7906})(powerbi || (powerbi = {}));
7907/*
7908 * Power BI Visualizations
7909 *
7910 * Copyright (c) Microsoft Corporation
7911 * All rights reserved.
7912 * MIT License
7913 *
7914 * Permission is hereby granted, free of charge, to any person obtaining a copy
7915 * of this software and associated documentation files (the ""Software""), to deal
7916 * in the Software without restriction, including without limitation the rights
7917 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7918 * copies of the Software, and to permit persons to whom the Software is
7919 * furnished to do so, subject to the following conditions:
7920 *
7921 * The above copyright notice and this permission notice shall be included in
7922 * all copies or substantial portions of the Software.
7923 *
7924 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7925 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7926 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7927 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7928 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7929 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7930 * THE SOFTWARE.
7931 */
7932var powerbi;
7933(function (powerbi) {
7934 var data;
7935 (function (data_1) {
7936 var Selector;
7937 (function (Selector) {
7938 function filterFromSelector(selectors, isNot) {
7939 if (_.isEmpty(selectors))
7940 return;
7941 var exprs = [];
7942 for (var i = 0, ilen = selectors.length; i < ilen; i++) {
7943 var identity = selectors[i];
7944 var data_2 = identity.data;
7945 var exprToAdd = undefined;
7946 if (data_2 && data_2.length) {
7947 for (var j = 0, jlen = data_2.length; j < jlen; j++) {
7948 exprToAdd = data_1.SQExprBuilder.and(exprToAdd, identity.data[j].expr);
7949 }
7950 }
7951 if (exprToAdd)
7952 exprs.push(exprToAdd);
7953 }
7954 if (!_.isEmpty(exprs))
7955 return powerbi.DataViewScopeIdentity.filterFromExprs(exprs, isNot);
7956 }
7957 Selector.filterFromSelector = filterFromSelector;
7958 function matchesData(selector, identities) {
7959 debug.assertValue(selector, 'selector');
7960 debug.assertValue(selector.data, 'selector.data');
7961 debug.assertValue(identities, 'identities');
7962 var selectorData = selector.data;
7963 if (selectorData.length !== identities.length)
7964 return false;
7965 for (var i = 0, len = selectorData.length; i < len; i++) {
7966 var dataItem = selector.data[i];
7967 var selectorDataItem = dataItem;
7968 if (selectorDataItem.expr) {
7969 if (!powerbi.DataViewScopeIdentity.equals(selectorDataItem, identities[i]))
7970 return false;
7971 }
7972 else {
7973 if (!data_1.DataViewScopeWildcard.matches(dataItem, identities[i]))
7974 return false;
7975 }
7976 }
7977 return true;
7978 }
7979 Selector.matchesData = matchesData;
7980 function matchesKeys(selector, keysList) {
7981 debug.assertValue(selector, 'selector');
7982 debug.assertValue(selector.data, 'selector.data');
7983 debug.assertValue(keysList, 'keysList');
7984 var selectorData = selector.data, selectorDataLength = selectorData.length;
7985 if (selectorDataLength !== keysList.length)
7986 return false;
7987 for (var i = 0; i < selectorDataLength; i++) {
7988 var selectorDataItem = selector.data[i], selectorDataExprs = void 0;
7989 if (selectorDataItem.expr) {
7990 selectorDataExprs = data_1.ScopeIdentityExtractor.getKeys(selectorDataItem.expr);
7991 }
7992 else if (selectorDataItem.exprs) {
7993 selectorDataExprs = selectorDataItem.exprs;
7994 }
7995 else {
7996 // In case DataViewRoleWildcard
7997 return false;
7998 }
7999 if (!selectorDataExprs)
8000 continue;
8001 if (!data_1.SQExprUtils.sequenceEqual(keysList[i], selectorDataExprs))
8002 return false;
8003 }
8004 return true;
8005 }
8006 Selector.matchesKeys = matchesKeys;
8007 /** Determines whether two selectors are equal. */
8008 function equals(x, y) {
8009 // Normalize falsy to null
8010 x = x || null;
8011 y = y || null;
8012 if (x === y)
8013 return true;
8014 if (!x !== !y)
8015 return false;
8016 debug.assertValue(x, 'x');
8017 debug.assertValue(y, 'y');
8018 if (x.id !== y.id)
8019 return false;
8020 if (x.metadata !== y.metadata)
8021 return false;
8022 if (!equalsDataArray(x.data, y.data))
8023 return false;
8024 return true;
8025 }
8026 Selector.equals = equals;
8027 function equalsDataArray(x, y) {
8028 // Normalize falsy to null
8029 x = x || null;
8030 y = y || null;
8031 if (x === y)
8032 return true;
8033 if (!x !== !y)
8034 return false;
8035 if (x.length !== y.length)
8036 return false;
8037 for (var i = 0, len = x.length; i < len; i++) {
8038 if (!equalsData(x[i], y[i]))
8039 return false;
8040 }
8041 return true;
8042 }
8043 function equalsData(x, y) {
8044 var selector1 = x;
8045 var selector2 = y;
8046 if (selector1.expr && selector2.expr)
8047 return powerbi.DataViewScopeIdentity.equals(selector1, selector2);
8048 if (selector1.exprs && selector2.exprs)
8049 return data_1.DataViewScopeWildcard.equals(selector1, selector2);
8050 if (selector1.roles && selector2.roles)
8051 return data_1.DataViewRoleWildcard.equals(selector1, selector2);
8052 return false;
8053 }
8054 function getKey(selector) {
8055 var toStringify = {};
8056 if (selector.data) {
8057 var data_3 = [];
8058 for (var i = 0, ilen = selector.data.length; i < ilen; i++) {
8059 data_3.push(selector.data[i].key);
8060 }
8061 toStringify.data = data_3;
8062 }
8063 if (selector.metadata)
8064 toStringify.metadata = selector.metadata;
8065 if (selector.id)
8066 toStringify.id = selector.id;
8067 return JSON.stringify(toStringify);
8068 }
8069 Selector.getKey = getKey;
8070 function containsWildcard(selector) {
8071 debug.assertValue(selector, 'selector');
8072 var dataItems = selector.data;
8073 if (!dataItems)
8074 return false;
8075 for (var _i = 0, dataItems_1 = dataItems; _i < dataItems_1.length; _i++) {
8076 var dataItem = dataItems_1[_i];
8077 var wildCard = dataItem;
8078 if (wildCard.exprs || wildCard.roles)
8079 return true;
8080 }
8081 return false;
8082 }
8083 Selector.containsWildcard = containsWildcard;
8084 function hasRoleWildcard(selector) {
8085 debug.assertValue(selector, 'selector');
8086 var dataItems = selector.data;
8087 if (_.isEmpty(dataItems))
8088 return false;
8089 for (var _i = 0, dataItems_2 = dataItems; _i < dataItems_2.length; _i++) {
8090 var dataItem = dataItems_2[_i];
8091 if (isRoleWildcard(dataItem))
8092 return true;
8093 }
8094 return false;
8095 }
8096 Selector.hasRoleWildcard = hasRoleWildcard;
8097 function isRoleWildcard(dataItem) {
8098 return !_.isEmpty(dataItem.roles);
8099 }
8100 Selector.isRoleWildcard = isRoleWildcard;
8101 })(Selector = data_1.Selector || (data_1.Selector = {}));
8102 })(data = powerbi.data || (powerbi.data = {}));
8103})(powerbi || (powerbi = {}));
8104/*
8105 * Power BI Visualizations
8106 *
8107 * Copyright (c) Microsoft Corporation
8108 * All rights reserved.
8109 * MIT License
8110 *
8111 * Permission is hereby granted, free of charge, to any person obtaining a copy
8112 * of this software and associated documentation files (the ""Software""), to deal
8113 * in the Software without restriction, including without limitation the rights
8114 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8115 * copies of the Software, and to permit persons to whom the Software is
8116 * furnished to do so, subject to the following conditions:
8117 *
8118 * The above copyright notice and this permission notice shall be included in
8119 * all copies or substantial portions of the Software.
8120 *
8121 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8122 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8123 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8124 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8125 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8126 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8127 * THE SOFTWARE.
8128 */
8129var powerbi;
8130(function (powerbi) {
8131 var data;
8132 (function (data) {
8133 (function (EntitySourceType) {
8134 EntitySourceType[EntitySourceType["Table"] = 0] = "Table";
8135 EntitySourceType[EntitySourceType["Pod"] = 1] = "Pod";
8136 })(data.EntitySourceType || (data.EntitySourceType = {}));
8137 var EntitySourceType = data.EntitySourceType;
8138 function getArithmeticOperatorName(arithmeticOperatorKind) {
8139 switch (arithmeticOperatorKind) {
8140 case 0 /* Add */:
8141 return "Add";
8142 case 1 /* Subtract */:
8143 return "Subtract";
8144 case 2 /* Multiply */:
8145 return "Multiply";
8146 case 3 /* Divide */:
8147 return "Divide";
8148 }
8149 throw new Error('Unexpected ArithmeticOperatorKind: ' + arithmeticOperatorKind);
8150 }
8151 data.getArithmeticOperatorName = getArithmeticOperatorName;
8152 (function (TimeUnit) {
8153 TimeUnit[TimeUnit["Day"] = 0] = "Day";
8154 TimeUnit[TimeUnit["Week"] = 1] = "Week";
8155 TimeUnit[TimeUnit["Month"] = 2] = "Month";
8156 TimeUnit[TimeUnit["Year"] = 3] = "Year";
8157 TimeUnit[TimeUnit["Decade"] = 4] = "Decade";
8158 TimeUnit[TimeUnit["Second"] = 5] = "Second";
8159 TimeUnit[TimeUnit["Minute"] = 6] = "Minute";
8160 TimeUnit[TimeUnit["Hour"] = 7] = "Hour";
8161 })(data.TimeUnit || (data.TimeUnit = {}));
8162 var TimeUnit = data.TimeUnit;
8163 (function (QueryAggregateFunction) {
8164 QueryAggregateFunction[QueryAggregateFunction["Sum"] = 0] = "Sum";
8165 QueryAggregateFunction[QueryAggregateFunction["Avg"] = 1] = "Avg";
8166 QueryAggregateFunction[QueryAggregateFunction["Count"] = 2] = "Count";
8167 QueryAggregateFunction[QueryAggregateFunction["Min"] = 3] = "Min";
8168 QueryAggregateFunction[QueryAggregateFunction["Max"] = 4] = "Max";
8169 QueryAggregateFunction[QueryAggregateFunction["CountNonNull"] = 5] = "CountNonNull";
8170 QueryAggregateFunction[QueryAggregateFunction["Median"] = 6] = "Median";
8171 QueryAggregateFunction[QueryAggregateFunction["StandardDeviation"] = 7] = "StandardDeviation";
8172 QueryAggregateFunction[QueryAggregateFunction["Variance"] = 8] = "Variance";
8173 })(data.QueryAggregateFunction || (data.QueryAggregateFunction = {}));
8174 var QueryAggregateFunction = data.QueryAggregateFunction;
8175 (function (QueryComparisonKind) {
8176 QueryComparisonKind[QueryComparisonKind["Equal"] = 0] = "Equal";
8177 QueryComparisonKind[QueryComparisonKind["GreaterThan"] = 1] = "GreaterThan";
8178 QueryComparisonKind[QueryComparisonKind["GreaterThanOrEqual"] = 2] = "GreaterThanOrEqual";
8179 QueryComparisonKind[QueryComparisonKind["LessThan"] = 3] = "LessThan";
8180 QueryComparisonKind[QueryComparisonKind["LessThanOrEqual"] = 4] = "LessThanOrEqual";
8181 })(data.QueryComparisonKind || (data.QueryComparisonKind = {}));
8182 var QueryComparisonKind = data.QueryComparisonKind;
8183 /** Defines semantic data types. */
8184 (function (SemanticType) {
8185 SemanticType[SemanticType["None"] = 0] = "None";
8186 SemanticType[SemanticType["Number"] = 1] = "Number";
8187 SemanticType[SemanticType["Integer"] = 3] = "Integer";
8188 SemanticType[SemanticType["DateTime"] = 4] = "DateTime";
8189 SemanticType[SemanticType["Time"] = 8] = "Time";
8190 SemanticType[SemanticType["Date"] = 20] = "Date";
8191 SemanticType[SemanticType["Month"] = 35] = "Month";
8192 SemanticType[SemanticType["Year"] = 67] = "Year";
8193 SemanticType[SemanticType["YearAndMonth"] = 128] = "YearAndMonth";
8194 SemanticType[SemanticType["MonthAndDay"] = 256] = "MonthAndDay";
8195 SemanticType[SemanticType["Decade"] = 515] = "Decade";
8196 SemanticType[SemanticType["YearAndWeek"] = 1024] = "YearAndWeek";
8197 SemanticType[SemanticType["String"] = 2048] = "String";
8198 SemanticType[SemanticType["Boolean"] = 4096] = "Boolean";
8199 SemanticType[SemanticType["Table"] = 8192] = "Table";
8200 SemanticType[SemanticType["Range"] = 16384] = "Range";
8201 })(data.SemanticType || (data.SemanticType = {}));
8202 var SemanticType = data.SemanticType;
8203 (function (FilterKind) {
8204 FilterKind[FilterKind["Default"] = 0] = "Default";
8205 FilterKind[FilterKind["Period"] = 1] = "Period";
8206 })(data.FilterKind || (data.FilterKind = {}));
8207 var FilterKind = data.FilterKind;
8208 })(data = powerbi.data || (powerbi.data = {}));
8209})(powerbi || (powerbi = {}));
8210/*
8211 * Power BI Visualizations
8212 *
8213 * Copyright (c) Microsoft Corporation
8214 * All rights reserved.
8215 * MIT License
8216 *
8217 * Permission is hereby granted, free of charge, to any person obtaining a copy
8218 * of this software and associated documentation files (the ""Software""), to deal
8219 * in the Software without restriction, including without limitation the rights
8220 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8221 * copies of the Software, and to permit persons to whom the Software is
8222 * furnished to do so, subject to the following conditions:
8223 *
8224 * The above copyright notice and this permission notice shall be included in
8225 * all copies or substantial portions of the Software.
8226 *
8227 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8228 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8229 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8230 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8231 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8232 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8233 * THE SOFTWARE.
8234 */
8235var powerbi;
8236(function (powerbi) {
8237 var data;
8238 (function (data) {
8239 var QueryProjectionCollection = (function () {
8240 function QueryProjectionCollection(items, activeProjectionRefs, showAll) {
8241 debug.assertValue(items, 'items');
8242 this.items = items;
8243 this._activeProjectionRefs = activeProjectionRefs;
8244 this._showAll = showAll;
8245 }
8246 /** Returns all projections in a mutable array. */
8247 QueryProjectionCollection.prototype.all = function () {
8248 return this.items;
8249 };
8250 Object.defineProperty(QueryProjectionCollection.prototype, "activeProjectionRefs", {
8251 get: function () {
8252 return this._activeProjectionRefs;
8253 },
8254 set: function (queryReferences) {
8255 if (!_.isEmpty(queryReferences)) {
8256 var queryRefs = this.items.map(function (val) { return val.queryRef; });
8257 for (var _i = 0, queryReferences_1 = queryReferences; _i < queryReferences_1.length; _i++) {
8258 var queryReference = queryReferences_1[_i];
8259 if (!_.contains(queryRefs, queryReference))
8260 return;
8261 }
8262 this._activeProjectionRefs = queryReferences;
8263 }
8264 },
8265 enumerable: true,
8266 configurable: true
8267 });
8268 Object.defineProperty(QueryProjectionCollection.prototype, "showAll", {
8269 get: function () {
8270 return this._showAll;
8271 },
8272 set: function (value) {
8273 this._showAll = value;
8274 },
8275 enumerable: true,
8276 configurable: true
8277 });
8278 QueryProjectionCollection.prototype.addActiveQueryReference = function (queryRef) {
8279 if (!this._activeProjectionRefs)
8280 this._activeProjectionRefs = [queryRef];
8281 else
8282 this._activeProjectionRefs.push(queryRef);
8283 };
8284 QueryProjectionCollection.prototype.getLastActiveQueryReference = function () {
8285 if (!_.isEmpty(this._activeProjectionRefs)) {
8286 return this._activeProjectionRefs[this._activeProjectionRefs.length - 1];
8287 }
8288 };
8289 /** Replaces the given oldQueryRef with newQueryRef in this QueryProjectionCollection. */
8290 QueryProjectionCollection.prototype.replaceQueryRef = function (oldQueryRef, newQueryRef) {
8291 debug.assertValue(oldQueryRef, 'oldQueryRef');
8292 debug.assertValue(newQueryRef, 'newQueryRef');
8293 debug.assert(oldQueryRef !== newQueryRef, 'oldQueryRef !== newQueryRef');
8294 debug.assert(_.isEmpty(this._activeProjectionRefs), 'replaceQueryRef(...) is not supported on the QueryProjectionCollection of a drillable role');
8295 // Note: the same queryRef can get projected multiple times
8296 for (var _i = 0, _a = this.items; _i < _a.length; _i++) {
8297 var item = _a[_i];
8298 if (item.queryRef === oldQueryRef) {
8299 item.queryRef = newQueryRef;
8300 }
8301 }
8302 };
8303 QueryProjectionCollection.prototype.clone = function () {
8304 return new QueryProjectionCollection(_.cloneDeep(this.items), _.clone(this._activeProjectionRefs), this._showAll);
8305 };
8306 return QueryProjectionCollection;
8307 }());
8308 data.QueryProjectionCollection = QueryProjectionCollection;
8309 var QueryProjectionsByRole;
8310 (function (QueryProjectionsByRole) {
8311 /** Clones the QueryProjectionsByRole. */
8312 function clone(roles) {
8313 if (!roles)
8314 return roles;
8315 var clonedRoles = {};
8316 for (var roleName in roles)
8317 clonedRoles[roleName] = roles[roleName].clone();
8318 return clonedRoles;
8319 }
8320 QueryProjectionsByRole.clone = clone;
8321 /** Returns the QueryProjectionCollection for that role. Even returns empty collections so that 'drillable' and 'activeProjection' fields are preserved. */
8322 function getRole(roles, name) {
8323 debug.assertAnyValue(roles, 'roles');
8324 debug.assertValue(name, 'name');
8325 if (!roles)
8326 return;
8327 return roles[name];
8328 }
8329 QueryProjectionsByRole.getRole = getRole;
8330 })(QueryProjectionsByRole = data.QueryProjectionsByRole || (data.QueryProjectionsByRole = {}));
8331 })(data = powerbi.data || (powerbi.data = {}));
8332})(powerbi || (powerbi = {}));
8333/*
8334 * Power BI Visualizations
8335 *
8336 * Copyright (c) Microsoft Corporation
8337 * All rights reserved.
8338 * MIT License
8339 *
8340 * Permission is hereby granted, free of charge, to any person obtaining a copy
8341 * of this software and associated documentation files (the ""Software""), to deal
8342 * in the Software without restriction, including without limitation the rights
8343 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8344 * copies of the Software, and to permit persons to whom the Software is
8345 * furnished to do so, subject to the following conditions:
8346 *
8347 * The above copyright notice and this permission notice shall be included in
8348 * all copies or substantial portions of the Software.
8349 *
8350 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8351 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8352 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8353 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8354 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8355 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8356 * THE SOFTWARE.
8357 */
8358var powerbi;
8359(function (powerbi) {
8360 /** The system used to determine display units used during formatting */
8361 (function (DisplayUnitSystemType) {
8362 /** Default display unit system, which saves space by using units such as K, M, bn with PowerView rules for when to pick a unit. Suitable for chart axes. */
8363 DisplayUnitSystemType[DisplayUnitSystemType["Default"] = 0] = "Default";
8364 /** A verbose display unit system that will only respect the formatting defined in the model. Suitable for explore mode single-value cards. */
8365 DisplayUnitSystemType[DisplayUnitSystemType["Verbose"] = 1] = "Verbose";
8366 /**
8367 * A display unit system that uses units such as K, M, bn if we have at least one of those units (e.g. 0.9M is not valid as it's less than 1 million).
8368 * Suitable for dashboard tile cards
8369 */
8370 DisplayUnitSystemType[DisplayUnitSystemType["WholeUnits"] = 2] = "WholeUnits";
8371 /**A display unit system that also contains Auto and None units for data labels*/
8372 DisplayUnitSystemType[DisplayUnitSystemType["DataLabels"] = 3] = "DataLabels";
8373 })(powerbi.DisplayUnitSystemType || (powerbi.DisplayUnitSystemType = {}));
8374 var DisplayUnitSystemType = powerbi.DisplayUnitSystemType;
8375})(powerbi || (powerbi = {}));
8376/*
8377 * Power BI Visualizations
8378 *
8379 * Copyright (c) Microsoft Corporation
8380 * All rights reserved.
8381 * MIT License
8382 *
8383 * Permission is hereby granted, free of charge, to any person obtaining a copy
8384 * of this software and associated documentation files (the ""Software""), to deal
8385 * in the Software without restriction, including without limitation the rights
8386 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8387 * copies of the Software, and to permit persons to whom the Software is
8388 * furnished to do so, subject to the following conditions:
8389 *
8390 * The above copyright notice and this permission notice shall be included in
8391 * all copies or substantial portions of the Software.
8392 *
8393 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8394 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8395 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8396 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8397 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8398 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8399 * THE SOFTWARE.
8400 */
8401var powerbi;
8402(function (powerbi) {
8403 /** Repreasents the sequence of the dates/times */
8404 var DateTimeSequence = (function () {
8405 // Constructors
8406 /** Creates new instance of the DateTimeSequence */
8407 function DateTimeSequence(unit) {
8408 this.unit = unit;
8409 this.sequence = [];
8410 this.min = new Date("9999-12-31T23:59:59.999");
8411 this.max = new Date("0001-01-01T00:00:00.000");
8412 }
8413 // Methods
8414 /**
8415 * Add a new Date to a sequence.
8416 * @param date - date to add
8417 */
8418 DateTimeSequence.prototype.add = function (date) {
8419 if (date < this.min) {
8420 this.min = date;
8421 }
8422 if (date > this.max) {
8423 this.max = date;
8424 }
8425 this.sequence.push(date);
8426 };
8427 // Methods
8428 /**
8429 * Extends the sequence to cover new date range
8430 * @param min - new min to be covered by sequence
8431 * @param max - new max to be covered by sequence
8432 */
8433 DateTimeSequence.prototype.extendToCover = function (min, max) {
8434 var x = this.min;
8435 while (min < x) {
8436 x = DateTimeSequence.addInterval(x, -this.interval, this.unit);
8437 this.sequence.splice(0, 0, x);
8438 }
8439 this.min = x;
8440 x = this.max;
8441 while (x < max) {
8442 x = DateTimeSequence.addInterval(x, this.interval, this.unit);
8443 this.sequence.push(x);
8444 }
8445 this.max = x;
8446 };
8447 /**
8448 * Move the sequence to cover new date range
8449 * @param min - new min to be covered by sequence
8450 * @param max - new max to be covered by sequence
8451 */
8452 DateTimeSequence.prototype.moveToCover = function (min, max) {
8453 var delta = DateTimeSequence.getDelta(min, max, this.unit);
8454 var count = Math.floor(delta / this.interval);
8455 this.min = DateTimeSequence.addInterval(this.min, count * this.interval, this.unit);
8456 this.sequence = [];
8457 this.sequence.push(this.min);
8458 this.max = this.min;
8459 while (this.max < max) {
8460 this.max = DateTimeSequence.addInterval(this.max, this.interval, this.unit);
8461 this.sequence.push(this.max);
8462 }
8463 };
8464 // Static
8465 /**
8466 * Calculate a new DateTimeSequence
8467 * @param dataMin - Date representing min of the data range
8468 * @param dataMax - Date representing max of the data range
8469 * @param expectedCount - expected number of intervals in the sequence
8470 * @param unit - of the intervals in the sequence
8471 */
8472 DateTimeSequence.calculate = function (dataMin, dataMax, expectedCount, unit) {
8473 if (!unit) {
8474 unit = DateTimeSequence.getIntervalUnit(dataMin, dataMax, expectedCount);
8475 }
8476 switch (unit) {
8477 case powerbi.DateTimeUnit.Year:
8478 return DateTimeSequence.calculateYears(dataMin, dataMax, expectedCount);
8479 case powerbi.DateTimeUnit.Month:
8480 return DateTimeSequence.calculateMonths(dataMin, dataMax, expectedCount);
8481 case powerbi.DateTimeUnit.Week:
8482 return DateTimeSequence.calculateWeeks(dataMin, dataMax, expectedCount);
8483 case powerbi.DateTimeUnit.Day:
8484 return DateTimeSequence.calculateDays(dataMin, dataMax, expectedCount);
8485 case powerbi.DateTimeUnit.Hour:
8486 return DateTimeSequence.calculateHours(dataMin, dataMax, expectedCount);
8487 case powerbi.DateTimeUnit.Minute:
8488 return DateTimeSequence.calculateMinutes(dataMin, dataMax, expectedCount);
8489 case powerbi.DateTimeUnit.Second:
8490 return DateTimeSequence.calculateSeconds(dataMin, dataMax, expectedCount);
8491 case powerbi.DateTimeUnit.Millisecond:
8492 return DateTimeSequence.calculateMilliseconds(dataMin, dataMax, expectedCount);
8493 default:
8494 debug.assertFail("Unsupported DateTimeUnit");
8495 }
8496 };
8497 DateTimeSequence.calculateYears = function (dataMin, dataMax, expectedCount) {
8498 debug.assertValue(dataMin, "dataMin");
8499 debug.assertValue(dataMax, "dataMax");
8500 debug.assert(!expectedCount || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "Expected count is out of range");
8501 // Calculate range and sequence
8502 var yearsRange = powerbi.NumericSequenceRange.calculateDataRange(dataMin.getFullYear(), dataMax.getFullYear(), false);
8503 // Calculate year sequence
8504 var sequence = powerbi.NumericSequence.calculate(powerbi.NumericSequenceRange.calculate(0, yearsRange.max - yearsRange.min), expectedCount, 0, null, null, [1, 2, 5]);
8505 var newMinYear = Math.floor(yearsRange.min / sequence.interval) * sequence.interval;
8506 var date = new Date(newMinYear, 0, 1);
8507 // Convert to date sequence
8508 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Year);
8509 return result;
8510 };
8511 DateTimeSequence.calculateMonths = function (dataMin, dataMax, expectedCount) {
8512 debug.assertValue(dataMin, "dataMin");
8513 debug.assertValue(dataMax, "dataMax");
8514 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8515 // Calculate range
8516 var minYear = dataMin.getFullYear();
8517 var maxYear = dataMax.getFullYear();
8518 var minMonth = dataMin.getMonth();
8519 var maxMonth = (maxYear - minYear) * 12 + dataMax.getMonth();
8520 var date = new Date(minYear, 0, 1);
8521 // Calculate month sequence
8522 var sequence = powerbi.NumericSequence.calculateUnits(minMonth, maxMonth, expectedCount, [1, 2, 3, 6, 12]);
8523 // Convert to date sequence
8524 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Month);
8525 return result;
8526 };
8527 DateTimeSequence.calculateWeeks = function (dataMin, dataMax, expectedCount) {
8528 debug.assertValue(dataMin, "dataMin");
8529 debug.assertValue(dataMax, "dataMax");
8530 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8531 var firstDayOfWeek = 0;
8532 var minDayOfWeek = dataMin.getDay();
8533 var dayOffset = (minDayOfWeek - firstDayOfWeek + 7) % 7;
8534 var minDay = dataMin.getDate() - dayOffset;
8535 // Calculate range
8536 var date = new Date(dataMin.getFullYear(), dataMin.getMonth(), minDay);
8537 var min = 0;
8538 var max = powerbi.Double.ceilWithPrecision(DateTimeSequence.getDelta(date, dataMax, powerbi.DateTimeUnit.Week));
8539 // Calculate week sequence
8540 var sequence = powerbi.NumericSequence.calculateUnits(min, max, expectedCount, [1, 2, 4, 8]);
8541 // Convert to date sequence
8542 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Week);
8543 return result;
8544 };
8545 DateTimeSequence.calculateDays = function (dataMin, dataMax, expectedCount) {
8546 debug.assertValue(dataMin, "dataMin");
8547 debug.assertValue(dataMax, "dataMax");
8548 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8549 // Calculate range
8550 var date = new Date(dataMin.getFullYear(), dataMin.getMonth(), dataMin.getDate());
8551 var min = 0;
8552 var max = powerbi.Double.ceilWithPrecision(DateTimeSequence.getDelta(dataMin, dataMax, powerbi.DateTimeUnit.Day));
8553 // Calculate day sequence
8554 var sequence = powerbi.NumericSequence.calculateUnits(min, max, expectedCount, [1, 2, 7, 14]);
8555 // Convert to date sequence
8556 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Day);
8557 return result;
8558 };
8559 DateTimeSequence.calculateHours = function (dataMin, dataMax, expectedCount) {
8560 debug.assertValue(dataMin, "dataMin");
8561 debug.assertValue(dataMax, "dataMax");
8562 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8563 // Calculate range
8564 var date = new Date(dataMin.getFullYear(), dataMin.getMonth(), dataMin.getDate());
8565 var min = powerbi.Double.floorWithPrecision(DateTimeSequence.getDelta(date, dataMin, powerbi.DateTimeUnit.Hour));
8566 var max = powerbi.Double.ceilWithPrecision(DateTimeSequence.getDelta(date, dataMax, powerbi.DateTimeUnit.Hour));
8567 // Calculate hour sequence
8568 var sequence = powerbi.NumericSequence.calculateUnits(min, max, expectedCount, [1, 2, 3, 6, 12, 24]);
8569 // Convert to date sequence
8570 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Hour);
8571 return result;
8572 };
8573 DateTimeSequence.calculateMinutes = function (dataMin, dataMax, expectedCount) {
8574 debug.assertValue(dataMin, "dataMin");
8575 debug.assertValue(dataMax, "dataMax");
8576 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8577 // Calculate range
8578 var date = new Date(dataMin.getFullYear(), dataMin.getMonth(), dataMin.getDate(), dataMin.getHours());
8579 var min = powerbi.Double.floorWithPrecision(DateTimeSequence.getDelta(date, dataMin, powerbi.DateTimeUnit.Minute));
8580 var max = powerbi.Double.ceilWithPrecision(DateTimeSequence.getDelta(date, dataMax, powerbi.DateTimeUnit.Minute));
8581 // Calculate minutes numeric sequence
8582 var sequence = powerbi.NumericSequence.calculateUnits(min, max, expectedCount, [1, 2, 5, 10, 15, 30, 60, 60 * 2, 60 * 3, 60 * 6, 60 * 12, 60 * 24]);
8583 // Convert to date sequence
8584 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Minute);
8585 return result;
8586 };
8587 DateTimeSequence.calculateSeconds = function (dataMin, dataMax, expectedCount) {
8588 debug.assertValue(dataMin, "dataMin");
8589 debug.assertValue(dataMax, "dataMax");
8590 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8591 // Calculate range
8592 var date = new Date(dataMin.getFullYear(), dataMin.getMonth(), dataMin.getDate(), dataMin.getHours(), dataMin.getMinutes());
8593 var min = powerbi.Double.floorWithPrecision(DateTimeSequence.getDelta(date, dataMin, powerbi.DateTimeUnit.Second));
8594 var max = powerbi.Double.ceilWithPrecision(DateTimeSequence.getDelta(date, dataMax, powerbi.DateTimeUnit.Second));
8595 // Calculate minutes numeric sequence
8596 var sequence = powerbi.NumericSequence.calculateUnits(min, max, expectedCount, [1, 2, 5, 10, 15, 30, 60, 60 * 2, 60 * 5, 60 * 10, 60 * 15, 60 * 30, 60 * 60]);
8597 // Convert to date sequence
8598 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Second);
8599 return result;
8600 };
8601 DateTimeSequence.calculateMilliseconds = function (dataMin, dataMax, expectedCount) {
8602 debug.assertValue(dataMin, "dataMin");
8603 debug.assertValue(dataMax, "dataMax");
8604 debug.assert(expectedCount === undefined || (expectedCount >= DateTimeSequence.MIN_COUNT && expectedCount <= DateTimeSequence.MAX_COUNT), "expected count is out of range");
8605 // Calculate range
8606 var date = new Date(dataMin.getFullYear(), dataMin.getMonth(), dataMin.getDate(), dataMin.getHours(), dataMin.getMinutes(), dataMin.getSeconds());
8607 var min = DateTimeSequence.getDelta(date, dataMin, powerbi.DateTimeUnit.Millisecond);
8608 var max = DateTimeSequence.getDelta(date, dataMax, powerbi.DateTimeUnit.Millisecond);
8609 // Calculate milliseconds numeric sequence
8610 var sequence = powerbi.NumericSequence.calculate(powerbi.NumericSequenceRange.calculate(min, max), expectedCount, 0);
8611 // Convert to date sequence
8612 var result = DateTimeSequence.fromNumericSequence(date, sequence, powerbi.DateTimeUnit.Millisecond);
8613 return result;
8614 };
8615 DateTimeSequence.addInterval = function (value, interval, unit) {
8616 interval = Math.round(interval);
8617 switch (unit) {
8618 case powerbi.DateTimeUnit.Year:
8619 return DateUtils.addYears(value, interval);
8620 case powerbi.DateTimeUnit.Month:
8621 return DateUtils.addMonths(value, interval);
8622 case powerbi.DateTimeUnit.Week:
8623 return DateUtils.addWeeks(value, interval);
8624 case powerbi.DateTimeUnit.Day:
8625 return DateUtils.addDays(value, interval);
8626 case powerbi.DateTimeUnit.Hour:
8627 return DateUtils.addHours(value, interval);
8628 case powerbi.DateTimeUnit.Minute:
8629 return DateUtils.addMinutes(value, interval);
8630 case powerbi.DateTimeUnit.Second:
8631 return DateUtils.addSeconds(value, interval);
8632 case powerbi.DateTimeUnit.Millisecond:
8633 return DateUtils.addMilliseconds(value, interval);
8634 }
8635 };
8636 DateTimeSequence.fromNumericSequence = function (date, sequence, unit) {
8637 var result = new DateTimeSequence(unit);
8638 for (var i = 0; i < sequence.sequence.length; i++) {
8639 var x = sequence.sequence[i];
8640 var d = DateTimeSequence.addInterval(date, x, unit);
8641 result.add(d);
8642 }
8643 result.interval = sequence.interval;
8644 result.intervalOffset = sequence.intervalOffset;
8645 return result;
8646 };
8647 DateTimeSequence.getDelta = function (min, max, unit) {
8648 var delta = 0;
8649 switch (unit) {
8650 case powerbi.DateTimeUnit.Year:
8651 delta = max.getFullYear() - min.getFullYear();
8652 break;
8653 case powerbi.DateTimeUnit.Month:
8654 delta = (max.getFullYear() - min.getFullYear()) * 12 + max.getMonth() - min.getMonth();
8655 break;
8656 case powerbi.DateTimeUnit.Week:
8657 delta = (max.getTime() - min.getTime()) / (7 * 24 * 3600000);
8658 break;
8659 case powerbi.DateTimeUnit.Day:
8660 delta = (max.getTime() - min.getTime()) / (24 * 3600000);
8661 break;
8662 case powerbi.DateTimeUnit.Hour:
8663 delta = (max.getTime() - min.getTime()) / 3600000;
8664 break;
8665 case powerbi.DateTimeUnit.Minute:
8666 delta = (max.getTime() - min.getTime()) / 60000;
8667 break;
8668 case powerbi.DateTimeUnit.Second:
8669 delta = (max.getTime() - min.getTime()) / 1000;
8670 break;
8671 case powerbi.DateTimeUnit.Millisecond:
8672 delta = max.getTime() - min.getTime();
8673 break;
8674 }
8675 return delta;
8676 };
8677 DateTimeSequence.getIntervalUnit = function (min, max, maxCount) {
8678 maxCount = Math.max(maxCount, 2);
8679 var totalDays = DateTimeSequence.getDelta(min, max, powerbi.DateTimeUnit.Day);
8680 if (totalDays > 356 && totalDays >= 30 * 6 * maxCount)
8681 return powerbi.DateTimeUnit.Year;
8682 if (totalDays > 60 && totalDays > 7 * maxCount)
8683 return powerbi.DateTimeUnit.Month;
8684 if (totalDays > 14 && totalDays > 2 * maxCount)
8685 return powerbi.DateTimeUnit.Week;
8686 var totalHours = DateTimeSequence.getDelta(min, max, powerbi.DateTimeUnit.Hour);
8687 if (totalDays > 2 && totalHours > 12 * maxCount)
8688 return powerbi.DateTimeUnit.Day;
8689 if (totalHours >= 24 && totalHours >= maxCount)
8690 return powerbi.DateTimeUnit.Hour;
8691 var totalMinutes = DateTimeSequence.getDelta(min, max, powerbi.DateTimeUnit.Minute);
8692 if (totalMinutes > 2 && totalMinutes >= maxCount)
8693 return powerbi.DateTimeUnit.Minute;
8694 var totalSeconds = DateTimeSequence.getDelta(min, max, powerbi.DateTimeUnit.Second);
8695 if (totalSeconds > 2 && totalSeconds >= 0.8 * maxCount)
8696 return powerbi.DateTimeUnit.Second;
8697 var totalMilliseconds = DateTimeSequence.getDelta(min, max, powerbi.DateTimeUnit.Millisecond);
8698 if (totalMilliseconds > 0)
8699 return powerbi.DateTimeUnit.Millisecond;
8700 // If the size of the range is 0 we need to guess the unit based on the date's non-zero values starting with milliseconds
8701 var date = min;
8702 if (date.getMilliseconds() !== 0)
8703 return powerbi.DateTimeUnit.Millisecond;
8704 if (date.getSeconds() !== 0)
8705 return powerbi.DateTimeUnit.Second;
8706 if (date.getMinutes() !== 0)
8707 return powerbi.DateTimeUnit.Minute;
8708 if (date.getHours() !== 0)
8709 return powerbi.DateTimeUnit.Hour;
8710 if (date.getDate() !== 1)
8711 return powerbi.DateTimeUnit.Day;
8712 if (date.getMonth() !== 0)
8713 return powerbi.DateTimeUnit.Month;
8714 return powerbi.DateTimeUnit.Year;
8715 };
8716 // Constants
8717 DateTimeSequence.MIN_COUNT = 1;
8718 DateTimeSequence.MAX_COUNT = 1000;
8719 return DateTimeSequence;
8720 }());
8721 powerbi.DateTimeSequence = DateTimeSequence;
8722 /** DateUtils module provides DateTimeSequence with set of additional date manipulation routines */
8723 var DateUtils;
8724 (function (DateUtils) {
8725 var MonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
8726 var MonthDaysLeap = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
8727 /**
8728 * Returns bool indicating weither the provided year is a leap year.
8729 * @param year - year value
8730 */
8731 function isLeap(year) {
8732 return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
8733 }
8734 /**
8735 * Returns number of days in the provided year/month.
8736 * @param year - year value
8737 * @param month - month value
8738 */
8739 function getMonthDays(year, month) {
8740 return isLeap(year) ? MonthDaysLeap[month] : MonthDays[month];
8741 }
8742 /**
8743 * Adds a specified number of years to the provided date.
8744 * @param date - date value
8745 * @param yearDelta - number of years to add
8746 */
8747 function addYears(date, yearDelta) {
8748 var year = date.getFullYear();
8749 var month = date.getMonth();
8750 var day = date.getDate();
8751 var isLeapDay = month === 2 && day === 29;
8752 var result = new Date(date.getTime());
8753 year = year + yearDelta;
8754 if (isLeapDay && !isLeap(year)) {
8755 day = 28;
8756 }
8757 result.setFullYear(year, month, day);
8758 return result;
8759 }
8760 DateUtils.addYears = addYears;
8761 /**
8762 * Adds a specified number of months to the provided date.
8763 * @param date - date value
8764 * @param monthDelta - number of months to add
8765 */
8766 function addMonths(date, monthDelta) {
8767 var year = date.getFullYear();
8768 var month = date.getMonth();
8769 var day = date.getDate();
8770 var result = new Date(date.getTime());
8771 year += (monthDelta - (monthDelta % 12)) / 12;
8772 month += monthDelta % 12;
8773 // VSTS 1325771: Certain column charts don't display any data
8774 // Wrap arround the month if is after december (value 11)
8775 if (month > 11) {
8776 month = month % 12;
8777 year++;
8778 }
8779 day = Math.min(day, getMonthDays(year, month));
8780 result.setFullYear(year, month, day);
8781 return result;
8782 }
8783 DateUtils.addMonths = addMonths;
8784 /**
8785 * Adds a specified number of weeks to the provided date.
8786 * @param date - date value
8787 * @param weeks - number of weeks to add
8788 */
8789 function addWeeks(date, weeks) {
8790 return addDays(date, weeks * 7);
8791 }
8792 DateUtils.addWeeks = addWeeks;
8793 /**
8794 * Adds a specified number of days to the provided date.
8795 * @param date - date value
8796 * @param days - number of days to add
8797 */
8798 function addDays(date, days) {
8799 var year = date.getFullYear();
8800 var month = date.getMonth();
8801 var day = date.getDate();
8802 var result = new Date(date.getTime());
8803 result.setFullYear(year, month, day + days);
8804 return result;
8805 }
8806 DateUtils.addDays = addDays;
8807 /**
8808 * Adds a specified number of hours to the provided date.
8809 * @param date - date value
8810 * @param hours - number of hours to add
8811 */
8812 function addHours(date, hours) {
8813 return new Date(date.getTime() + hours * 3600000);
8814 }
8815 DateUtils.addHours = addHours;
8816 /**
8817 * Adds a specified number of minutes to the provided date.
8818 * @param date - date value
8819 * @param minutes - number of minutes to add
8820 */
8821 function addMinutes(date, minutes) {
8822 return new Date(date.getTime() + minutes * 60000);
8823 }
8824 DateUtils.addMinutes = addMinutes;
8825 /**
8826 * Adds a specified number of seconds to the provided date.
8827 * @param date - date value
8828 * @param seconds - number of seconds to add
8829 */
8830 function addSeconds(date, seconds) {
8831 return new Date(date.getTime() + seconds * 1000);
8832 }
8833 DateUtils.addSeconds = addSeconds;
8834 /**
8835 * Adds a specified number of milliseconds to the provided date.
8836 * @param date - date value
8837 * @param milliseconds - number of milliseconds to add
8838 */
8839 function addMilliseconds(date, milliseconds) {
8840 return new Date(date.getTime() + milliseconds);
8841 }
8842 DateUtils.addMilliseconds = addMilliseconds;
8843 })(DateUtils = powerbi.DateUtils || (powerbi.DateUtils = {}));
8844})(powerbi || (powerbi = {}));
8845/*
8846 * Power BI Visualizations
8847 *
8848 * Copyright (c) Microsoft Corporation
8849 * All rights reserved.
8850 * MIT License
8851 *
8852 * Permission is hereby granted, free of charge, to any person obtaining a copy
8853 * of this software and associated documentation files (the ""Software""), to deal
8854 * in the Software without restriction, including without limitation the rights
8855 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8856 * copies of the Software, and to permit persons to whom the Software is
8857 * furnished to do so, subject to the following conditions:
8858 *
8859 * The above copyright notice and this permission notice shall be included in
8860 * all copies or substantial portions of the Software.
8861 *
8862 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8863 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8864 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8865 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8866 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8867 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8868 * THE SOFTWARE.
8869 */
8870var powerbi;
8871(function (powerbi) {
8872 // Constants
8873 var maxExponent = 24;
8874 var defaultScientificBigNumbersBoundary = 1E15;
8875 var scientificSmallNumbersBoundary = 1E-4;
8876 var PERCENTAGE_FORMAT = '%';
8877 var SCIENTIFIC_FORMAT = 'E+0';
8878 var DEFAULT_SCIENTIFIC_FORMAT = '0.##' + SCIENTIFIC_FORMAT;
8879 // Regular expressions
8880 /**
8881 * This regex looks for strings that match one of the following conditions:
8882 * - Optionally contain "0", "#", followed by a period, followed by at least one "0" or "#" (Ex. ###,000.###)
8883 * - Contains at least one of "0", "#", or "," (Ex. ###,000)
8884 * - Contain a "g" (indicates to use the general .NET numeric format string)
8885 * The entire string (start to end) must match, and the match is not case-sensitive.
8886 */
8887 var SUPPORTED_SCIENTIFIC_FORMATS = /^([0\#,]*\.[0\#]+|[0\#,]+|g)$/i;
8888 var DisplayUnit = (function () {
8889 function DisplayUnit() {
8890 }
8891 // Methods
8892 DisplayUnit.prototype.project = function (value) {
8893 if (this.value) {
8894 return powerbi.Double.removeDecimalNoise(value / this.value);
8895 }
8896 else {
8897 return value;
8898 }
8899 };
8900 DisplayUnit.prototype.reverseProject = function (value) {
8901 if (this.value) {
8902 return value * this.value;
8903 }
8904 else {
8905 return value;
8906 }
8907 };
8908 DisplayUnit.prototype.isApplicableTo = function (value) {
8909 value = Math.abs(value);
8910 var precision = powerbi.Double.getPrecision(value, 3);
8911 return powerbi.Double.greaterOrEqualWithPrecision(value, this.applicableRangeMin, precision) && powerbi.Double.lessWithPrecision(value, this.applicableRangeMax, precision);
8912 };
8913 DisplayUnit.prototype.isScaling = function () {
8914 return this.value > 1;
8915 };
8916 return DisplayUnit;
8917 }());
8918 powerbi.DisplayUnit = DisplayUnit;
8919 var DisplayUnitSystem = (function () {
8920 // Constructor
8921 function DisplayUnitSystem(units) {
8922 this.units = units ? units : [];
8923 }
8924 Object.defineProperty(DisplayUnitSystem.prototype, "title", {
8925 // Properties
8926 get: function () {
8927 return this.displayUnit ? this.displayUnit.title : undefined;
8928 },
8929 enumerable: true,
8930 configurable: true
8931 });
8932 // Methods
8933 DisplayUnitSystem.prototype.update = function (value) {
8934 if (value === undefined)
8935 return;
8936 this.unitBaseValue = value;
8937 this.displayUnit = this.findApplicableDisplayUnit(value);
8938 };
8939 DisplayUnitSystem.prototype.findApplicableDisplayUnit = function (value) {
8940 for (var _i = 0, _a = this.units; _i < _a.length; _i++) {
8941 var unit = _a[_i];
8942 if (unit.isApplicableTo(value))
8943 return unit;
8944 }
8945 return undefined;
8946 };
8947 DisplayUnitSystem.prototype.format = function (value, format, decimals, trailingZeros) {
8948 debug.assert(typeof (value) === "number", "value must be a number");
8949 if (this.isFormatSupported(format)) {
8950 decimals = this.getNumberOfDecimalsForFormatting(format, decimals);
8951 if (this.hasScientitifcFormat(format)) {
8952 return this.formatHelper(value, '', format, decimals, trailingZeros);
8953 }
8954 if (this.isScalingUnit() && this.shouldRespectScalingUnit(format)) {
8955 return this.formatHelper(this.displayUnit.project(value), this.displayUnit.labelFormat, format, decimals, trailingZeros);
8956 }
8957 if (decimals != null) {
8958 return this.formatHelper(value, '', format, decimals, trailingZeros);
8959 }
8960 }
8961 return powerbi.formattingService.formatValue(value, format);
8962 };
8963 DisplayUnitSystem.prototype.isFormatSupported = function (format) {
8964 return !DisplayUnitSystem.UNSUPPORTED_FORMATS.test(format);
8965 };
8966 DisplayUnitSystem.prototype.isPercentageFormat = function (format) {
8967 return format && format.indexOf(PERCENTAGE_FORMAT) >= 0;
8968 };
8969 DisplayUnitSystem.prototype.shouldRespectScalingUnit = function (format) {
8970 return !this.isPercentageFormat(format);
8971 };
8972 DisplayUnitSystem.prototype.getNumberOfDecimalsForFormatting = function (format, decimals) {
8973 return decimals;
8974 };
8975 DisplayUnitSystem.prototype.isScalingUnit = function () {
8976 return this.displayUnit && this.displayUnit.isScaling();
8977 };
8978 DisplayUnitSystem.prototype.formatHelper = function (value, nonScientificFormat, format, decimals, trailingZeros) {
8979 // If the format is "general" and we want to override the number of decimal places then use the default numeric format string.
8980 if ((format === 'g' || format === 'G') && decimals != null)
8981 format = powerbi.visuals.valueFormatter.DefaultNumericFormat;
8982 format = powerbi.NumberFormat.addDecimalsToFormat(format, decimals, trailingZeros);
8983 if (format && !powerbi.formattingService.isStandardNumberFormat(format))
8984 return powerbi.formattingService.formatNumberWithCustomOverride(value, format, nonScientificFormat);
8985 if (!format)
8986 format = 'G';
8987 if (!nonScientificFormat)
8988 nonScientificFormat = '{0}';
8989 var text = powerbi.formattingService.formatValue(value, format);
8990 return powerbi.formattingService.format(nonScientificFormat, [text]);
8991 };
8992 /** Formats a single value by choosing an appropriate base for the DisplayUnitSystem before formatting. */
8993 DisplayUnitSystem.prototype.formatSingleValue = function (value, format, decimals, trailingZeros) {
8994 // Change unit base to a value appropriate for this value
8995 this.update(this.shouldUseValuePrecision(value) ? powerbi.Double.getPrecision(value, 8) : value);
8996 return this.format(value, format, decimals, trailingZeros);
8997 };
8998 DisplayUnitSystem.prototype.shouldUseValuePrecision = function (value) {
8999 if (this.units.length === 0)
9000 return true;
9001 // Check if the value is big enough to have a valid unit by checking against the smallest unit (that it's value bigger than 1).
9002 var applicableRangeMin = 0;
9003 for (var i = 0; i < this.units.length; i++) {
9004 if (this.units[i].isScaling()) {
9005 applicableRangeMin = this.units[i].applicableRangeMin;
9006 break;
9007 }
9008 }
9009 return Math.abs(value) < applicableRangeMin;
9010 };
9011 DisplayUnitSystem.prototype.isScientific = function (value) {
9012 return value < -defaultScientificBigNumbersBoundary || value > defaultScientificBigNumbersBoundary ||
9013 (-scientificSmallNumbersBoundary < value && value < scientificSmallNumbersBoundary && value !== 0);
9014 };
9015 DisplayUnitSystem.prototype.hasScientitifcFormat = function (format) {
9016 return format && format.toUpperCase().indexOf("E") !== -1;
9017 };
9018 DisplayUnitSystem.prototype.supportsScientificFormat = function (format) {
9019 if (format)
9020 return SUPPORTED_SCIENTIFIC_FORMATS.test(format);
9021 return true;
9022 };
9023 DisplayUnitSystem.prototype.shouldFallbackToScientific = function (value, format) {
9024 return !this.hasScientitifcFormat(format)
9025 && this.supportsScientificFormat(format)
9026 && this.isScientific(value);
9027 };
9028 DisplayUnitSystem.prototype.getScientificFormat = function (data, format, decimals, trailingZeros) {
9029 // Use scientific format outside of the range
9030 if (this.isFormatSupported(format) && this.shouldFallbackToScientific(data, format)) {
9031 var numericFormat = powerbi.NumberFormat.getNumericFormat(data, format);
9032 if (decimals)
9033 numericFormat = powerbi.NumberFormat.addDecimalsToFormat(numericFormat ? numericFormat : '0', Math.abs(decimals), trailingZeros);
9034 if (numericFormat)
9035 return numericFormat + SCIENTIFIC_FORMAT;
9036 else
9037 return DEFAULT_SCIENTIFIC_FORMAT;
9038 }
9039 return format;
9040 };
9041 DisplayUnitSystem.UNSUPPORTED_FORMATS = /^(p\d*)|(.*\%)|(e\d*)$/i;
9042 return DisplayUnitSystem;
9043 }());
9044 powerbi.DisplayUnitSystem = DisplayUnitSystem;
9045 /** Provides a unit system that is defined by formatting in the model, and is suitable for visualizations shown in single number visuals in explore mode. */
9046 var NoDisplayUnitSystem = (function (_super) {
9047 __extends(NoDisplayUnitSystem, _super);
9048 // Constructor
9049 function NoDisplayUnitSystem() {
9050 _super.call(this, []);
9051 }
9052 return NoDisplayUnitSystem;
9053 }(DisplayUnitSystem));
9054 powerbi.NoDisplayUnitSystem = NoDisplayUnitSystem;
9055 /** Provides a unit system that creates a more concise format for displaying values. This is suitable for most of the cases where
9056 we are showing values (chart axes) and as such it is the default unit system. */
9057 var DefaultDisplayUnitSystem = (function (_super) {
9058 __extends(DefaultDisplayUnitSystem, _super);
9059 // Constructor
9060 function DefaultDisplayUnitSystem(unitLookup) {
9061 _super.call(this, DefaultDisplayUnitSystem.getUnits(unitLookup));
9062 }
9063 // Methods
9064 DefaultDisplayUnitSystem.prototype.format = function (data, format, decimals, trailingZeros) {
9065 format = this.getScientificFormat(data, format, decimals, trailingZeros);
9066 return _super.prototype.format.call(this, data, format, decimals, trailingZeros);
9067 };
9068 DefaultDisplayUnitSystem.reset = function () {
9069 DefaultDisplayUnitSystem.units = null;
9070 };
9071 DefaultDisplayUnitSystem.getUnits = function (unitLookup) {
9072 if (!DefaultDisplayUnitSystem.units) {
9073 DefaultDisplayUnitSystem.units = createDisplayUnits(unitLookup, function (value, previousUnitValue, min) {
9074 // When dealing with millions/billions/trillions we need to switch to millions earlier: for example instead of showing 100K 200K 300K we should show 0.1M 0.2M 0.3M etc
9075 if (value - previousUnitValue >= 1000) {
9076 return value / 10;
9077 }
9078 return min;
9079 });
9080 // Ensure last unit has max of infinity
9081 DefaultDisplayUnitSystem.units[DefaultDisplayUnitSystem.units.length - 1].applicableRangeMax = Infinity;
9082 }
9083 return DefaultDisplayUnitSystem.units;
9084 };
9085 return DefaultDisplayUnitSystem;
9086 }(DisplayUnitSystem));
9087 powerbi.DefaultDisplayUnitSystem = DefaultDisplayUnitSystem;
9088 /** Provides a unit system that creates a more concise format for displaying values, but only allows showing a unit if we have at least
9089 one of those units (e.g. 0.9M is not allowed since it's less than 1 million). This is suitable for cases such as dashboard tiles
9090 where we have restricted space but do not want to show partial units. */
9091 var WholeUnitsDisplayUnitSystem = (function (_super) {
9092 __extends(WholeUnitsDisplayUnitSystem, _super);
9093 // Constructor
9094 function WholeUnitsDisplayUnitSystem(unitLookup) {
9095 _super.call(this, WholeUnitsDisplayUnitSystem.getUnits(unitLookup));
9096 }
9097 WholeUnitsDisplayUnitSystem.reset = function () {
9098 WholeUnitsDisplayUnitSystem.units = null;
9099 };
9100 WholeUnitsDisplayUnitSystem.getUnits = function (unitLookup) {
9101 if (!WholeUnitsDisplayUnitSystem.units) {
9102 WholeUnitsDisplayUnitSystem.units = createDisplayUnits(unitLookup);
9103 // Ensure last unit has max of infinity
9104 WholeUnitsDisplayUnitSystem.units[WholeUnitsDisplayUnitSystem.units.length - 1].applicableRangeMax = Infinity;
9105 }
9106 return WholeUnitsDisplayUnitSystem.units;
9107 };
9108 WholeUnitsDisplayUnitSystem.prototype.format = function (data, format, decimals, trailingZeros) {
9109 format = this.getScientificFormat(data, format, decimals, trailingZeros);
9110 return _super.prototype.format.call(this, data, format, decimals, trailingZeros);
9111 };
9112 return WholeUnitsDisplayUnitSystem;
9113 }(DisplayUnitSystem));
9114 powerbi.WholeUnitsDisplayUnitSystem = WholeUnitsDisplayUnitSystem;
9115 var DataLabelsDisplayUnitSystem = (function (_super) {
9116 __extends(DataLabelsDisplayUnitSystem, _super);
9117 function DataLabelsDisplayUnitSystem(unitLookup) {
9118 _super.call(this, DataLabelsDisplayUnitSystem.getUnits(unitLookup));
9119 }
9120 DataLabelsDisplayUnitSystem.prototype.isFormatSupported = function (format) {
9121 return !DataLabelsDisplayUnitSystem.UNSUPPORTED_FORMATS.test(format);
9122 };
9123 DataLabelsDisplayUnitSystem.getUnits = function (unitLookup) {
9124 if (!DataLabelsDisplayUnitSystem.units) {
9125 var units = [];
9126 var adjustMinBasedOnPreviousUnit = function (value, previousUnitValue, min) {
9127 // Never returns true, we are always ignoring
9128 // We do not early switch (e.g. 100K instead of 0.1M)
9129 // Intended? If so, remove this function, otherwise, remove if statement
9130 if (value === -1)
9131 if (value - previousUnitValue >= 1000) {
9132 return value / 10;
9133 }
9134 return min;
9135 };
9136 // Add Auto & None
9137 var names = unitLookup(-1);
9138 addUnitIfNonEmpty(units, DataLabelsDisplayUnitSystem.AUTO_DISPLAYUNIT_VALUE, names.title, names.format, adjustMinBasedOnPreviousUnit);
9139 names = unitLookup(0);
9140 addUnitIfNonEmpty(units, DataLabelsDisplayUnitSystem.NONE_DISPLAYUNIT_VALUE, names.title, names.format, adjustMinBasedOnPreviousUnit);
9141 // Add normal units
9142 DataLabelsDisplayUnitSystem.units = units.concat(createDisplayUnits(unitLookup, adjustMinBasedOnPreviousUnit));
9143 // Ensure last unit has max of infinity
9144 DataLabelsDisplayUnitSystem.units[DataLabelsDisplayUnitSystem.units.length - 1].applicableRangeMax = Infinity;
9145 }
9146 return DataLabelsDisplayUnitSystem.units;
9147 };
9148 DataLabelsDisplayUnitSystem.prototype.format = function (data, format, decimals, trailingZeros) {
9149 format = this.getScientificFormat(data, format, decimals, trailingZeros);
9150 return _super.prototype.format.call(this, data, format, decimals, trailingZeros);
9151 };
9152 // Constants
9153 DataLabelsDisplayUnitSystem.AUTO_DISPLAYUNIT_VALUE = 0;
9154 DataLabelsDisplayUnitSystem.NONE_DISPLAYUNIT_VALUE = 1;
9155 DataLabelsDisplayUnitSystem.UNSUPPORTED_FORMATS = /^(e\d*)$/i;
9156 return DataLabelsDisplayUnitSystem;
9157 }(DisplayUnitSystem));
9158 powerbi.DataLabelsDisplayUnitSystem = DataLabelsDisplayUnitSystem;
9159 function createDisplayUnits(unitLookup, adjustMinBasedOnPreviousUnit) {
9160 var units = [];
9161 for (var i = 3; i < maxExponent; i++) {
9162 var names = unitLookup(i);
9163 if (names)
9164 addUnitIfNonEmpty(units, powerbi.Double.pow10(i), names.title, names.format, adjustMinBasedOnPreviousUnit);
9165 }
9166 return units;
9167 }
9168 function addUnitIfNonEmpty(units, value, title, labelFormat, adjustMinBasedOnPreviousUnit) {
9169 if (title || labelFormat) {
9170 var min = value;
9171 if (units.length > 0) {
9172 var previousUnit = units[units.length - 1];
9173 if (adjustMinBasedOnPreviousUnit)
9174 min = adjustMinBasedOnPreviousUnit(value, previousUnit.value, min);
9175 previousUnit.applicableRangeMax = min;
9176 }
9177 var unit = new DisplayUnit();
9178 unit.value = value;
9179 unit.applicableRangeMin = min;
9180 unit.applicableRangeMax = min * 1000;
9181 unit.title = title;
9182 unit.labelFormat = labelFormat;
9183 units.push(unit);
9184 }
9185 }
9186})(powerbi || (powerbi = {}));
9187/*
9188 * Power BI Visualizations
9189 *
9190 * Copyright (c) Microsoft Corporation
9191 * All rights reserved.
9192 * MIT License
9193 *
9194 * Permission is hereby granted, free of charge, to any person obtaining a copy
9195 * of this software and associated documentation files (the ""Software""), to deal
9196 * in the Software without restriction, including without limitation the rights
9197 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9198 * copies of the Software, and to permit persons to whom the Software is
9199 * furnished to do so, subject to the following conditions:
9200 *
9201 * The above copyright notice and this permission notice shall be included in
9202 * all copies or substantial portions of the Software.
9203 *
9204 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9205 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9206 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9207 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9208 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9209 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9210 * THE SOFTWARE.
9211 */
9212var powerbi;
9213(function (powerbi) {
9214 var NumericSequence = (function () {
9215 function NumericSequence() {
9216 }
9217 NumericSequence.calculate = function (range, expectedCount, maxAllowedMargin, minPower, useZeroRefPoint, steps) {
9218 debug.assertValue(range, "range");
9219 debug.assert(expectedCount === undefined || (expectedCount >= NumericSequence.MIN_COUNT && expectedCount <= NumericSequence.MAX_COUNT), "expectedCount");
9220 debug.assert(minPower === undefined || (minPower >= powerbi.Double.MIN_EXP && minPower <= powerbi.Double.MAX_EXP), "minPower");
9221 debug.assert(maxAllowedMargin === undefined || (maxAllowedMargin >= 0), "maxAllowedMargin");
9222 var result = new NumericSequence();
9223 if (expectedCount === undefined)
9224 expectedCount = 10;
9225 else
9226 expectedCount = powerbi.Double.ensureInRange(expectedCount, NumericSequence.MIN_COUNT, NumericSequence.MAX_COUNT);
9227 if (minPower === undefined)
9228 minPower = powerbi.Double.MIN_EXP;
9229 if (useZeroRefPoint === undefined)
9230 useZeroRefPoint = false;
9231 if (maxAllowedMargin === undefined)
9232 maxAllowedMargin = 1;
9233 if (steps === undefined)
9234 steps = [1, 2, 5];
9235 // Handle single stop case
9236 if (range.forcedSingleStop) {
9237 result.interval = range.getSize();
9238 result.intervalOffset = result.interval - (range.forcedSingleStop - range.min);
9239 result.min = range.min;
9240 result.max = range.max;
9241 result.sequence = [range.forcedSingleStop];
9242 return result;
9243 }
9244 var interval = 0;
9245 var min = 0;
9246 var max = 9;
9247 var canExtendMin = maxAllowedMargin > 0 && !range.hasFixedMin;
9248 var canExtendMax = maxAllowedMargin > 0 && !range.hasFixedMax;
9249 var size = range.getSize();
9250 var exp = powerbi.Double.log10(size);
9251 // Account for Exp of steps
9252 var stepExp = powerbi.Double.log10(steps[0]);
9253 exp = exp - stepExp;
9254 // Account for MaxCount
9255 var expectedCountExp = powerbi.Double.log10(expectedCount);
9256 exp = exp - expectedCountExp;
9257 // Account for MinPower
9258 exp = Math.max(exp, minPower - stepExp + 1);
9259 var count = undefined;
9260 // Create array of "good looking" numbers
9261 if (interval !== 0) {
9262 // If explicit interval is defined - use it instead of the steps array.
9263 var power = powerbi.Double.pow10(exp);
9264 var roundMin = powerbi.Double.floorToPrecision(range.min, power);
9265 var roundMax = powerbi.Double.ceilToPrecision(range.max, power);
9266 var roundRange = powerbi.NumericSequenceRange.calculateFixedRange(roundMin, roundMax);
9267 roundRange.shrinkByStep(range, interval);
9268 min = roundRange.min;
9269 max = roundRange.max;
9270 count = Math.floor(roundRange.getSize() / interval);
9271 }
9272 else {
9273 // No interval defined -> find optimal interval
9274 var dexp = void 0;
9275 for (dexp = 0; dexp < 3; dexp++) {
9276 var e = exp + dexp;
9277 var power = powerbi.Double.pow10(e);
9278 var roundMin = powerbi.Double.floorToPrecision(range.min, power);
9279 var roundMax = powerbi.Double.ceilToPrecision(range.max, power);
9280 // Go throught the steps array looking for the smallest step that produces the right interval count.
9281 var stepsCount = steps.length;
9282 var stepPower = powerbi.Double.pow10(e - 1);
9283 for (var i = 0; i < stepsCount; i++) {
9284 var step = steps[i] * stepPower;
9285 var roundRange = powerbi.NumericSequenceRange.calculateFixedRange(roundMin, roundMax, useZeroRefPoint);
9286 roundRange.shrinkByStep(range, step);
9287 // If the range is based on Data we might need to extend it to provide nice data margins.
9288 if (canExtendMin && range.min === roundRange.min && maxAllowedMargin >= 1)
9289 roundRange.min -= step;
9290 if (canExtendMax && range.max === roundRange.max && maxAllowedMargin >= 1)
9291 roundRange.max += step;
9292 // Count the intervals
9293 count = powerbi.Double.ceilWithPrecision(roundRange.getSize() / step);
9294 if (count <= expectedCount || (dexp === 2 && i === stepsCount - 1) || (expectedCount === 1 && count === 2 && (step > range.getSize() || (range.min < 0 && range.max > 0 && step * 2 >= range.getSize())))) {
9295 interval = step;
9296 min = roundRange.min;
9297 max = roundRange.max;
9298 break;
9299 }
9300 }
9301 // Increase the scale power until the interval is found
9302 if (interval !== 0)
9303 break;
9304 }
9305 }
9306 // Avoid extreme count cases (>1000 ticks)
9307 if (count > expectedCount * 32 || count > NumericSequence.MAX_COUNT) {
9308 count = Math.min(expectedCount * 32, NumericSequence.MAX_COUNT);
9309 interval = (max - min) / count;
9310 }
9311 result.min = min;
9312 result.max = max;
9313 result.interval = interval;
9314 result.intervalOffset = min - range.min;
9315 result.maxAllowedMargin = maxAllowedMargin;
9316 result.canExtendMin = canExtendMin;
9317 result.canExtendMax = canExtendMax;
9318 // Fill in the Sequence
9319 var precision = powerbi.Double.getPrecision(interval, 0);
9320 result.precision = precision;
9321 var sequence = [];
9322 var x = powerbi.Double.roundToPrecision(min, precision);
9323 sequence.push(x);
9324 for (var i = 0; i < count; i++) {
9325 x = powerbi.Double.roundToPrecision(x + interval, precision);
9326 sequence.push(x);
9327 }
9328 result.sequence = sequence;
9329 result.trimMinMax(range.min, range.max);
9330 return result;
9331 };
9332 /**
9333 * Calculates the sequence of int numbers which are mapped to the multiples of the units grid.
9334 * @min - The minimum of the range.
9335 * @max - The maximum of the range.
9336 * @maxCount - The max count of intervals.
9337 * @steps - array of intervals.
9338 */
9339 NumericSequence.calculateUnits = function (min, max, maxCount, steps) {
9340 // Initialization actions
9341 maxCount = powerbi.Double.ensureInRange(maxCount, NumericSequence.MIN_COUNT, NumericSequence.MAX_COUNT);
9342 if (min === max) {
9343 max = min + 1;
9344 }
9345 var stepCount = 0;
9346 var step = 0;
9347 // Calculate step
9348 for (var i = 0; i < steps.length; i++) {
9349 step = steps[i];
9350 var maxStepCount = powerbi.Double.ceilWithPrecision(max / step);
9351 var minStepCount = powerbi.Double.floorWithPrecision(min / step);
9352 stepCount = maxStepCount - minStepCount;
9353 if (stepCount <= maxCount) {
9354 break;
9355 }
9356 }
9357 // Calculate the offset
9358 var offset = -min;
9359 offset = offset % step;
9360 // Create sequence
9361 var result = new NumericSequence();
9362 result.sequence = [];
9363 for (var x = min + offset;; x += step) {
9364 result.sequence.push(x);
9365 if (x >= max)
9366 break;
9367 }
9368 result.interval = step;
9369 result.intervalOffset = offset;
9370 result.min = result.sequence[0];
9371 result.max = result.sequence[result.sequence.length - 1];
9372 return result;
9373 };
9374 NumericSequence.prototype.trimMinMax = function (min, max) {
9375 var minMargin = (min - this.min) / this.interval;
9376 var maxMargin = (this.max - max) / this.interval;
9377 var marginPrecision = 0.001;
9378 if (!this.canExtendMin || (minMargin > this.maxAllowedMargin && minMargin > marginPrecision)) {
9379 this.min = min;
9380 }
9381 if (!this.canExtendMax || (maxMargin > this.maxAllowedMargin && maxMargin > marginPrecision)) {
9382 this.max = max;
9383 }
9384 };
9385 NumericSequence.MIN_COUNT = 1;
9386 NumericSequence.MAX_COUNT = 1000;
9387 return NumericSequence;
9388 }());
9389 powerbi.NumericSequence = NumericSequence;
9390})(powerbi || (powerbi = {}));
9391/*
9392 * Power BI Visualizations
9393 *
9394 * Copyright (c) Microsoft Corporation
9395 * All rights reserved.
9396 * MIT License
9397 *
9398 * Permission is hereby granted, free of charge, to any person obtaining a copy
9399 * of this software and associated documentation files (the ""Software""), to deal
9400 * in the Software without restriction, including without limitation the rights
9401 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9402 * copies of the Software, and to permit persons to whom the Software is
9403 * furnished to do so, subject to the following conditions:
9404 *
9405 * The above copyright notice and this permission notice shall be included in
9406 * all copies or substantial portions of the Software.
9407 *
9408 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9409 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9410 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9411 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9412 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9413 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9414 * THE SOFTWARE.
9415 */
9416var powerbi;
9417(function (powerbi) {
9418 var NumericSequenceRange = (function () {
9419 function NumericSequenceRange() {
9420 }
9421 NumericSequenceRange.prototype._ensureIncludeZero = function () {
9422 if (this.includeZero) {
9423 // fixed min and max has higher priority than includeZero
9424 if (this.min > 0 && !this.hasFixedMin) {
9425 this.min = 0;
9426 }
9427 if (this.max < 0 && !this.hasFixedMax) {
9428 this.max = 0;
9429 }
9430 }
9431 };
9432 NumericSequenceRange.prototype._ensureNotEmpty = function () {
9433 if (this.min === this.max) {
9434 if (!this.min) {
9435 this.min = 0;
9436 this.max = NumericSequenceRange.DEFAULT_MAX;
9437 this.hasFixedMin = true;
9438 this.hasFixedMax = true;
9439 }
9440 else {
9441 // We are dealing with a single data value (includeZero is not set)
9442 // In order to fix the range we need to extend it in both directions by half of the interval.
9443 // Interval is calculated based on the number:
9444 // 1. Integers below 10,000 are extended by 0.5: so the [2006-2006] empty range is extended to [2005.5-2006.5] range and the ForsedSingleStop=2006
9445 // 2. Other numbers are extended by half of their power: [700,001-700,001] => [650,001-750,001] and the ForsedSingleStop=null as we want the intervals to be calculated to cover the range.
9446 var value = this.min;
9447 var exp = powerbi.Double.log10(Math.abs(value));
9448 var step = void 0;
9449 if (exp >= 0 && exp < 4) {
9450 step = 0.5;
9451 this.forcedSingleStop = value;
9452 }
9453 else {
9454 step = powerbi.Double.pow10(exp) / 2;
9455 this.forcedSingleStop = null;
9456 }
9457 this.min = value - step;
9458 this.max = value + step;
9459 }
9460 }
9461 };
9462 NumericSequenceRange.prototype._ensureDirection = function () {
9463 if (this.min > this.max) {
9464 var temp = this.min;
9465 this.min = this.max;
9466 this.max = temp;
9467 }
9468 };
9469 NumericSequenceRange.prototype.getSize = function () {
9470 return this.max - this.min;
9471 };
9472 NumericSequenceRange.prototype.shrinkByStep = function (range, step) {
9473 debug.assertValue(range, "range");
9474 debug.assert(step > 0, "step");
9475 var oldCount = this.min / step;
9476 var newCount = range.min / step;
9477 var deltaCount = Math.floor(newCount - oldCount);
9478 this.min += deltaCount * step;
9479 oldCount = this.max / step;
9480 newCount = range.max / step;
9481 deltaCount = Math.ceil(newCount - oldCount);
9482 this.max += deltaCount * step;
9483 };
9484 NumericSequenceRange.calculate = function (dataMin, dataMax, fixedMin, fixedMax, includeZero) {
9485 debug.assert(dataMin <= dataMax, "dataMin should be less or equal to dataMax.");
9486 debug.assert(!fixedMin || !fixedMax || fixedMin <= fixedMax, "fixedMin should be less or equal to fixedMax.");
9487 var result = new NumericSequenceRange();
9488 result.includeZero = includeZero ? true : false;
9489 result.hasDataRange = ValueUtil.hasValue(dataMin) && ValueUtil.hasValue(dataMax);
9490 result.hasFixedMin = ValueUtil.hasValue(fixedMin);
9491 result.hasFixedMax = ValueUtil.hasValue(fixedMax);
9492 dataMin = powerbi.Double.ensureInRange(dataMin, NumericSequenceRange.MIN_SUPPORTED_DOUBLE, NumericSequenceRange.MAX_SUPPORTED_DOUBLE);
9493 dataMax = powerbi.Double.ensureInRange(dataMax, NumericSequenceRange.MIN_SUPPORTED_DOUBLE, NumericSequenceRange.MAX_SUPPORTED_DOUBLE);
9494 // Calculate the range using the min, max, dataRange
9495 if (result.hasFixedMin && result.hasFixedMax) {
9496 result.min = fixedMin;
9497 result.max = fixedMax;
9498 }
9499 else if (result.hasFixedMin) {
9500 result.min = fixedMin;
9501 result.max = dataMax > fixedMin ? dataMax : fixedMin;
9502 }
9503 else if (result.hasFixedMax) {
9504 result.min = dataMin < fixedMax ? dataMin : fixedMax;
9505 result.max = fixedMax;
9506 }
9507 else if (result.hasDataRange) {
9508 result.min = dataMin;
9509 result.max = dataMax;
9510 }
9511 else {
9512 result.min = 0;
9513 result.max = 0;
9514 }
9515 result._ensureIncludeZero();
9516 result._ensureNotEmpty();
9517 result._ensureDirection();
9518 if (result.min === 0) {
9519 result.hasFixedMin = true; // If the range starts from zero we should prevent extending the intervals into the negative range
9520 }
9521 else if (result.max === 0) {
9522 result.hasFixedMax = true; // If the range ends at zero we should prevent extending the intervals into the positive range
9523 }
9524 return result;
9525 };
9526 NumericSequenceRange.calculateDataRange = function (dataMin, dataMax, includeZero) {
9527 if (!ValueUtil.hasValue(dataMin) || !ValueUtil.hasValue(dataMax)) {
9528 return NumericSequenceRange.calculateFixedRange(0, NumericSequenceRange.DEFAULT_MAX);
9529 }
9530 else {
9531 return NumericSequenceRange.calculate(dataMin, dataMax, null, null, includeZero);
9532 }
9533 };
9534 NumericSequenceRange.calculateFixedRange = function (fixedMin, fixedMax, includeZero) {
9535 debug.assertValue(fixedMin, "fixedMin");
9536 debug.assertValue(fixedMax, "fixedMax");
9537 var result = new NumericSequenceRange();
9538 result.hasDataRange = false;
9539 result.includeZero = includeZero;
9540 result.min = fixedMin;
9541 result.max = fixedMax;
9542 result._ensureIncludeZero();
9543 result._ensureNotEmpty();
9544 result._ensureDirection();
9545 result.hasFixedMin = true;
9546 result.hasFixedMax = true;
9547 return result;
9548 };
9549 NumericSequenceRange.DEFAULT_MAX = 10;
9550 NumericSequenceRange.MIN_SUPPORTED_DOUBLE = -1E307;
9551 NumericSequenceRange.MAX_SUPPORTED_DOUBLE = 1E307;
9552 return NumericSequenceRange;
9553 }());
9554 powerbi.NumericSequenceRange = NumericSequenceRange;
9555 /** Note: Exported for testability */
9556 var ValueUtil;
9557 (function (ValueUtil) {
9558 function hasValue(value) {
9559 return value !== undefined && value !== null;
9560 }
9561 ValueUtil.hasValue = hasValue;
9562 })(ValueUtil = powerbi.ValueUtil || (powerbi.ValueUtil = {}));
9563})(powerbi || (powerbi = {}));
9564/*
9565 * Power BI Visualizations
9566 *
9567 * Copyright (c) Microsoft Corporation
9568 * All rights reserved.
9569 * MIT License
9570 *
9571 * Permission is hereby granted, free of charge, to any person obtaining a copy
9572 * of this software and associated documentation files (the ""Software""), to deal
9573 * in the Software without restriction, including without limitation the rights
9574 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9575 * copies of the Software, and to permit persons to whom the Software is
9576 * furnished to do so, subject to the following conditions:
9577 *
9578 * The above copyright notice and this permission notice shall be included in
9579 * all copies or substantial portions of the Software.
9580 *
9581 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9582 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9583 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9584 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9585 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9586 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9587 * THE SOFTWARE.
9588 */
9589var powerbi;
9590(function (powerbi) {
9591 var visuals;
9592 (function (visuals) {
9593 var valueFormatter;
9594 (function (valueFormatter) {
9595 var StringExtensions = jsCommon.StringExtensions;
9596 var BeautifiedFormat = {
9597 '0.00 %;-0.00 %;0.00 %': 'Percentage',
9598 '0.0 %;-0.0 %;0.0 %': 'Percentage1',
9599 };
9600 valueFormatter.DefaultIntegerFormat = 'g';
9601 valueFormatter.DefaultNumericFormat = '#,0.00';
9602 valueFormatter.DefaultDateFormat = 'd';
9603 var defaultLocalizedStrings = {
9604 'NullValue': '(Blank)',
9605 'BooleanTrue': 'True',
9606 'BooleanFalse': 'False',
9607 'NaNValue': 'NaN',
9608 'InfinityValue': '+Infinity',
9609 'NegativeInfinityValue': '-Infinity',
9610 'RestatementComma': '{0}, {1}',
9611 'RestatementCompoundAnd': '{0} and {1}',
9612 'RestatementCompoundOr': '{0} or {1}',
9613 'DisplayUnitSystem_EAuto_Title': 'Auto',
9614 'DisplayUnitSystem_E0_Title': 'None',
9615 'DisplayUnitSystem_E3_LabelFormat': '{0}K',
9616 'DisplayUnitSystem_E3_Title': 'Thousands',
9617 'DisplayUnitSystem_E6_LabelFormat': '{0}M',
9618 'DisplayUnitSystem_E6_Title': 'Millions',
9619 'DisplayUnitSystem_E9_LabelFormat': '{0}bn',
9620 'DisplayUnitSystem_E9_Title': 'Billions',
9621 'DisplayUnitSystem_E12_LabelFormat': '{0}T',
9622 'DisplayUnitSystem_E12_Title': 'Trillions',
9623 'Percentage': '#,0.##%',
9624 'Percentage1': '#,0.#%',
9625 'TableTotalLabel': 'Total',
9626 'Tooltip_HighlightedValueDisplayName': 'Highlighted',
9627 'Funnel_PercentOfFirst': 'Percent of first',
9628 'Funnel_PercentOfPrevious': 'Percent of previous',
9629 'Funnel_PercentOfFirst_Highlight': 'Percent of first (highlighted)',
9630 'Funnel_PercentOfPrevious_Highlight': 'Percent of previous (highlighted)',
9631 // Geotagging strings
9632 'GeotaggingString_Continent': 'continent',
9633 'GeotaggingString_Continents': 'continents',
9634 'GeotaggingString_Country': 'country',
9635 'GeotaggingString_Countries': 'countries',
9636 'GeotaggingString_State': 'state',
9637 'GeotaggingString_States': 'states',
9638 'GeotaggingString_City': 'city',
9639 'GeotaggingString_Cities': 'cities',
9640 'GeotaggingString_Town': 'town',
9641 'GeotaggingString_Towns': 'towns',
9642 'GeotaggingString_Province': 'province',
9643 'GeotaggingString_Provinces': 'provinces',
9644 'GeotaggingString_County': 'county',
9645 'GeotaggingString_Counties': 'counties',
9646 'GeotaggingString_Village': 'village',
9647 'GeotaggingString_Villages': 'villages',
9648 'GeotaggingString_Post': 'post',
9649 'GeotaggingString_Zip': 'zip',
9650 'GeotaggingString_Code': 'code',
9651 'GeotaggingString_Place': 'place',
9652 'GeotaggingString_Places': 'places',
9653 'GeotaggingString_Address': 'address',
9654 'GeotaggingString_Addresses': 'addresses',
9655 'GeotaggingString_Street': 'street',
9656 'GeotaggingString_Streets': 'streets',
9657 'GeotaggingString_Longitude': 'longitude',
9658 'GeotaggingString_Longitude_Short': 'lon',
9659 'GeotaggingString_Latitude': 'latitude',
9660 'GeotaggingString_Latitude_Short': 'lat',
9661 'GeotaggingString_PostalCode': 'postal code',
9662 'GeotaggingString_PostalCodes': 'postal codes',
9663 'GeotaggingString_ZipCode': 'zip code',
9664 'GeotaggingString_ZipCodes': 'zip codes',
9665 'GeotaggingString_Territory': 'territory',
9666 'GeotaggingString_Territories': 'territories',
9667 };
9668 function beautify(format) {
9669 var key = BeautifiedFormat[format];
9670 if (key)
9671 return defaultLocalizedStrings[key] || format;
9672 return format;
9673 }
9674 function describeUnit(exponent) {
9675 var exponentLookup = (exponent === -1) ? 'Auto' : exponent.toString();
9676 var title = defaultLocalizedStrings["DisplayUnitSystem_E" + exponentLookup + "_Title"];
9677 var format = (exponent <= 0) ? '{0}' : defaultLocalizedStrings["DisplayUnitSystem_E" + exponentLookup + "_LabelFormat"];
9678 if (title || format)
9679 return { title: title, format: format };
9680 }
9681 function getLocalizedString(stringId) {
9682 return defaultLocalizedStrings[stringId];
9683 }
9684 valueFormatter.getLocalizedString = getLocalizedString;
9685 // NOTE: Define default locale options, but these can be overriden by setLocaleOptions.
9686 var locale = {
9687 null: defaultLocalizedStrings['NullValue'],
9688 true: defaultLocalizedStrings['BooleanTrue'],
9689 false: defaultLocalizedStrings['BooleanFalse'],
9690 NaN: defaultLocalizedStrings['NaNValue'],
9691 infinity: defaultLocalizedStrings['InfinityValue'],
9692 negativeInfinity: defaultLocalizedStrings['NegativeInfinityValue'],
9693 beautify: function (format) { return beautify(format); },
9694 describe: function (exponent) { return describeUnit(exponent); },
9695 restatementComma: defaultLocalizedStrings['RestatementComma'],
9696 restatementCompoundAnd: defaultLocalizedStrings['RestatementCompoundAnd'],
9697 restatementCompoundOr: defaultLocalizedStrings['RestatementCompoundOr'],
9698 };
9699 var MaxScaledDecimalPlaces = 2;
9700 var MaxValueForDisplayUnitRounding = 1000;
9701 var MinIntegerValueForDisplayUnits = 10000;
9702 var MinPrecisionForDisplayUnits = 2;
9703 var DateTimeMetadataColumn = {
9704 displayName: '',
9705 type: powerbi.ValueType.fromPrimitiveTypeAndCategory(powerbi.PrimitiveType.DateTime),
9706 };
9707 function getFormatMetadata(format) {
9708 return powerbi.NumberFormat.getCustomFormatMetadata(format);
9709 }
9710 valueFormatter.getFormatMetadata = getFormatMetadata;
9711 function setLocaleOptions(options) {
9712 debug.assertValue(options, 'options');
9713 locale = options;
9714 powerbi.DefaultDisplayUnitSystem.reset();
9715 powerbi.WholeUnitsDisplayUnitSystem.reset();
9716 }
9717 valueFormatter.setLocaleOptions = setLocaleOptions;
9718 function createDefaultFormatter(formatString, allowFormatBeautification) {
9719 if (allowFormatBeautification === void 0) { allowFormatBeautification = false; }
9720 var formatBeaut = allowFormatBeautification ? locale.beautify(formatString) : formatString;
9721 return {
9722 format: function (value) {
9723 if (value == null)
9724 return locale.null;
9725 return formatCore(value, formatBeaut);
9726 }
9727 };
9728 }
9729 valueFormatter.createDefaultFormatter = createDefaultFormatter;
9730 /** Creates an IValueFormatter to be used for a range of values. */
9731 function create(options) {
9732 debug.assertValue(options, 'options');
9733 var format = !!options.allowFormatBeautification ? locale.beautify(options.format) : options.format;
9734 if (shouldUseNumericDisplayUnits(options)) {
9735 var displayUnitSystem_1 = createDisplayUnitSystem(options.displayUnitSystemType);
9736 var singleValueFormattingMode_1 = !!options.formatSingleValues;
9737 displayUnitSystem_1.update(Math.max(Math.abs(options.value || 0), Math.abs(options.value2 || 0)));
9738 var forcePrecision_1 = options.precision != null;
9739 var decimals_1;
9740 if (forcePrecision_1)
9741 decimals_1 = -options.precision;
9742 else if (displayUnitSystem_1.displayUnit && displayUnitSystem_1.displayUnit.value > 1)
9743 decimals_1 = -MaxScaledDecimalPlaces;
9744 // Detect axis precision
9745 if (options.detectAxisPrecision) {
9746 // Trailing zeroes
9747 forcePrecision_1 = true;
9748 var axisValue = options.value;
9749 if (displayUnitSystem_1.displayUnit && displayUnitSystem_1.displayUnit.value > 0)
9750 axisValue = axisValue / displayUnitSystem_1.displayUnit.value;
9751 if (powerbi.Double.isInteger(axisValue))
9752 decimals_1 = 0;
9753 else
9754 decimals_1 = powerbi.Double.log10(axisValue);
9755 }
9756 return {
9757 format: function (value) {
9758 var formattedValue = getStringFormat(value, true /*nullsAreBlank*/);
9759 if (!StringExtensions.isNullOrUndefinedOrWhiteSpaceString(formattedValue))
9760 return formattedValue;
9761 // Round to Double.DEFAULT_PRECISION
9762 if (value && !displayUnitSystem_1.isScalingUnit() && Math.abs(value) < MaxValueForDisplayUnitRounding && !forcePrecision_1)
9763 value = powerbi.Double.roundToPrecision(value);
9764 return singleValueFormattingMode_1 ?
9765 displayUnitSystem_1.formatSingleValue(value, format, decimals_1, forcePrecision_1) :
9766 displayUnitSystem_1.format(value, format, decimals_1, forcePrecision_1);
9767 },
9768 displayUnit: displayUnitSystem_1.displayUnit,
9769 options: options
9770 };
9771 }
9772 if (shouldUseDateUnits(options.value, options.value2, options.tickCount)) {
9773 var unit_1 = powerbi.DateTimeSequence.getIntervalUnit(options.value /* minDate */, options.value2 /* maxDate */, options.tickCount);
9774 return {
9775 format: function (value) {
9776 if (value == null)
9777 return locale.null;
9778 var formatString = powerbi.formattingService.dateFormatString(unit_1);
9779 return formatCore(value, formatString);
9780 },
9781 options: options
9782 };
9783 }
9784 return createDefaultFormatter(format);
9785 }
9786 valueFormatter.create = create;
9787 function format(value, format, allowFormatBeautification) {
9788 if (value == null)
9789 return locale.null;
9790 return formatCore(value, !!allowFormatBeautification ? locale.beautify(format) : format);
9791 }
9792 valueFormatter.format = format;
9793 function getValueFormat(value, columnType) {
9794 // If column type not defined or is not datetime
9795 // ...and the value is of time datetime,
9796 // then use the default date format string
9797 if ((!columnType || !columnType.dateTime) && value instanceof Date)
9798 return getFormatString(DateTimeMetadataColumn, null, false);
9799 }
9800 function formatValueColumn(value, column, formatStringProp) {
9801 var valueFormat = getValueFormat(value, column.type);
9802 if (valueFormat)
9803 return formatCore(value, valueFormat);
9804 else
9805 return formatCore(value, getFormatString(column, formatStringProp));
9806 }
9807 valueFormatter.formatValueColumn = formatValueColumn;
9808 function createDisplayUnitSystem(displayUnitSystemType) {
9809 if (displayUnitSystemType == null)
9810 return new powerbi.DefaultDisplayUnitSystem(locale.describe);
9811 switch (displayUnitSystemType) {
9812 case powerbi.DisplayUnitSystemType.Default:
9813 return new powerbi.DefaultDisplayUnitSystem(locale.describe);
9814 case powerbi.DisplayUnitSystemType.WholeUnits:
9815 return new powerbi.WholeUnitsDisplayUnitSystem(locale.describe);
9816 case powerbi.DisplayUnitSystemType.Verbose:
9817 return new powerbi.NoDisplayUnitSystem();
9818 case powerbi.DisplayUnitSystemType.DataLabels:
9819 return new powerbi.DataLabelsDisplayUnitSystem(locale.describe);
9820 default:
9821 debug.assertFail('Unknown display unit system type');
9822 return new powerbi.DefaultDisplayUnitSystem(locale.describe);
9823 }
9824 }
9825 function shouldUseNumericDisplayUnits(options) {
9826 var value = options.value;
9827 var value2 = options.value2;
9828 var format = options.format;
9829 // For singleValue visuals like card, gauge we don't want to roundoff data to the nearest thousands so format the whole number / integers below 10K to not use display units
9830 if (options.formatSingleValues && format) {
9831 if (Math.abs(value) < MinIntegerValueForDisplayUnits) {
9832 var isCustomFormat = !powerbi.NumberFormat.isStandardFormat(format);
9833 if (isCustomFormat) {
9834 var precision = powerbi.NumberFormat.getCustomFormatMetadata(format, true /*calculatePrecision*/).precision;
9835 if (precision < MinPrecisionForDisplayUnits)
9836 return false;
9837 }
9838 else if (powerbi.Double.isInteger(value))
9839 return false;
9840 }
9841 }
9842 if ((typeof value === 'number') || (typeof value2 === 'number')) {
9843 return true;
9844 }
9845 }
9846 function shouldUseDateUnits(value, value2, tickCount) {
9847 // must check both value and value2 because we'll need to get an interval for date units
9848 return (value instanceof Date) && (value2 instanceof Date) && (tickCount !== undefined && tickCount !== null);
9849 }
9850 /*
9851 * Get the column format. Order of precendence is:
9852 * 1. Column format
9853 * 2. Default PowerView policy for column type
9854 */
9855 function getFormatString(column, formatStringProperty, suppressTypeFallback) {
9856 if (column) {
9857 if (formatStringProperty) {
9858 var propertyValue = powerbi.DataViewObjects.getValue(column.objects, formatStringProperty);
9859 if (propertyValue)
9860 return propertyValue;
9861 }
9862 if (!suppressTypeFallback) {
9863 var columnType = column.type;
9864 if (columnType) {
9865 if (columnType.dateTime)
9866 return valueFormatter.DefaultDateFormat;
9867 if (columnType.integer)
9868 return valueFormatter.DefaultIntegerFormat;
9869 if (columnType.numeric)
9870 return valueFormatter.DefaultNumericFormat;
9871 }
9872 }
9873 }
9874 }
9875 valueFormatter.getFormatString = getFormatString;
9876 function formatListCompound(strings, conjunction) {
9877 var result;
9878 if (!strings) {
9879 return null;
9880 }
9881 var length = strings.length;
9882 if (length > 0) {
9883 result = strings[0];
9884 var lastIndex = length - 1;
9885 for (var i = 1, len = lastIndex; i < len; i++) {
9886 var value = strings[i];
9887 result = StringExtensions.format(locale.restatementComma, result, value);
9888 }
9889 if (length > 1) {
9890 var value = strings[lastIndex];
9891 result = StringExtensions.format(conjunction, result, value);
9892 }
9893 }
9894 else {
9895 result = null;
9896 }
9897 return result;
9898 }
9899 /** The returned string will look like 'A, B, ..., and C' */
9900 function formatListAnd(strings) {
9901 return formatListCompound(strings, locale.restatementCompoundAnd);
9902 }
9903 valueFormatter.formatListAnd = formatListAnd;
9904 /** The returned string will look like 'A, B, ..., or C' */
9905 function formatListOr(strings) {
9906 return formatListCompound(strings, locale.restatementCompoundOr);
9907 }
9908 valueFormatter.formatListOr = formatListOr;
9909 function formatCore(value, format) {
9910 var formattedValue = getStringFormat(value, false /*nullsAreBlank*/);
9911 if (!StringExtensions.isNullOrUndefinedOrWhiteSpaceString(formattedValue))
9912 return formattedValue;
9913 return powerbi.formattingService.formatValue(value, format);
9914 }
9915 function getStringFormat(value, nullsAreBlank) {
9916 if (value == null && nullsAreBlank)
9917 return locale.null;
9918 if (value === true)
9919 return locale.true;
9920 if (value === false)
9921 return locale.false;
9922 if (typeof value === 'number' && isNaN(value))
9923 return locale.NaN;
9924 if (value === Number.NEGATIVE_INFINITY)
9925 return locale.negativeInfinity;
9926 if (value === Number.POSITIVE_INFINITY)
9927 return locale.infinity;
9928 return '';
9929 }
9930 function getDisplayUnits(displayUnitSystemType) {
9931 var displayUnitSystem = createDisplayUnitSystem(displayUnitSystemType);
9932 return displayUnitSystem.units;
9933 }
9934 valueFormatter.getDisplayUnits = getDisplayUnits;
9935 })(valueFormatter = visuals.valueFormatter || (visuals.valueFormatter = {}));
9936 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
9937})(powerbi || (powerbi = {}));
9938/*
9939 * Power BI Visualizations
9940 *
9941 * Copyright (c) Microsoft Corporation
9942 * All rights reserved.
9943 * MIT License
9944 *
9945 * Permission is hereby granted, free of charge, to any person obtaining a copy
9946 * of this software and associated documentation files (the ""Software""), to deal
9947 * in the Software without restriction, including without limitation the rights
9948 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9949 * copies of the Software, and to permit persons to whom the Software is
9950 * furnished to do so, subject to the following conditions:
9951 *
9952 * The above copyright notice and this permission notice shall be included in
9953 * all copies or substantial portions of the Software.
9954 *
9955 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9956 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9957 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9958 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9959 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9960 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9961 * THE SOFTWARE.
9962 */
9963/*
9964 * Power BI Visualizations
9965 *
9966 * Copyright (c) Microsoft Corporation
9967 * All rights reserved.
9968 * MIT License
9969 *
9970 * Permission is hereby granted, free of charge, to any person obtaining a copy
9971 * of this software and associated documentation files (the ""Software""), to deal
9972 * in the Software without restriction, including without limitation the rights
9973 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9974 * copies of the Software, and to permit persons to whom the Software is
9975 * furnished to do so, subject to the following conditions:
9976 *
9977 * The above copyright notice and this permission notice shall be included in
9978 * all copies or substantial portions of the Software.
9979 *
9980 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9981 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9982 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9983 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9984 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9985 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9986 * THE SOFTWARE.
9987 */
9988/*
9989 * Power BI Visualizations
9990 *
9991 * Copyright (c) Microsoft Corporation
9992 * All rights reserved.
9993 * MIT License
9994 *
9995 * Permission is hereby granted, free of charge, to any person obtaining a copy
9996 * of this software and associated documentation files (the ""Software""), to deal
9997 * in the Software without restriction, including without limitation the rights
9998 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9999 * copies of the Software, and to permit persons to whom the Software is
10000 * furnished to do so, subject to the following conditions:
10001 *
10002 * The above copyright notice and this permission notice shall be included in
10003 * all copies or substantial portions of the Software.
10004 *
10005 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10006 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10007 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10008 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10009 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10010 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10011 * THE SOFTWARE.
10012 */
10013var powerbi;
10014(function (powerbi) {
10015 var data;
10016 (function (data) {
10017 var DataRoleHelper;
10018 (function (DataRoleHelper) {
10019 function getMeasureIndexOfRole(grouped, roleName) {
10020 if (!_.isEmpty(grouped)) {
10021 var firstGroup = grouped[0];
10022 if (firstGroup.values && firstGroup.values.length > 0) {
10023 for (var i = 0, len = firstGroup.values.length; i < len; ++i) {
10024 var value = firstGroup.values[i];
10025 if (value && value.source) {
10026 if (hasRole(value.source, roleName))
10027 return i;
10028 }
10029 }
10030 }
10031 }
10032 return -1;
10033 }
10034 DataRoleHelper.getMeasureIndexOfRole = getMeasureIndexOfRole;
10035 function getCategoryIndexOfRole(categories, roleName) {
10036 if (!_.isEmpty(categories)) {
10037 for (var i = 0, ilen = categories.length; i < ilen; i++) {
10038 if (hasRole(categories[i].source, roleName))
10039 return i;
10040 }
10041 }
10042 return -1;
10043 }
10044 DataRoleHelper.getCategoryIndexOfRole = getCategoryIndexOfRole;
10045 function hasRole(column, name) {
10046 var roles = column.roles;
10047 return roles && roles[name];
10048 }
10049 DataRoleHelper.hasRole = hasRole;
10050 function hasRoleInDataView(dataView, name) {
10051 return dataView != null
10052 && dataView.metadata != null
10053 && dataView.metadata.columns
10054 && _.any(dataView.metadata.columns, function (c) { return c.roles && c.roles[name] !== undefined; });
10055 }
10056 DataRoleHelper.hasRoleInDataView = hasRoleInDataView;
10057 function hasRoleInValueColumn(valueColumn, name) {
10058 return valueColumn && valueColumn.source && valueColumn.source.roles && (valueColumn.source.roles[name] === true);
10059 }
10060 DataRoleHelper.hasRoleInValueColumn = hasRoleInValueColumn;
10061 })(DataRoleHelper = data.DataRoleHelper || (data.DataRoleHelper = {}));
10062 })(data = powerbi.data || (powerbi.data = {}));
10063})(powerbi || (powerbi = {}));
10064/*
10065 * Power BI Visualizations
10066 *
10067 * Copyright (c) Microsoft Corporation
10068 * All rights reserved.
10069 * MIT License
10070 *
10071 * Permission is hereby granted, free of charge, to any person obtaining a copy
10072 * of this software and associated documentation files (the ""Software""), to deal
10073 * in the Software without restriction, including without limitation the rights
10074 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10075 * copies of the Software, and to permit persons to whom the Software is
10076 * furnished to do so, subject to the following conditions:
10077 *
10078 * The above copyright notice and this permission notice shall be included in
10079 * all copies or substantial portions of the Software.
10080 *
10081 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10082 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10083 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10084 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10085 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10086 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10087 * THE SOFTWARE.
10088 */
10089var powerbi;
10090(function (powerbi) {
10091 var data;
10092 (function (data) {
10093 var DataRoleHelper = powerbi.data.DataRoleHelper;
10094 function createIDataViewCategoricalReader(dataView) {
10095 return new DataViewCategoricalReader(dataView);
10096 }
10097 data.createIDataViewCategoricalReader = createIDataViewCategoricalReader;
10098 var DataViewCategoricalReader = (function () {
10099 function DataViewCategoricalReader(dataView) {
10100 debug.assertValue(dataView, 'dataView');
10101 this.dataView = dataView;
10102 // Validate categories
10103 var categorical;
10104 if (dataView)
10105 categorical = dataView.categorical;
10106 var categories;
10107 if (categorical)
10108 categories = this.categories = categorical.categories;
10109 this.hasValidCategories = !_.isEmpty(categories);
10110 // Validate values
10111 var values;
10112 if (categorical)
10113 values = categorical.values;
10114 // We need to access grouped as long as values is non-null; if it's an empty array (meaning there is a category + series), we'll use grouped for non-value stuff
10115 // TODO: think a bit more about how to represent this internally; Maybe split this up between hasGroup and hasValidValues or something
10116 this.hasAnyValidValues = false;
10117 if (values != null) {
10118 var grouped = dataView.categorical.values.grouped();
10119 if (grouped.length > 0) {
10120 this.hasAnyValidValues = true;
10121 this.grouped = grouped;
10122 // Iterate through the first group's values to populate the valueRoleIndexMapping
10123 var valueRoleIndexMapping = {};
10124 var firstGroupValues = grouped[0].values;
10125 for (var valueIndex = 0, valueCount = firstGroupValues.length; valueIndex < valueCount; valueIndex++) {
10126 var valueRoles = firstGroupValues[valueIndex].source.roles;
10127 for (var role in valueRoles) {
10128 if (valueRoles[role]) {
10129 if (!valueRoleIndexMapping[role])
10130 valueRoleIndexMapping[role] = [];
10131 valueRoleIndexMapping[role].push(valueIndex);
10132 }
10133 }
10134 }
10135 this.valueRoleIndexMapping = valueRoleIndexMapping;
10136 }
10137 }
10138 if (this.hasAnyValidValues)
10139 this.dataHasDynamicSeries = !!this.dataView.categorical.values.source;
10140 }
10141 // Category methods
10142 DataViewCategoricalReader.prototype.hasCategories = function () {
10143 return this.hasValidCategories;
10144 };
10145 DataViewCategoricalReader.prototype.getCategoryCount = function () {
10146 if (this.hasValidCategories)
10147 return this.categories[0].values.length;
10148 else
10149 return 0;
10150 };
10151 DataViewCategoricalReader.prototype.getCategoryValues = function (roleName) {
10152 if (this.hasValidCategories) {
10153 var categories = this.getCategoryFromRole(roleName);
10154 return categories ? categories.values : undefined;
10155 }
10156 };
10157 DataViewCategoricalReader.prototype.getCategoryValue = function (roleName, categoryIndex) {
10158 if (this.hasValidCategories) {
10159 var categories = this.getCategoryFromRole(roleName);
10160 return categories ? categories.values[categoryIndex] : undefined;
10161 }
10162 };
10163 DataViewCategoricalReader.prototype.getCategoryColumn = function (roleName) {
10164 if (this.hasValidCategories)
10165 return this.getCategoryFromRole(roleName);
10166 };
10167 DataViewCategoricalReader.prototype.getCategoryMetadataColumn = function (roleName) {
10168 if (this.hasValidCategories) {
10169 var categories = this.getCategoryFromRole(roleName);
10170 return categories ? categories.source : undefined;
10171 }
10172 };
10173 DataViewCategoricalReader.prototype.getCategoryColumnIdentityFields = function (roleName) {
10174 if (this.hasValidCategories) {
10175 var categories = this.getCategoryFromRole(roleName);
10176 return categories ? categories.identityFields : undefined;
10177 }
10178 };
10179 DataViewCategoricalReader.prototype.getCategoryDisplayName = function (roleName) {
10180 if (this.hasValidCategories) {
10181 var targetColumn = this.getCategoryColumn(roleName);
10182 if (targetColumn && targetColumn.source) {
10183 return targetColumn.source.displayName;
10184 }
10185 }
10186 };
10187 DataViewCategoricalReader.prototype.hasCompositeCategories = function () {
10188 if (this.hasValidCategories)
10189 return this.categories.length > 1;
10190 };
10191 DataViewCategoricalReader.prototype.hasCategoryWithRole = function (roleName) {
10192 return DataRoleHelper.getCategoryIndexOfRole(this.categories, roleName) !== -1;
10193 };
10194 DataViewCategoricalReader.prototype.getCategoryObjects = function (roleName, categoryIndex) {
10195 if (this.hasValidCategories) {
10196 var category = this.getCategoryFromRole(roleName);
10197 if (category && category.objects) {
10198 return category.objects[categoryIndex];
10199 }
10200 }
10201 };
10202 DataViewCategoricalReader.prototype.getCategoryFromRole = function (roleName) {
10203 var categories = this.categories;
10204 return categories[DataRoleHelper.getCategoryIndexOfRole(categories, roleName)];
10205 };
10206 // Value and measure methods
10207 DataViewCategoricalReader.prototype.hasValues = function (roleName) {
10208 return this.valueRoleIndexMapping && !_.isEmpty(this.valueRoleIndexMapping[roleName]);
10209 };
10210 DataViewCategoricalReader.prototype.getValue = function (roleName, categoryIndex, seriesIndex) {
10211 if (seriesIndex === void 0) { seriesIndex = 0; }
10212 if (this.hasValues(roleName)) {
10213 if (this.dataHasDynamicSeries) {
10214 // For dynamic series, we only ever obtain the first value column from a role
10215 return this.getValueInternal(roleName, categoryIndex, seriesIndex, 0, false /* getHighlight */);
10216 }
10217 else {
10218 // For static series or single series, we obtain value columns from the first series
10219 // and use the seriesIndex to index into the value columns within the role
10220 return this.getValueInternal(roleName, categoryIndex, 0, seriesIndex, false /* getHighlight */);
10221 }
10222 }
10223 };
10224 DataViewCategoricalReader.prototype.getHighlight = function (roleName, categoryIndex, seriesIndex) {
10225 if (seriesIndex === void 0) { seriesIndex = 0; }
10226 if (this.hasValues(roleName)) {
10227 if (this.dataHasDynamicSeries) {
10228 // For dynamic series, we only ever obtain the first value column from a role
10229 return this.getValueInternal(roleName, categoryIndex, seriesIndex, 0, true /* getHighlight */);
10230 }
10231 else {
10232 // For static series or single series, we obtain value columns from the first series
10233 // and use the seriesIndex to index into the value columns within the role
10234 return this.getValueInternal(roleName, categoryIndex, 0, seriesIndex, true /* getHighlight */);
10235 }
10236 }
10237 };
10238 DataViewCategoricalReader.prototype.getAllValuesForRole = function (roleName, categoryIndex, seriesIndex) {
10239 if (seriesIndex === void 0) { seriesIndex = 0; }
10240 if (this.hasValues(roleName)) {
10241 var valuesInRole = [];
10242 for (var roleValueIndex = void 0, roleValueCount = this.valueRoleIndexMapping[roleName].length; roleValueIndex < roleValueCount; roleValueIndex++) {
10243 valuesInRole.push(this.getValueInternal(roleName, categoryIndex, seriesIndex, roleValueIndex, false /* getHighlight */));
10244 }
10245 return valuesInRole;
10246 }
10247 };
10248 DataViewCategoricalReader.prototype.getAllHighlightsForRole = function (roleName, categoryIndex, seriesIndex) {
10249 if (seriesIndex === void 0) { seriesIndex = 0; }
10250 if (this.hasValues(roleName)) {
10251 var valuesInRole = [];
10252 for (var roleValueIndex = void 0, roleValueCount = this.valueRoleIndexMapping[roleName].length; roleValueIndex < roleValueCount; roleValueIndex++) {
10253 valuesInRole.push(this.getValueInternal(roleName, categoryIndex, seriesIndex, roleValueIndex, true /* getHighlight */));
10254 }
10255 return valuesInRole;
10256 }
10257 };
10258 /**
10259 * Obtains the value from grouped.
10260 *
10261 * Grouped: [0] [1] [2] [3] (seriesIndex)
10262 * / \
10263 * .values: [T0] [V0] [V1] [T1] [V2] (valueColumnIndex)
10264 * / \ \ \
10265 * v.values: [0, 1, 2, 3, 4] [5, 6, 7, 8, 9] (categoryIndex)
10266 *
10267 *--------------------------------|
10268 * |Category |
10269 * Series|Value Columns |A B C D E|
10270 *--------------------------------|
10271 * 0|col0 (tooltip)| |
10272 * |col1 (value) | |
10273 * |col2 (value) | |
10274 * |col3 (tooltip)| |
10275 * |col4 (value) | |
10276 *--------------------------------|
10277 * 1|col0 (tooltip)| |
10278 * |col1 (value) |0 1 2 3 4|
10279 * |col2 (value) |5 6 7 8 9|
10280 * |col3 (tooltip)| |
10281 * |col4 (value) | |
10282 *--------------------------------|
10283 * 2|col0 (tooltip)|... |
10284 *
10285 * valueColumnIndexInRole is for indexing into the values for a single role
10286 * valueColumnIndex is for indexing into the entire value array including
10287 * all roles
10288 *
10289 * The valueRoleIndexMapping converts roleValueIndex and role (value role
10290 * with an index of 1) into groupedValueIndex (2)
10291 *
10292 * Example: getValueInternal(V, 3, 1, 1) returns 8: The second group,
10293 * the second value column with role "value" (which is converted to a
10294 * groupedValueIndex of 2) and the fourth value within that value column.
10295 */
10296 DataViewCategoricalReader.prototype.getValueInternal = function (roleName, categoryIndex, groupIndex, valueColumnIndexInRole, getHighlight) {
10297 if (this.hasValues(roleName)) {
10298 var valueColumnIndex = this.valueRoleIndexMapping[roleName][valueColumnIndexInRole];
10299 var groupedValues = this.grouped[groupIndex].values[valueColumnIndex];
10300 return getHighlight ? groupedValues.highlights[categoryIndex] : groupedValues.values[categoryIndex];
10301 }
10302 };
10303 DataViewCategoricalReader.prototype.getFirstNonNullValueForCategory = function (roleName, categoryIndex) {
10304 if (this.hasValues(roleName)) {
10305 if (!this.dataHasDynamicSeries) {
10306 debug.assert(this.grouped.length === 1, "getFirstNonNullValueForCategory shouldn't be called if you have a static series");
10307 return this.getValue(roleName, categoryIndex);
10308 }
10309 for (var seriesIndex = 0, seriesCount = this.grouped.length; seriesIndex < seriesCount; seriesIndex++) {
10310 var value = this.getValue(roleName, categoryIndex, seriesIndex);
10311 if (value != null) {
10312 return value;
10313 }
10314 }
10315 }
10316 };
10317 DataViewCategoricalReader.prototype.getMeasureQueryName = function (roleName) {
10318 if (this.hasValues(roleName))
10319 return this.grouped[0].values[this.valueRoleIndexMapping[roleName][0]].source.queryName;
10320 };
10321 DataViewCategoricalReader.prototype.getValueColumn = function (roleName, seriesIndex) {
10322 if (seriesIndex === void 0) { seriesIndex = 0; }
10323 if (this.hasValues(roleName)) {
10324 if (this.dataHasDynamicSeries) {
10325 return this.grouped[seriesIndex].values[this.valueRoleIndexMapping[roleName][0]];
10326 }
10327 else {
10328 return this.grouped[0].values[this.valueRoleIndexMapping[roleName][seriesIndex]];
10329 }
10330 }
10331 };
10332 DataViewCategoricalReader.prototype.getValueMetadataColumn = function (roleName, seriesIndex) {
10333 if (seriesIndex === void 0) { seriesIndex = 0; }
10334 var valueColumn = this.getValueColumn(roleName, seriesIndex);
10335 if (valueColumn) {
10336 return valueColumn.source;
10337 }
10338 };
10339 DataViewCategoricalReader.prototype.getValueDisplayName = function (roleName, seriesIndex) {
10340 if (this.hasValues(roleName)) {
10341 var targetColumn = this.getValueColumn(roleName, seriesIndex);
10342 if (targetColumn && targetColumn.source) {
10343 return targetColumn.source.displayName;
10344 }
10345 }
10346 };
10347 // Series methods
10348 DataViewCategoricalReader.prototype.hasDynamicSeries = function () {
10349 return this.dataHasDynamicSeries;
10350 };
10351 DataViewCategoricalReader.prototype.getSeriesCount = function (valueRoleName) {
10352 if (this.hasAnyValidValues) {
10353 if (this.dataHasDynamicSeries) {
10354 return this.grouped.length;
10355 }
10356 else if (valueRoleName) {
10357 return this.valueRoleIndexMapping[valueRoleName].length;
10358 }
10359 else {
10360 return 1;
10361 }
10362 }
10363 };
10364 DataViewCategoricalReader.prototype.getSeriesObjects = function (seriesIndex) {
10365 if (this.hasAnyValidValues)
10366 return this.grouped[seriesIndex].objects;
10367 };
10368 DataViewCategoricalReader.prototype.getSeriesValueColumns = function () {
10369 if (this.hasAnyValidValues)
10370 return this.dataView.categorical.values;
10371 };
10372 DataViewCategoricalReader.prototype.getSeriesValueColumnGroup = function (seriesIndex) {
10373 if (this.hasAnyValidValues)
10374 return this.grouped[seriesIndex];
10375 };
10376 DataViewCategoricalReader.prototype.getSeriesMetadataColumn = function () {
10377 if (this.hasAnyValidValues)
10378 return this.dataView.categorical.values.source;
10379 };
10380 DataViewCategoricalReader.prototype.getSeriesColumnIdentityFields = function () {
10381 if (this.hasAnyValidValues)
10382 return this.dataView.categorical.values.identityFields;
10383 };
10384 DataViewCategoricalReader.prototype.getSeriesName = function (seriesIndex) {
10385 if (this.hasAnyValidValues)
10386 return this.grouped[seriesIndex].name;
10387 };
10388 DataViewCategoricalReader.prototype.getSeriesDisplayName = function () {
10389 if (this.hasAnyValidValues && this.dataHasDynamicSeries)
10390 return this.dataView.categorical.values.source.displayName;
10391 };
10392 return DataViewCategoricalReader;
10393 }());
10394 })(data = powerbi.data || (powerbi.data = {}));
10395})(powerbi || (powerbi = {}));
10396/*
10397 * Power BI Visualizations
10398 *
10399 * Copyright (c) Microsoft Corporation
10400 * All rights reserved.
10401 * MIT License
10402 *
10403 * Permission is hereby granted, free of charge, to any person obtaining a copy
10404 * of this software and associated documentation files (the ""Software""), to deal
10405 * in the Software without restriction, including without limitation the rights
10406 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10407 * copies of the Software, and to permit persons to whom the Software is
10408 * furnished to do so, subject to the following conditions:
10409 *
10410 * The above copyright notice and this permission notice shall be included in
10411 * all copies or substantial portions of the Software.
10412 *
10413 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10414 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10415 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10416 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10417 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10418 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10419 * THE SOFTWARE.
10420 */
10421var powerbi;
10422(function (powerbi) {
10423 var data;
10424 (function (data) {
10425 var inherit = powerbi.Prototype.inherit;
10426 var inheritSingle = powerbi.Prototype.inheritSingle;
10427 var valueFormatter = powerbi.visuals.valueFormatter;
10428 var DataViewConcatenateCategoricalColumns;
10429 (function (DataViewConcatenateCategoricalColumns) {
10430 function detectAndApply(dataView, objectDescriptors, roleMappings, projectionOrdering, selects, projectionActiveItems) {
10431 debug.assertValue(dataView, 'dataView');
10432 debug.assertAnyValue(roleMappings, 'roleMappings');
10433 debug.assertAnyValue(projectionOrdering, 'projectionOrdering');
10434 var result = dataView;
10435 var dataViewCategorical = dataView.categorical;
10436 if (dataViewCategorical) {
10437 var concatenationSource = detectCategoricalRoleForHierarchicalGroup(dataViewCategorical, dataView.metadata, roleMappings, selects, projectionActiveItems);
10438 if (concatenationSource) {
10439 // Consider: Perhaps the re-ordering of categorical columns should happen in the function transformSelects(...) of dataViewTransform?
10440 var columnsSortedByProjectionOrdering = sortColumnsByProjectionOrdering(projectionOrdering, concatenationSource.roleName, concatenationSource.categories);
10441 if (columnsSortedByProjectionOrdering.length >= 2) {
10442 var activeItemsToIgnoreInConcatenation = _.chain(projectionActiveItems[concatenationSource.roleName])
10443 .filter(function (activeItemInfo) { return activeItemInfo.suppressConcat; })
10444 .map(function (activeItemInfo) { return activeItemInfo.queryRef; })
10445 .value();
10446 result = applyConcatenation(dataView, objectDescriptors, concatenationSource.roleName, columnsSortedByProjectionOrdering, activeItemsToIgnoreInConcatenation);
10447 }
10448 }
10449 }
10450 return result;
10451 }
10452 DataViewConcatenateCategoricalColumns.detectAndApply = detectAndApply;
10453 /** For applying concatenation to the DataViewCategorical that is the data for one of the frames in a play chart. */
10454 function applyToPlayChartCategorical(metadata, objectDescriptors, categoryRoleName, categorical) {
10455 debug.assertValue(metadata, 'metadata');
10456 debug.assertAnyValue(objectDescriptors, 'objectDescriptors');
10457 debug.assertValue(categorical, 'categorical');
10458 var result;
10459 if (!_.isEmpty(categorical.categories) && categorical.categories.length >= 2) {
10460 // In PlayChart, the code converts the Visual DataView with a matrix into multiple Visual DataViews, each with a categorical.
10461 // metadata and metadata.columns could already be inherited objects as they come from the Visual DataView with a matrix.
10462 // To guarantee that this method does not have any side effect on prototypeMetadata (which might already be an inherited obj),
10463 // use inherit() rather than inheritSingle() here.
10464 var transformingColumns_1 = inherit(metadata.columns);
10465 var transformingMetadata = inherit(metadata, function (m) { m.columns = transformingColumns_1; });
10466 var transformingDataView = { metadata: transformingMetadata, categorical: categorical };
10467 result = applyConcatenation(transformingDataView, objectDescriptors, categoryRoleName, categorical.categories, []);
10468 }
10469 else {
10470 result = { metadata: metadata, categorical: categorical };
10471 }
10472 return result;
10473 }
10474 DataViewConcatenateCategoricalColumns.applyToPlayChartCategorical = applyToPlayChartCategorical;
10475 /**
10476 * Returns the role and its assocated category columns (from dataViewCategorical.categories)
10477 * that should be concatenated for the case of hierarchical group.
10478 *
10479 * Note: In the future if we support sibling hierarchical groups in categorical,
10480 * change the return type to CategoryColumnsByRole[] and update detection logic.
10481 */
10482 function detectCategoricalRoleForHierarchicalGroup(dataViewCategorical, metadata, dataViewMappings, selects, projectionActiveItems) {
10483 debug.assertValue(dataViewCategorical, 'dataViewCategorical');
10484 debug.assertAnyValue(dataViewMappings, 'dataViewMappings');
10485 var result;
10486 var roleKinds = data.DataViewSelectTransform.createRoleKindFromMetadata(selects, metadata);
10487 var projections = data.DataViewSelectTransform.projectionsFromSelects(selects, projectionActiveItems);
10488 var supportedRoleMappings = powerbi.DataViewAnalysis.chooseDataViewMappings(projections, dataViewMappings, roleKinds).supportedMappings;
10489 // The following code will choose a role name only if all supportedRoleMappings share the same role for Categorical Category.
10490 // Handling multiple supportedRoleMappings is necessary for TransformActions with splits, which can happen in scenarios such as:
10491 // 1. combo chart with a field for both Line and Column values, and
10492 // 2. chart with regression line enabled.
10493 // In case 1, you can pretty much get exactly the one from supportedRoleMappings for which this code is currently processing for,
10494 // by looking at the index of the current split in DataViewTransformActions.splits.
10495 // In case 2, however, supportedRoleMappings.length will be different than DataViewTransformActions.splits.length, hence it is
10496 // not straight forward to figure out for which one in supportedRoleMappings is this code currently processing.
10497 // SO... This code will just choose the category role name if it is consistent across all supportedRoleMappings.
10498 var isEveryRoleMappingForCategorical = !_.isEmpty(supportedRoleMappings) &&
10499 _.every(supportedRoleMappings, function (roleMapping) { return !!roleMapping.categorical; });
10500 if (isEveryRoleMappingForCategorical) {
10501 var targetRoleName_1 = getSingleCategoryRoleNameInEveryRoleMapping(supportedRoleMappings);
10502 if (targetRoleName_1 &&
10503 isVisualExpectingMaxOneCategoryColumn(targetRoleName_1, supportedRoleMappings)) {
10504 var categoryColumnsForTargetRole_1 = _.filter(dataViewCategorical.categories, function (categoryColumn) { return categoryColumn.source.roles && !!categoryColumn.source.roles[targetRoleName_1]; });
10505 // There is no need to concatenate columns unless there is actually more than one column
10506 if (categoryColumnsForTargetRole_1.length >= 2) {
10507 // At least for now, we expect all category columns for the same role to have the same number of value entries.
10508 // If that's not the case, we won't run the concatenate logic for that role at all...
10509 var areValuesCountsEqual = _.every(categoryColumnsForTargetRole_1, function (categoryColumn) { return categoryColumn.values.length === categoryColumnsForTargetRole_1[0].values.length; });
10510 if (areValuesCountsEqual) {
10511 result = {
10512 roleName: targetRoleName_1,
10513 categories: categoryColumnsForTargetRole_1,
10514 };
10515 }
10516 }
10517 }
10518 }
10519 return result;
10520 }
10521 /** If all mappings in the specified roleMappings have the same single role name for their categorical category roles, return that role name, else returns undefined. */
10522 function getSingleCategoryRoleNameInEveryRoleMapping(categoricalRoleMappings) {
10523 debug.assertNonEmpty(categoricalRoleMappings, 'categoricalRoleMappings');
10524 debug.assert(_.every(categoricalRoleMappings, function (roleMapping) { return !!roleMapping.categorical; }), 'All mappings in categoricalRoleMappings must contain a DataViewCategoricalMapping');
10525 var result;
10526 // With "list" in role mapping, it is possible to have multiple role names for category.
10527 // For now, proceed to concatenate category columns only when categories are bound to 1 Role.
10528 // We can change this if we want to support independent (sibling) group hierarchies in categorical.
10529 var uniqueCategoryRoles = _.chain(categoricalRoleMappings)
10530 .map(function (roleMapping) {
10531 var categoryRoles = getAllRolesInCategories(roleMapping.categorical);
10532 return categoryRoles.length === 1 ? categoryRoles[0] : undefined;
10533 })
10534 .uniq() // Note: _.uniq() does not treat two arrays with same elements as equal
10535 .value();
10536 var isSameCategoryRoleNameInAllRoleMappings = uniqueCategoryRoles.length === 1 && !_.isUndefined(uniqueCategoryRoles[0]);
10537 if (isSameCategoryRoleNameInAllRoleMappings) {
10538 result = uniqueCategoryRoles[0];
10539 }
10540 return result;
10541 }
10542 function isVisualExpectingMaxOneCategoryColumn(categoricalRoleName, roleMappings) {
10543 debug.assertValue(categoricalRoleName, 'categoricalRoleName');
10544 debug.assertNonEmpty(roleMappings, 'roleMappings');
10545 var isVisualExpectingMaxOneCategoryColumn = _.every(roleMappings, function (roleMapping) {
10546 return !_.isEmpty(roleMapping.conditions) &&
10547 _.every(roleMapping.conditions, function (condition) { return condition[categoricalRoleName] && condition[categoricalRoleName].max === 1; });
10548 });
10549 return isVisualExpectingMaxOneCategoryColumn;
10550 }
10551 /**
10552 * Returns the array of role names that are mapped to categorical categories.
10553 * Returns an empty array if none exists.
10554 */
10555 function getAllRolesInCategories(categoricalRoleMapping) {
10556 debug.assertValue(categoricalRoleMapping, 'categoricalRoleMapping');
10557 var roleNames = [];
10558 powerbi.DataViewMapping.visitCategoricalCategories(categoricalRoleMapping.categories, {
10559 visitRole: function (roleName) {
10560 roleNames.push(roleName);
10561 }
10562 });
10563 return roleNames;
10564 }
10565 function applyConcatenation(dataView, objectDescriptors, roleName, columnsSortedByProjectionOrdering, queryRefsToIgnore) {
10566 debug.assertValue(dataView, 'dataView');
10567 debug.assertAnyValue(objectDescriptors, 'objectDescriptors');
10568 debug.assertValue(roleName, 'roleName');
10569 debug.assert(columnsSortedByProjectionOrdering && columnsSortedByProjectionOrdering.length >= 2, 'columnsSortedByProjectionOrdering && columnsSortedByProjectionOrdering.length >= 2');
10570 var formatStringPropId = data.DataViewObjectDescriptors.findFormatString(objectDescriptors);
10571 var concatenatedValues = concatenateValues(columnsSortedByProjectionOrdering, queryRefsToIgnore, formatStringPropId);
10572 var columnsSourceSortedByProjectionOrdering = _.map(columnsSortedByProjectionOrdering, function (categoryColumn) { return categoryColumn.source; });
10573 var concatenatedColumnMetadata = createConcatenatedColumnMetadata(roleName, columnsSourceSortedByProjectionOrdering, queryRefsToIgnore);
10574 var transformedDataView = inheritSingle(dataView);
10575 addToMetadata(transformedDataView, concatenatedColumnMetadata);
10576 var concatenatedCategoryColumn = createConcatenatedCategoryColumn(columnsSortedByProjectionOrdering, concatenatedColumnMetadata, concatenatedValues);
10577 var dataViewCategorical = dataView.categorical;
10578 var transformedCategoricalCategories = _.difference(dataViewCategorical.categories, columnsSortedByProjectionOrdering);
10579 transformedCategoricalCategories.push(concatenatedCategoryColumn);
10580 var transformedCategorical = inheritSingle(dataViewCategorical);
10581 transformedCategorical.categories = transformedCategoricalCategories;
10582 transformedDataView.categorical = transformedCategorical;
10583 return transformedDataView;
10584 }
10585 function concatenateValues(columnsSortedByProjectionOrdering, queryRefsToIgnore, formatStringPropId) {
10586 debug.assertValue(columnsSortedByProjectionOrdering, 'columnsSortedByProjectionOrdering');
10587 debug.assertAnyValue(queryRefsToIgnore, 'queryRefsToIgnore');
10588 debug.assertAnyValue(formatStringPropId, 'formatStringPropId');
10589 var concatenatedValues = [];
10590 // concatenate the values in dataViewCategorical.categories[0..length-1].values[j], and store it in combinedValues[j]
10591 for (var _i = 0, columnsSortedByProjectionOrdering_1 = columnsSortedByProjectionOrdering; _i < columnsSortedByProjectionOrdering_1.length; _i++) {
10592 var categoryColumn = columnsSortedByProjectionOrdering_1[_i];
10593 var formatString = valueFormatter.getFormatString(categoryColumn.source, formatStringPropId);
10594 for (var i = 0, len = categoryColumn.values.length; i < len; i++) {
10595 if (!_.contains(queryRefsToIgnore, categoryColumn.source.queryName)) {
10596 var value = categoryColumn.values && categoryColumn.values[i];
10597 var formattedValue = valueFormatter.format(value, formatString);
10598 concatenatedValues[i] = (concatenatedValues[i] === undefined) ? formattedValue : (formattedValue + ' ' + concatenatedValues[i]);
10599 }
10600 }
10601 }
10602 return concatenatedValues;
10603 }
10604 /**
10605 * Returns a new array of elements from columns as they are ordered for the specified roleName in the specified projectionOrdering.
10606 */
10607 function sortColumnsByProjectionOrdering(projectionOrdering, roleName, columns) {
10608 debug.assertAnyValue(projectionOrdering, 'projectionOrdering');
10609 debug.assertValue(roleName, 'roleName');
10610 debug.assertValue(columns, 'columns');
10611 var columnsInProjectionOrdering;
10612 if (projectionOrdering) {
10613 // the numeric values in projectionOrdering correspond to the index property of DataViewMetadataColumn
10614 var columnsByIndex_1 = {};
10615 for (var _i = 0, columns_1 = columns; _i < columns_1.length; _i++) {
10616 var column = columns_1[_i];
10617 if (column.source.roles[roleName]) {
10618 debug.assert(!columnsByIndex_1[column.source.index], 'The specified columns should not contain multiple columns with same index: ' + column.source.index);
10619 columnsByIndex_1[column.source.index] = column;
10620 }
10621 }
10622 var columnIndicesInProjectionOrdering = projectionOrdering[roleName];
10623 columnsInProjectionOrdering = _.chain(columnIndicesInProjectionOrdering)
10624 .map(function (columnIndex) { return columnsByIndex_1[columnIndex]; })
10625 .filter(function (column) { return !!column; })
10626 .value();
10627 }
10628 else {
10629 // If projectionOrder is unspecified, just return the columns for the specified role in their current order
10630 columnsInProjectionOrdering = _.filter(columns, function (column) { return column.source.roles[roleName]; });
10631 }
10632 return columnsInProjectionOrdering;
10633 }
10634 /**
10635 * Creates the column metadata that will back the column with the concatenated values.
10636 */
10637 function createConcatenatedColumnMetadata(roleName, sourceColumnsSortedByProjectionOrdering, queryRefsToIgnore) {
10638 debug.assertValue(roleName, 'roleName');
10639 debug.assertNonEmpty(sourceColumnsSortedByProjectionOrdering, 'sourceColumnsSortedByProjectionOrdering');
10640 debug.assert(_.chain(sourceColumnsSortedByProjectionOrdering).map(function (c) { return c.isMeasure; }).uniq().value().length === 1, 'pre-condition: caller code should not attempt to combine a mix of measure columns and non-measure columns');
10641 var concatenatedDisplayName;
10642 for (var _i = 0, sourceColumnsSortedByProjectionOrdering_1 = sourceColumnsSortedByProjectionOrdering; _i < sourceColumnsSortedByProjectionOrdering_1.length; _i++) {
10643 var columnSource = sourceColumnsSortedByProjectionOrdering_1[_i];
10644 if (!_.contains(queryRefsToIgnore, columnSource.queryName)) {
10645 concatenatedDisplayName = (concatenatedDisplayName == null) ? columnSource.displayName : (columnSource.displayName + ' ' + concatenatedDisplayName);
10646 }
10647 }
10648 var newRoles = {};
10649 newRoles[roleName] = true;
10650 var newColumnMetadata = {
10651 displayName: concatenatedDisplayName,
10652 roles: newRoles,
10653 type: powerbi.ValueType.fromPrimitiveTypeAndCategory(powerbi.PrimitiveType.Text)
10654 };
10655 var columnSourceForCurrentDrillLevel = _.last(sourceColumnsSortedByProjectionOrdering);
10656 if (columnSourceForCurrentDrillLevel.isMeasure !== undefined) {
10657 newColumnMetadata.isMeasure = columnSourceForCurrentDrillLevel.isMeasure;
10658 }
10659 // TODO VSTS 6842046: Investigate whether we should change that property to mandatory or change the Chart visual code.
10660 // If queryName is not set at all, the column chart visual will only render column for the first group instance.
10661 // If queryName is set to any string other than columnForCurrentDrillLevel.source.queryName, then drilldown by group instance is broken (VSTS 6847879).
10662 newColumnMetadata.queryName = columnSourceForCurrentDrillLevel.queryName;
10663 return newColumnMetadata;
10664 }
10665 function addToMetadata(transformedDataView, newColumn) {
10666 debug.assertValue(transformedDataView, 'transformedDataView');
10667 debug.assertValue(newColumn, 'newColumn');
10668 var transformedColumns = inheritSingle(transformedDataView.metadata.columns);
10669 transformedColumns.push(newColumn);
10670 var transformedMetadata = inheritSingle(transformedDataView.metadata);
10671 transformedMetadata.columns = transformedColumns;
10672 transformedDataView.metadata = transformedMetadata;
10673 }
10674 function createConcatenatedCategoryColumn(sourceColumnsSortedByProjectionOrdering, columnMetadata, concatenatedValues) {
10675 debug.assert(sourceColumnsSortedByProjectionOrdering && sourceColumnsSortedByProjectionOrdering.length >= 2, 'sourceColumnsSortedByProjectionOrdering && sourceColumnsSortedByProjectionOrdering.length >= 2');
10676 var newCategoryColumn = {
10677 source: columnMetadata,
10678 values: concatenatedValues
10679 };
10680 // We expect every DataViewCategoryColumn in concatenationSourceColumns to have the same set of identities, always.
10681 // So, we'll just take the identities and identityFields from the first column
10682 var firstColumn = sourceColumnsSortedByProjectionOrdering[0];
10683 if (firstColumn.identity) {
10684 newCategoryColumn.identity = firstColumn.identity;
10685 }
10686 if (firstColumn.identityFields) {
10687 newCategoryColumn.identityFields = firstColumn.identityFields;
10688 }
10689 // It is safe to look at the first column as it is the one that is being set by findSelectedCategoricalColumn
10690 if (firstColumn.objects) {
10691 newCategoryColumn.objects = firstColumn.objects;
10692 }
10693 return newCategoryColumn;
10694 }
10695 })(DataViewConcatenateCategoricalColumns = data.DataViewConcatenateCategoricalColumns || (data.DataViewConcatenateCategoricalColumns = {}));
10696 })(data = powerbi.data || (powerbi.data = {}));
10697})(powerbi || (powerbi = {}));
10698/*
10699 * Power BI Visualizations
10700 *
10701 * Copyright (c) Microsoft Corporation
10702 * All rights reserved.
10703 * MIT License
10704 *
10705 * Permission is hereby granted, free of charge, to any person obtaining a copy
10706 * of this software and associated documentation files (the ""Software""), to deal
10707 * in the Software without restriction, including without limitation the rights
10708 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10709 * copies of the Software, and to permit persons to whom the Software is
10710 * furnished to do so, subject to the following conditions:
10711 *
10712 * The above copyright notice and this permission notice shall be included in
10713 * all copies or substantial portions of the Software.
10714 *
10715 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10716 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10717 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10718 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10719 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10720 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10721 * THE SOFTWARE.
10722 */
10723var powerbi;
10724(function (powerbi) {
10725 var DataViewMapping;
10726 (function (DataViewMapping) {
10727 function visitMapping(mapping, visitor) {
10728 debug.assertValue(mapping, 'mapping');
10729 debug.assertValue(visitor, 'visitor');
10730 var categorical = mapping.categorical;
10731 if (categorical)
10732 visitCategorical(categorical, visitor);
10733 var table = mapping.table;
10734 if (table)
10735 visitTable(table, visitor);
10736 var matrix = mapping.matrix;
10737 if (matrix)
10738 visitMatrix(matrix, visitor);
10739 var tree = mapping.tree;
10740 if (tree)
10741 visitTree(tree, visitor);
10742 var single = mapping.single;
10743 if (single)
10744 visitSingle(single, visitor);
10745 }
10746 DataViewMapping.visitMapping = visitMapping;
10747 function visitCategorical(mapping, visitor) {
10748 debug.assertValue(mapping, 'mapping');
10749 debug.assertValue(visitor, 'visitor');
10750 visitCategoricalCategories(mapping.categories, visitor);
10751 visitCategoricalValues(mapping.values, visitor);
10752 }
10753 DataViewMapping.visitCategorical = visitCategorical;
10754 function visitCategoricalCategories(mapping, visitor) {
10755 debug.assertAnyValue(mapping, 'mapping');
10756 debug.assertValue(visitor, 'visitor');
10757 if (mapping) {
10758 visitBind(mapping, visitor);
10759 visitFor(mapping, visitor);
10760 visitList(mapping, visitor);
10761 visitReduction(mapping, visitor);
10762 }
10763 }
10764 DataViewMapping.visitCategoricalCategories = visitCategoricalCategories;
10765 function visitCategoricalValues(mapping, visitor) {
10766 debug.assertAnyValue(mapping, 'mapping');
10767 debug.assertValue(visitor, 'visitor');
10768 if (mapping) {
10769 visitBind(mapping, visitor, 0 /* CategoricalValue */);
10770 visitFor(mapping, visitor, 0 /* CategoricalValue */);
10771 visitList(mapping, visitor, 0 /* CategoricalValue */);
10772 var groupedRoleMapping = mapping;
10773 visitGrouped(groupedRoleMapping, visitor);
10774 var group = groupedRoleMapping.group;
10775 if (group) {
10776 for (var _i = 0, _a = group.select; _i < _a.length; _i++) {
10777 var item = _a[_i];
10778 visitBind(item, visitor, 1 /* CategoricalValueGroup */);
10779 visitFor(item, visitor, 1 /* CategoricalValueGroup */);
10780 }
10781 }
10782 }
10783 }
10784 DataViewMapping.visitCategoricalValues = visitCategoricalValues;
10785 function visitTable(mapping, visitor) {
10786 debug.assertValue(mapping, 'mapping');
10787 debug.assertValue(visitor, 'visitor');
10788 var rows = mapping.rows;
10789 visitBind(rows, visitor);
10790 visitFor(rows, visitor);
10791 visitList(rows, visitor);
10792 visitReduction(rows, visitor);
10793 }
10794 DataViewMapping.visitTable = visitTable;
10795 function visitMatrix(mapping, visitor) {
10796 debug.assertValue(mapping, 'mapping');
10797 debug.assertValue(visitor, 'visitor');
10798 visitMatrixItems(mapping.rows, visitor);
10799 visitMatrixItems(mapping.columns, visitor);
10800 visitMatrixItems(mapping.values, visitor);
10801 }
10802 /**
10803 * For visiting DataViewMatrixMapping.rows, DataViewMatrixMapping.columns, or DataViewMatrixMapping.values.
10804 *
10805 * @param mapping Can be one of DataViewMatrixMapping.rows, DataViewMatrixMapping.columns, or DataViewMatrixMapping.values.
10806 * @param visitor The visitor.
10807 */
10808 function visitMatrixItems(mapping, visitor) {
10809 debug.assertAnyValue(mapping, 'mapping');
10810 debug.assertValue(visitor, 'visitor');
10811 if (mapping) {
10812 visitFor(mapping, visitor);
10813 visitList(mapping, visitor);
10814 visitReduction(mapping, visitor);
10815 }
10816 }
10817 DataViewMapping.visitMatrixItems = visitMatrixItems;
10818 function visitTree(mapping, visitor) {
10819 debug.assertValue(mapping, 'mapping');
10820 debug.assertValue(visitor, 'visitor');
10821 visitTreeNodes(mapping.nodes, visitor);
10822 visitTreeValues(mapping.values, visitor);
10823 }
10824 function visitTreeNodes(mapping, visitor) {
10825 debug.assertAnyValue(mapping, 'mapping');
10826 debug.assertValue(visitor, 'visitor');
10827 if (mapping) {
10828 visitFor(mapping, visitor);
10829 visitReduction(mapping, visitor);
10830 }
10831 }
10832 DataViewMapping.visitTreeNodes = visitTreeNodes;
10833 function visitTreeValues(mapping, visitor) {
10834 debug.assertAnyValue(mapping, 'mapping');
10835 debug.assertValue(visitor, 'visitor');
10836 if (mapping) {
10837 visitFor(mapping, visitor);
10838 }
10839 }
10840 DataViewMapping.visitTreeValues = visitTreeValues;
10841 function visitBind(mapping, visitor, context) {
10842 debug.assertValue(mapping, 'mapping');
10843 debug.assertValue(visitor, 'visitor');
10844 var bind = mapping.bind;
10845 if (bind) {
10846 if (context != null)
10847 visitor.visitRole(bind.to, context);
10848 else
10849 visitor.visitRole(bind.to);
10850 }
10851 }
10852 function visitFor(mapping, visitor, context) {
10853 debug.assertValue(mapping, 'mapping');
10854 debug.assertValue(visitor, 'visitor');
10855 var forValue = mapping.for;
10856 if (forValue) {
10857 if (context != null)
10858 visitor.visitRole(forValue.in, context);
10859 else
10860 visitor.visitRole(forValue.in);
10861 }
10862 }
10863 function visitList(mapping, visitor, context) {
10864 debug.assertValue(mapping, 'mapping');
10865 debug.assertValue(visitor, 'visitor');
10866 var select = mapping.select;
10867 if (select) {
10868 for (var _i = 0, select_1 = select; _i < select_1.length; _i++) {
10869 var item = select_1[_i];
10870 visitBind(item, visitor, context);
10871 visitFor(item, visitor, context);
10872 }
10873 }
10874 }
10875 function visitGrouped(mapping, visitor) {
10876 debug.assertAnyValue(mapping, 'mapping');
10877 debug.assertValue(visitor, 'visitor');
10878 if (!mapping)
10879 return;
10880 var group = mapping.group;
10881 if (group) {
10882 visitor.visitRole(group.by);
10883 visitReduction(group, visitor);
10884 }
10885 }
10886 DataViewMapping.visitGrouped = visitGrouped;
10887 function visitReduction(mapping, visitor) {
10888 debug.assertValue(mapping, 'mapping');
10889 debug.assertValue(visitor, 'visitor');
10890 if (visitor.visitReduction) {
10891 var reductionAlgorithm = mapping.dataReductionAlgorithm;
10892 if (reductionAlgorithm) {
10893 visitor.visitReduction(reductionAlgorithm);
10894 }
10895 }
10896 }
10897 function visitSingle(mapping, visitor) {
10898 debug.assertValue(mapping, 'mapping');
10899 debug.assertValue(visitor, 'visitor');
10900 visitor.visitRole(mapping.role);
10901 }
10902 })(DataViewMapping = powerbi.DataViewMapping || (powerbi.DataViewMapping = {}));
10903})(powerbi || (powerbi = {}));
10904/*
10905 * Power BI Visualizations
10906 *
10907 * Copyright (c) Microsoft Corporation
10908 * All rights reserved.
10909 * MIT License
10910 *
10911 * Permission is hereby granted, free of charge, to any person obtaining a copy
10912 * of this software and associated documentation files (the ""Software""), to deal
10913 * in the Software without restriction, including without limitation the rights
10914 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10915 * copies of the Software, and to permit persons to whom the Software is
10916 * furnished to do so, subject to the following conditions:
10917 *
10918 * The above copyright notice and this permission notice shall be included in
10919 * all copies or substantial portions of the Software.
10920 *
10921 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10922 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10923 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10924 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10925 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10926 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10927 * THE SOFTWARE.
10928 */
10929var powerbi;
10930(function (powerbi) {
10931 var data;
10932 (function (data) {
10933 var inheritSingle = powerbi.Prototype.inheritSingle;
10934 var DataViewNormalizeValues;
10935 (function (DataViewNormalizeValues) {
10936 function apply(options) {
10937 debug.assertValue(options, 'options');
10938 var rolesToNormalize = _.filter(options.dataRoles, function (role) { return !_.isEmpty(role.requiredTypes); });
10939 filterVariantMeasures(options.dataview, options.dataViewMappings, rolesToNormalize);
10940 }
10941 DataViewNormalizeValues.apply = apply;
10942 function filterVariantMeasures(dataview, dataViewMappings, rolesToNormalize) {
10943 debug.assertValue(dataview, 'dataview');
10944 // Don't perform this unless we actually have dataViewMappings and variant measures to suppress
10945 // When we switch to lazy per-visual DataView creation, we'll be able to remove this check.
10946 if (_.isEmpty(dataViewMappings) || _.isEmpty(rolesToNormalize))
10947 return;
10948 var columnFilter = generateMetadataColumnFilter(dataview.metadata.columns, rolesToNormalize);
10949 var valueFilter = generateValueFilter(dataview.metadata.columns, rolesToNormalize);
10950 var usedMappings = {};
10951 for (var _i = 0, dataViewMappings_1 = dataViewMappings; _i < dataViewMappings_1.length; _i++) {
10952 var dataViewMapping = dataViewMappings_1[_i];
10953 // Get dataview specified in mappings which are also in dataview
10954 for (var dataViewMappingProp in dataViewMapping) {
10955 if (dataview[dataViewMappingProp] != null)
10956 usedMappings[dataViewMappingProp] = true;
10957 }
10958 }
10959 if (usedMappings['categorical'])
10960 filterVariantMeasuresCategorical(dataview.categorical, columnFilter, valueFilter);
10961 if (usedMappings['table'])
10962 filterVariantMeasuresTable(dataview.table, columnFilter, valueFilter);
10963 if (usedMappings['tree'])
10964 filterVariantMeasuresTreeNode(dataview.tree.root, columnFilter, valueFilter);
10965 if (usedMappings['matrix'])
10966 filterVariantMeasuresMatrix(dataview.matrix, columnFilter, valueFilter);
10967 if (usedMappings['single'])
10968 filterVariantMeasuresSingle(dataview, dataViewMappings, rolesToNormalize, valueFilter);
10969 }
10970 DataViewNormalizeValues.filterVariantMeasures = filterVariantMeasures;
10971 function generateMetadataColumnFilter(columns, rolesToNormalize) {
10972 if (!columns || !rolesToNormalize)
10973 return function () { return false; };
10974 var columnsToNormalize = {};
10975 for (var _i = 0, columns_2 = columns; _i < columns_2.length; _i++) {
10976 var column = columns_2[_i];
10977 var roles = column.roles;
10978 if (!roles)
10979 continue;
10980 for (var _a = 0, rolesToNormalize_1 = rolesToNormalize; _a < rolesToNormalize_1.length; _a++) {
10981 var role = rolesToNormalize_1[_a];
10982 if (!roles[role.name])
10983 continue;
10984 columnsToNormalize[column.index] = true;
10985 break;
10986 }
10987 }
10988 return function (columnIndex) {
10989 if (isNaN(columnIndex))
10990 return false;
10991 return !!columnsToNormalize[columnIndex];
10992 };
10993 }
10994 DataViewNormalizeValues.generateMetadataColumnFilter = generateMetadataColumnFilter;
10995 function generateValueFilter(columns, rolesToNormalize) {
10996 if (!columns || !rolesToNormalize)
10997 return function () { return true; };
10998 var columnValueFilters = [];
10999 // Build columnValueFilters based on role requiredTypes
11000 for (var _i = 0, columns_3 = columns; _i < columns_3.length; _i++) {
11001 var column = columns_3[_i];
11002 var columnValueFilter = generateColumnValueFilter(column, rolesToNormalize);
11003 if (columnValueFilter)
11004 columnValueFilters[column.index] = columnValueFilter;
11005 }
11006 return function (columnIndex, value) {
11007 if (columnValueFilters[columnIndex])
11008 return columnValueFilters[columnIndex](value);
11009 return true;
11010 };
11011 }
11012 DataViewNormalizeValues.generateValueFilter = generateValueFilter;
11013 function generateColumnValueFilter(column, rolesToNormalize) {
11014 var requiredTypes = getColumnRequiredTypes(column, rolesToNormalize);
11015 if (_.isEmpty(requiredTypes))
11016 return;
11017 return function (value) {
11018 return doesValueMatchTypes(value, requiredTypes);
11019 };
11020 }
11021 function getColumnRequiredTypes(column, rolesToNormalize) {
11022 var requiredTypes = [];
11023 var columnRoles = column && column.roles;
11024 if (!columnRoles)
11025 return requiredTypes;
11026 for (var _i = 0, rolesToNormalize_2 = rolesToNormalize; _i < rolesToNormalize_2.length; _i++) {
11027 var role = rolesToNormalize_2[_i];
11028 if (!columnRoles[role.name])
11029 continue;
11030 for (var _a = 0, _b = role.requiredTypes; _a < _b.length; _a++) {
11031 var typeDescriptor = _b[_a];
11032 var type = powerbi.ValueType.fromDescriptor(typeDescriptor);
11033 requiredTypes.push(type);
11034 }
11035 }
11036 return requiredTypes;
11037 }
11038 DataViewNormalizeValues.getColumnRequiredTypes = getColumnRequiredTypes;
11039 function filterVariantMeasuresCategorical(dataview, columnFilter, valueFilter) {
11040 var values = dataview && dataview.values;
11041 if (!values)
11042 return;
11043 var valuesGrouped = values.grouped();
11044 if (!valuesGrouped)
11045 return;
11046 for (var _i = 0, valuesGrouped_1 = valuesGrouped; _i < valuesGrouped_1.length; _i++) {
11047 var valueGroup = valuesGrouped_1[_i];
11048 var valuesInGroup = valueGroup.values;
11049 for (var _a = 0, valuesInGroup_1 = valuesInGroup; _a < valuesInGroup_1.length; _a++) {
11050 var valueColumn = valuesInGroup_1[_a];
11051 var columnIndex = valueColumn.source.index;
11052 if (!columnFilter(columnIndex))
11053 continue;
11054 for (var i = 0, ilen = valueColumn.values.length; i < ilen; i++) {
11055 valueColumn.values = normalizeVariant(valueColumn.values, i, columnIndex, valueFilter);
11056 }
11057 }
11058 }
11059 }
11060 function filterVariantMeasuresTable(dataview, columnFilter, valueFilter) {
11061 var columns = dataview && dataview.columns;
11062 if (!columns)
11063 return;
11064 var filteredColumns = [];
11065 for (var _i = 0, columns_4 = columns; _i < columns_4.length; _i++) {
11066 var column = columns_4[_i];
11067 if (columnFilter(column.index))
11068 filteredColumns.push(column.index);
11069 }
11070 var rows = dataview.rows;
11071 for (var i = 0, ilen = rows.length; i < ilen; i++) {
11072 for (var _a = 0, filteredColumns_1 = filteredColumns; _a < filteredColumns_1.length; _a++) {
11073 var index = filteredColumns_1[_a];
11074 rows[i] = normalizeVariant(rows[i], index, index, valueFilter);
11075 }
11076 }
11077 }
11078 function filterVariantMeasuresTreeNode(node, columnFilter, valueFilter) {
11079 if (node.values) {
11080 for (var columnIndex in node.values) {
11081 // In dataView.tree, the keys in node.values correspond to columnIndex of the node value
11082 if (columnFilter(columnIndex)) {
11083 // According to nojorgen, it is possible to have primitive values as values in the node.values dictionary.
11084 if (typeof (node.values[columnIndex]) === 'object' && ('value' in node.values[columnIndex]))
11085 node.values[columnIndex] = normalizeVariant(node.values[columnIndex], 'value', columnIndex, valueFilter);
11086 else
11087 node.values = normalizeVariant(node.values, columnIndex, columnIndex, valueFilter);
11088 }
11089 }
11090 }
11091 else if (node.children) {
11092 for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
11093 var child = _a[_i];
11094 filterVariantMeasuresTreeNode(child, columnFilter, valueFilter);
11095 }
11096 }
11097 }
11098 function filterVariantMeasuresMatrix(dataview, columnFilter, valueFilter) {
11099 var root = dataview && dataview.rows && dataview.rows.root;
11100 if (!root)
11101 return;
11102 // Recurse into rows.children
11103 // e.g. rows.children -> .children -> .children.values
11104 filterVariantMeasuresMatrixRecursive(dataview, root, columnFilter, valueFilter);
11105 }
11106 function filterVariantMeasuresMatrixRecursive(dataviewMatrix, node, columnFilter, valueFilter) {
11107 if (node.values) {
11108 for (var id in node.values) {
11109 // Note related to VSTS 6547124: In dataView.matrix, the keys in node.values are NOT equivalent to value.valueSourceIndex.
11110 var nodeValue = node.values[id];
11111 // the property DataViewMatrixNodeValue.valueSourceIndex will not exist if valueSourceIndex is 0 for that value
11112 var valueSourceIndex = nodeValue.valueSourceIndex || 0;
11113 // index is an optional property on DataViewMetadataColumn, but I am not sure when it will ever be undefined in a matrix' column metadata
11114 var columnIndex = dataviewMatrix.valueSources[valueSourceIndex].index;
11115 if (_.isNumber(columnIndex) && columnFilter(columnIndex)) {
11116 node.values[id] = normalizeVariant(nodeValue, 'value', columnIndex, valueFilter);
11117 }
11118 }
11119 }
11120 else if (node.children) {
11121 for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
11122 var child = _a[_i];
11123 filterVariantMeasuresMatrixRecursive(dataviewMatrix, child, columnFilter, valueFilter);
11124 }
11125 }
11126 }
11127 function filterVariantMeasuresSingle(dataview, dataViewMappings, rolesToNormalize, valueFilter) {
11128 if (!dataview.single)
11129 return;
11130 var roleNames = [];
11131 for (var _i = 0, rolesToNormalize_3 = rolesToNormalize; _i < rolesToNormalize_3.length; _i++) {
11132 var role = rolesToNormalize_3[_i];
11133 if (role.name)
11134 roleNames.push(role.name);
11135 }
11136 var columns = dataview.metadata.columns;
11137 for (var _a = 0, dataViewMappings_2 = dataViewMappings; _a < dataViewMappings_2.length; _a++) {
11138 var dataViewMapping = dataViewMappings_2[_a];
11139 var roleName = dataViewMapping.single.role;
11140 if (roleNames.indexOf(roleName) !== -1) {
11141 var column = firstColumnByRoleName(columns, roleName);
11142 if (column)
11143 dataview.single = normalizeVariant(dataview.single, 'value', column.index, valueFilter);
11144 return;
11145 }
11146 }
11147 }
11148 function normalizeVariant(object, key, columnIndex, valueFilter) {
11149 if (!object)
11150 return;
11151 var value = object[key];
11152 if (value !== null && !valueFilter(columnIndex, value)) {
11153 object = inheritSingle(object);
11154 object[key] = null;
11155 }
11156 return object;
11157 }
11158 DataViewNormalizeValues.normalizeVariant = normalizeVariant;
11159 function doesValueMatchTypes(value, types) {
11160 for (var _i = 0, types_1 = types; _i < types_1.length; _i++) {
11161 var type = types_1[_i];
11162 if (type.numeric || type.integer)
11163 return typeof (value) === 'number';
11164 }
11165 return false;
11166 }
11167 function firstColumnByRoleName(columns, roleName) {
11168 for (var _i = 0, columns_5 = columns; _i < columns_5.length; _i++) {
11169 var column = columns_5[_i];
11170 var columnRoles = column && column.roles;
11171 if (columnRoles && columnRoles[roleName])
11172 return column;
11173 }
11174 }
11175 })(DataViewNormalizeValues = data.DataViewNormalizeValues || (data.DataViewNormalizeValues = {}));
11176 })(data = powerbi.data || (powerbi.data = {}));
11177})(powerbi || (powerbi = {}));
11178/*
11179 * Power BI Visualizations
11180 *
11181 * Copyright (c) Microsoft Corporation
11182 * All rights reserved.
11183 * MIT License
11184 *
11185 * Permission is hereby granted, free of charge, to any person obtaining a copy
11186 * of this software and associated documentation files (the ""Software""), to deal
11187 * in the Software without restriction, including without limitation the rights
11188 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11189 * copies of the Software, and to permit persons to whom the Software is
11190 * furnished to do so, subject to the following conditions:
11191 *
11192 * The above copyright notice and this permission notice shall be included in
11193 * all copies or substantial portions of the Software.
11194 *
11195 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11196 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11197 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11198 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11199 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11200 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11201 * THE SOFTWARE.
11202 */
11203var powerbi;
11204(function (powerbi) {
11205 var DataViewObjects;
11206 (function (DataViewObjects) {
11207 /** Gets the value of the given object/property pair. */
11208 function getValue(objects, propertyId, defaultValue) {
11209 debug.assertAnyValue(objects, 'objects');
11210 debug.assertValue(propertyId, 'propertyId');
11211 if (!objects)
11212 return defaultValue;
11213 var objectOrMap = objects[propertyId.objectName];
11214 debug.assert(!isUserDefined(objectOrMap), 'expected DataViewObject');
11215 var object = objectOrMap;
11216 return DataViewObject.getValue(object, propertyId.propertyName, defaultValue);
11217 }
11218 DataViewObjects.getValue = getValue;
11219 /** Gets an object from objects. */
11220 function getObject(objects, objectName, defaultValue) {
11221 if (objects && objects[objectName]) {
11222 var object = objects[objectName];
11223 debug.assert(!isUserDefined(object), 'expected DataViewObject');
11224 return object;
11225 }
11226 else {
11227 return defaultValue;
11228 }
11229 }
11230 DataViewObjects.getObject = getObject;
11231 /** Gets a map of user-defined objects. */
11232 function getUserDefinedObjects(objects, objectName) {
11233 if (objects && objects[objectName]) {
11234 var map = objects[objectName];
11235 debug.assert(isUserDefined(map), 'expected DataViewObjectMap');
11236 return map;
11237 }
11238 }
11239 DataViewObjects.getUserDefinedObjects = getUserDefinedObjects;
11240 /** Gets the solid color from a fill property. */
11241 function getFillColor(objects, propertyId, defaultColor) {
11242 var value = getValue(objects, propertyId);
11243 if (!value || !value.solid)
11244 return defaultColor;
11245 return value.solid.color;
11246 }
11247 DataViewObjects.getFillColor = getFillColor;
11248 /** Returns true if the given object represents a collection of user-defined objects */
11249 function isUserDefined(objectOrMap) {
11250 return _.isArray(objectOrMap);
11251 }
11252 DataViewObjects.isUserDefined = isUserDefined;
11253 })(DataViewObjects = powerbi.DataViewObjects || (powerbi.DataViewObjects = {}));
11254 var DataViewObject;
11255 (function (DataViewObject) {
11256 function getValue(object, propertyName, defaultValue) {
11257 debug.assertAnyValue(object, 'object');
11258 debug.assertValue(propertyName, 'propertyName');
11259 if (!object)
11260 return defaultValue;
11261 var propertyValue = object[propertyName];
11262 if (propertyValue === undefined)
11263 return defaultValue;
11264 return propertyValue;
11265 }
11266 DataViewObject.getValue = getValue;
11267 /** Gets the solid color from a fill property using only a propertyName */
11268 function getFillColorByPropertyName(objects, propertyName, defaultColor) {
11269 var value = DataViewObject.getValue(objects, propertyName);
11270 if (!value || !value.solid)
11271 return defaultColor;
11272 return value.solid.color;
11273 }
11274 DataViewObject.getFillColorByPropertyName = getFillColorByPropertyName;
11275 })(DataViewObject = powerbi.DataViewObject || (powerbi.DataViewObject = {}));
11276})(powerbi || (powerbi = {}));
11277/*
11278 * Power BI Visualizations
11279 *
11280 * Copyright (c) Microsoft Corporation
11281 * All rights reserved.
11282 * MIT License
11283 *
11284 * Permission is hereby granted, free of charge, to any person obtaining a copy
11285 * of this software and associated documentation files (the ""Software""), to deal
11286 * in the Software without restriction, including without limitation the rights
11287 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11288 * copies of the Software, and to permit persons to whom the Software is
11289 * furnished to do so, subject to the following conditions:
11290 *
11291 * The above copyright notice and this permission notice shall be included in
11292 * all copies or substantial portions of the Software.
11293 *
11294 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11295 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11296 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11297 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11298 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11299 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11300 * THE SOFTWARE.
11301 */
11302var powerbi;
11303(function (powerbi) {
11304 var data;
11305 (function (data) {
11306 var JsonComparer = jsCommon.JsonComparer;
11307 var DataViewObjectDefinitions;
11308 (function (DataViewObjectDefinitions) {
11309 /** Creates or reuses a DataViewObjectDefinition for matching the given objectName and selector within the defns. */
11310 function ensure(defns, objectName, selector) {
11311 debug.assertValue(defns, 'defns');
11312 var defnsForObject = defns[objectName];
11313 if (!defnsForObject)
11314 defns[objectName] = defnsForObject = [];
11315 for (var i = 0, len = defnsForObject.length; i < len; i++) {
11316 var defn = defnsForObject[i];
11317 if (data.Selector.equals(defn.selector, selector))
11318 return defn;
11319 }
11320 var newDefn = {
11321 selector: selector,
11322 properties: {},
11323 };
11324 defnsForObject.push(newDefn);
11325 return newDefn;
11326 }
11327 DataViewObjectDefinitions.ensure = ensure;
11328 function deleteProperty(defns, objectName, selector, propertyName) {
11329 debug.assertValue(defns, 'defns');
11330 var defn = getObjectDefinition(defns, objectName, selector);
11331 if (!defn)
11332 return;
11333 DataViewObjectDefinition.deleteSingleProperty(defn, propertyName);
11334 }
11335 DataViewObjectDefinitions.deleteProperty = deleteProperty;
11336 function setValue(defns, propertyId, selector, value) {
11337 debug.assertValue(defns, 'defns');
11338 debug.assertValue(propertyId, 'propertyId');
11339 ensure(defns, propertyId.objectName, selector).properties[propertyId.propertyName] = value;
11340 }
11341 DataViewObjectDefinitions.setValue = setValue;
11342 function getValue(defns, propertyId, selector) {
11343 var properties = getPropertyContainer(defns, propertyId, selector);
11344 if (!properties)
11345 return;
11346 return properties[propertyId.propertyName];
11347 }
11348 DataViewObjectDefinitions.getValue = getValue;
11349 function getPropertyContainer(defns, propertyId, selector) {
11350 var defn = getObjectDefinition(defns, propertyId.objectName, selector);
11351 if (!defn)
11352 return;
11353 return defn.properties;
11354 }
11355 DataViewObjectDefinitions.getPropertyContainer = getPropertyContainer;
11356 function getObjectDefinition(defns, objectName, selector) {
11357 debug.assertAnyValue(defns, 'defns');
11358 debug.assertValue(objectName, 'objectName');
11359 debug.assertAnyValue(selector, 'selector');
11360 if (!defns)
11361 return;
11362 var defnsForObject = defns[objectName];
11363 if (!defnsForObject)
11364 return;
11365 for (var i = 0, len = defnsForObject.length; i < len; i++) {
11366 var defn = defnsForObject[i];
11367 if (data.Selector.equals(defn.selector, selector))
11368 return defn;
11369 }
11370 }
11371 DataViewObjectDefinitions.getObjectDefinition = getObjectDefinition;
11372 function propertiesAreEqual(a, b) {
11373 if (a instanceof data.SemanticFilter && b instanceof data.SemanticFilter) {
11374 return data.SemanticFilter.isSameFilter(a, b);
11375 }
11376 return JsonComparer.equals(a, b);
11377 }
11378 DataViewObjectDefinitions.propertiesAreEqual = propertiesAreEqual;
11379 function allPropertiesAreEqual(a, b) {
11380 debug.assertValue(a, 'a');
11381 debug.assertValue(b, 'b');
11382 if (Object.keys(a).length !== Object.keys(b).length)
11383 return false;
11384 for (var property in a) {
11385 if (!propertiesAreEqual(a[property], b[property]))
11386 return false;
11387 }
11388 return true;
11389 }
11390 DataViewObjectDefinitions.allPropertiesAreEqual = allPropertiesAreEqual;
11391 function encodePropertyValue(value, valueTypeDescriptor) {
11392 debug.assertAnyValue(value, 'value');
11393 debug.assertValue(valueTypeDescriptor, 'valueTypeDescriptor');
11394 if (valueTypeDescriptor.bool) {
11395 if (typeof (value) !== 'boolean')
11396 value = false; // This is fallback, which doesn't really belong here.
11397 return data.SQExprBuilder.boolean(value);
11398 }
11399 else if (valueTypeDescriptor.text || (valueTypeDescriptor.scripting && valueTypeDescriptor.scripting.source)) {
11400 return data.SQExprBuilder.text(value);
11401 }
11402 else if (valueTypeDescriptor.numeric) {
11403 if ($.isNumeric(value))
11404 return data.SQExprBuilder.double(+value);
11405 }
11406 else if (valueTypeDescriptor.fill) {
11407 if (value) {
11408 return {
11409 solid: { color: data.SQExprBuilder.text(value) }
11410 };
11411 }
11412 }
11413 else if (valueTypeDescriptor.formatting) {
11414 if (valueTypeDescriptor.formatting.labelDisplayUnits) {
11415 return data.SQExprBuilder.double(+value);
11416 }
11417 else {
11418 return data.SQExprBuilder.text(value);
11419 }
11420 }
11421 else if (valueTypeDescriptor.enumeration) {
11422 if ($.isNumeric(value))
11423 return data.SQExprBuilder.double(+value);
11424 else
11425 return data.SQExprBuilder.text(value);
11426 }
11427 else if (valueTypeDescriptor.misc) {
11428 if (value) {
11429 value = data.SQExprBuilder.text(value);
11430 }
11431 else {
11432 value = null;
11433 }
11434 }
11435 else if (valueTypeDescriptor.image) {
11436 if (value) {
11437 var imageValue = value;
11438 var imageDefinition = {
11439 name: data.SQExprBuilder.text(imageValue.name),
11440 url: data.SQExprBuilder.text(imageValue.url),
11441 };
11442 if (imageValue.scaling)
11443 imageDefinition.scaling = data.SQExprBuilder.text(imageValue.scaling);
11444 return imageDefinition;
11445 }
11446 }
11447 return value;
11448 }
11449 DataViewObjectDefinitions.encodePropertyValue = encodePropertyValue;
11450 function clone(original) {
11451 debug.assertValue(original, 'original');
11452 var cloned = {};
11453 for (var objectName in original) {
11454 var originalDefns = original[objectName];
11455 if (_.isEmpty(originalDefns))
11456 continue;
11457 var clonedDefns = [];
11458 for (var _i = 0, originalDefns_1 = originalDefns; _i < originalDefns_1.length; _i++) {
11459 var originalDefn = originalDefns_1[_i];
11460 clonedDefns.push({
11461 properties: cloneProperties(originalDefn.properties),
11462 selector: originalDefn.selector,
11463 });
11464 }
11465 cloned[objectName] = clonedDefns;
11466 }
11467 return cloned;
11468 }
11469 DataViewObjectDefinitions.clone = clone;
11470 function cloneProperties(original) {
11471 debug.assertValue(original, 'original');
11472 // NOTE: properties are considered atomic, so a shallow clone is appropriate here.
11473 return _.clone(original);
11474 }
11475 })(DataViewObjectDefinitions = data.DataViewObjectDefinitions || (data.DataViewObjectDefinitions = {}));
11476 var DataViewObjectDefinition;
11477 (function (DataViewObjectDefinition) {
11478 function deleteSingleProperty(defn, propertyName) {
11479 //note: We decided that delete is acceptable here and that we don't need optimization here
11480 delete defn.properties[propertyName];
11481 }
11482 DataViewObjectDefinition.deleteSingleProperty = deleteSingleProperty;
11483 })(DataViewObjectDefinition = data.DataViewObjectDefinition || (data.DataViewObjectDefinition = {}));
11484 })(data = powerbi.data || (powerbi.data = {}));
11485})(powerbi || (powerbi = {}));
11486/*
11487 * Power BI Visualizations
11488 *
11489 * Copyright (c) Microsoft Corporation
11490 * All rights reserved.
11491 * MIT License
11492 *
11493 * Permission is hereby granted, free of charge, to any person obtaining a copy
11494 * of this software and associated documentation files (the ""Software""), to deal
11495 * in the Software without restriction, including without limitation the rights
11496 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11497 * copies of the Software, and to permit persons to whom the Software is
11498 * furnished to do so, subject to the following conditions:
11499 *
11500 * The above copyright notice and this permission notice shall be included in
11501 * all copies or substantial portions of the Software.
11502 *
11503 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11504 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11505 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11506 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11507 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11508 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11509 * THE SOFTWARE.
11510 */
11511var powerbi;
11512(function (powerbi) {
11513 var data;
11514 (function (data) {
11515 var DataViewObjectDescriptors;
11516 (function (DataViewObjectDescriptors) {
11517 /** Attempts to find the format string property. This can be useful for upgrade and conversion. */
11518 function findFormatString(descriptors) {
11519 return findProperty(descriptors, function (propDesc) {
11520 var formattingTypeDesc = powerbi.ValueType.fromDescriptor(propDesc.type).formatting;
11521 return formattingTypeDesc && formattingTypeDesc.formatString;
11522 });
11523 }
11524 DataViewObjectDescriptors.findFormatString = findFormatString;
11525 /** Attempts to find the filter property. This can be useful for propagating filters from one visual to others. */
11526 function findFilterOutput(descriptors) {
11527 return findProperty(descriptors, function (propDesc) {
11528 var propType = propDesc.type;
11529 return propType && !!propType.filter;
11530 });
11531 }
11532 DataViewObjectDescriptors.findFilterOutput = findFilterOutput;
11533 /** Attempts to find the default value property. This can be useful for propagating schema default value. */
11534 function findDefaultValue(descriptors) {
11535 return findProperty(descriptors, function (propDesc) {
11536 var propType = propDesc.type;
11537 return propType && !!propType.expression && propType.expression.defaultValue;
11538 });
11539 }
11540 DataViewObjectDescriptors.findDefaultValue = findDefaultValue;
11541 function findProperty(descriptors, propPredicate) {
11542 debug.assertAnyValue(descriptors, 'descriptors');
11543 debug.assertAnyValue(propPredicate, 'propPredicate');
11544 if (!descriptors)
11545 return;
11546 for (var objectName in descriptors) {
11547 var objPropDescs = descriptors[objectName].properties;
11548 for (var propertyName in objPropDescs) {
11549 if (propPredicate(objPropDescs[propertyName])) {
11550 return {
11551 objectName: objectName,
11552 propertyName: propertyName,
11553 };
11554 }
11555 }
11556 }
11557 }
11558 })(DataViewObjectDescriptors = data.DataViewObjectDescriptors || (data.DataViewObjectDescriptors = {}));
11559 })(data = powerbi.data || (powerbi.data = {}));
11560})(powerbi || (powerbi = {}));
11561/*
11562* Power BI Visualizations
11563*
11564* Copyright (c) Microsoft Corporation
11565* All rights reserved.
11566 * MIT License
11567*
11568* Permission is hereby granted, free of charge, to any person obtaining a copy
11569* of this software and associated documentation files (the ""Software""), to deal
11570* in the Software without restriction, including without limitation the rights
11571* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11572* copies of the Software, and to permit persons to whom the Software is
11573* furnished to do so, subject to the following conditions:
11574*
11575 * The above copyright notice and this permission notice shall be included in
11576 * all copies or substantial portions of the Software.
11577*
11578 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11579 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11580 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11581 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11582 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11583* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11584* THE SOFTWARE.
11585*/
11586var powerbi;
11587(function (powerbi) {
11588 var data;
11589 (function (data) {
11590 var DataViewObjectEvaluationUtils;
11591 (function (DataViewObjectEvaluationUtils) {
11592 function evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns) {
11593 debug.assertValue(evalContext, 'evalContext');
11594 debug.assertValue(objectDescriptors, 'objectDescriptors');
11595 debug.assertValue(objectDefns, 'objectDefns');
11596 var objects;
11597 for (var j = 0, jlen = objectDefns.length; j < jlen; j++) {
11598 var objectDefinition = objectDefns[j], objectName = objectDefinition.name;
11599 var evaluatedObject = data.DataViewObjectEvaluator.run(evalContext, objectDescriptors[objectName], objectDefinition.properties);
11600 if (!evaluatedObject)
11601 continue;
11602 if (!objects)
11603 objects = {};
11604 // NOTE: this currently has last-object-wins semantics.
11605 objects[objectName] = evaluatedObject;
11606 }
11607 return objects;
11608 }
11609 DataViewObjectEvaluationUtils.evaluateDataViewObjects = evaluateDataViewObjects;
11610 function groupObjectsBySelector(objectDefinitions) {
11611 debug.assertAnyValue(objectDefinitions, 'objectDefinitions');
11612 var grouped = {
11613 data: [],
11614 };
11615 if (objectDefinitions) {
11616 for (var objectName in objectDefinitions) {
11617 var objectDefnList = objectDefinitions[objectName];
11618 for (var i = 0, len = objectDefnList.length; i < len; i++) {
11619 var objectDefn = objectDefnList[i];
11620 ensureDefinitionListForSelector(grouped, objectDefn.selector).objects.push({
11621 name: objectName,
11622 properties: objectDefn.properties,
11623 });
11624 }
11625 }
11626 }
11627 return grouped;
11628 }
11629 DataViewObjectEvaluationUtils.groupObjectsBySelector = groupObjectsBySelector;
11630 function ensureDefinitionListForSelector(grouped, selector) {
11631 debug.assertValue(grouped, 'grouped');
11632 debug.assertAnyValue(selector, 'selector');
11633 if (!selector) {
11634 if (!grouped.metadataOnce)
11635 grouped.metadataOnce = { objects: [] };
11636 return grouped.metadataOnce;
11637 }
11638 var groupedObjects;
11639 if (selector.data) {
11640 groupedObjects = grouped.data;
11641 }
11642 else if (selector.metadata) {
11643 if (!grouped.metadata)
11644 grouped.metadata = [];
11645 groupedObjects = grouped.metadata;
11646 }
11647 else if (selector.id) {
11648 if (!grouped.userDefined)
11649 grouped.userDefined = [];
11650 groupedObjects = grouped.userDefined;
11651 }
11652 debug.assert(!!groupedObjects, 'GroupedObjects is not defined. Indicates malformed selector.');
11653 for (var _i = 0, groupedObjects_1 = groupedObjects; _i < groupedObjects_1.length; _i++) {
11654 var item_1 = groupedObjects_1[_i];
11655 if (data.Selector.equals(selector, item_1.selector))
11656 return item_1;
11657 }
11658 var item = {
11659 selector: selector,
11660 objects: [],
11661 };
11662 groupedObjects.push(item);
11663 return item;
11664 }
11665 function addImplicitObjects(objectsForAllSelectors, objectDescriptors, columns, selectTransforms) {
11666 debug.assertValue(objectsForAllSelectors, 'objectsForAllSelectors');
11667 debug.assertValue(objectDescriptors, 'objectDescriptors');
11668 debug.assertValue(columns, 'columns');
11669 debug.assertAnyValue(selectTransforms, 'selectTransforms');
11670 if (selectTransforms) {
11671 addDefaultFormatString(objectsForAllSelectors, objectDescriptors, columns, selectTransforms);
11672 addDefaultValue(objectsForAllSelectors, objectDescriptors, columns, selectTransforms);
11673 }
11674 }
11675 DataViewObjectEvaluationUtils.addImplicitObjects = addImplicitObjects;
11676 function addDefaultFormatString(objectsForAllSelectors, objectDescriptors, columns, selectTransforms) {
11677 debug.assertValue(objectsForAllSelectors, 'objectsForAllSelectors');
11678 debug.assertValue(objectDescriptors, 'objectDescriptors');
11679 debug.assertValue(columns, 'columns');
11680 debug.assertValue(selectTransforms, 'selectTransforms');
11681 var formatStringProp = data.DataViewObjectDescriptors.findFormatString(objectDescriptors);
11682 if (!formatStringProp)
11683 return;
11684 for (var selectIdx = 0, selectLen = selectTransforms.length; selectIdx < selectLen; selectIdx++) {
11685 var selectTransform = selectTransforms[selectIdx];
11686 if (!selectTransform)
11687 continue;
11688 debug.assertValue(selectTransform.queryName, 'selectTransform.queryName');
11689 applyFormatString(objectsForAllSelectors, formatStringProp, selectTransform.queryName, selectTransform.format || getColumnFormatForIndex(columns, selectIdx));
11690 }
11691 }
11692 /** Registers properties for default value, if the properties are not explicitly provided. */
11693 function addDefaultValue(objectsForAllSelectors, objectDescriptors, columns, selectTransforms) {
11694 debug.assertValue(objectsForAllSelectors, 'objectsForAllSelectors');
11695 debug.assertValue(objectDescriptors, 'objectDescriptors');
11696 debug.assertValue(columns, 'columns');
11697 debug.assertValue(selectTransforms, 'selectTransforms');
11698 var defaultValueProp = data.DataViewObjectDescriptors.findDefaultValue(objectDescriptors);
11699 if (!defaultValueProp)
11700 return;
11701 for (var _i = 0, selectTransforms_1 = selectTransforms; _i < selectTransforms_1.length; _i++) {
11702 var selectTransform = selectTransforms_1[_i];
11703 if (!selectTransform)
11704 continue;
11705 debug.assertValue(selectTransform.queryName, 'selectTransform.queryName');
11706 applyDefaultValue(objectsForAllSelectors, defaultValueProp, selectTransform.queryName, selectTransform.defaultValue);
11707 }
11708 }
11709 function getColumnFormatForIndex(columns, selectIdx) {
11710 for (var columnIdx = 0, columnLen = columns.length; columnIdx < columnLen; columnIdx++) {
11711 var column = columns[columnIdx];
11712 if (!column || column.index !== selectIdx)
11713 continue;
11714 return column.format;
11715 }
11716 }
11717 function applyFormatString(objectsForAllSelectors, formatStringProp, queryName, formatStringValue) {
11718 if (!formatStringValue)
11719 return;
11720 // There is a format string specified -- apply it as an object property, if there is not already one specified.
11721 applyMetadataProperty(objectsForAllSelectors, formatStringProp, { metadata: queryName }, data.SQExprBuilder.text(formatStringValue));
11722 }
11723 function applyDefaultValue(objectsForAllSelectors, defaultValueProp, queryName, defaultValue) {
11724 if (!defaultValue)
11725 return;
11726 // There is a default value specified -- apply it as an object property, if there is not already one specified.
11727 applyMetadataProperty(objectsForAllSelectors, defaultValueProp, { metadata: queryName }, defaultValue);
11728 }
11729 function applyMetadataProperty(objectsForAllSelectors, propertyId, selector, value) {
11730 var objectDefns;
11731 if (selector) {
11732 var metadataObjects = objectsForAllSelectors.metadata;
11733 if (!metadataObjects)
11734 metadataObjects = objectsForAllSelectors.metadata = [];
11735 objectDefns = metadataObjects;
11736 }
11737 else {
11738 var metadataOnce = objectsForAllSelectors.metadataOnce;
11739 if (!metadataOnce)
11740 metadataOnce = objectsForAllSelectors.metadataOnce = { selector: selector, objects: [] };
11741 objectDefns = [metadataOnce];
11742 }
11743 var targetMetadataObject = findWithMatchingSelector(objectDefns, selector);
11744 var targetObjectDefn;
11745 if (targetMetadataObject) {
11746 var targetObjectDefns = targetMetadataObject.objects;
11747 targetObjectDefn = findExistingObject(targetObjectDefns, propertyId.objectName);
11748 if (targetObjectDefn) {
11749 if (targetObjectDefn.properties[propertyId.propertyName])
11750 return;
11751 }
11752 else {
11753 targetObjectDefn = {
11754 name: propertyId.objectName,
11755 properties: {},
11756 };
11757 targetObjectDefns.push(targetObjectDefn);
11758 }
11759 }
11760 else {
11761 targetObjectDefn = {
11762 name: propertyId.objectName,
11763 properties: {}
11764 };
11765 objectDefns.push({
11766 selector: selector,
11767 objects: [targetObjectDefn],
11768 });
11769 }
11770 targetObjectDefn.properties[propertyId.propertyName] = value;
11771 }
11772 function findWithMatchingSelector(objects, selector) {
11773 debug.assertValue(objects, 'objects');
11774 debug.assertAnyValue(selector, 'selector');
11775 for (var i = 0, len = objects.length; i < len; i++) {
11776 var object = objects[i];
11777 if (data.Selector.equals(object.selector, selector))
11778 return object;
11779 }
11780 }
11781 function findExistingObject(objectDefns, objectName) {
11782 debug.assertValue(objectDefns, 'objectDefns');
11783 debug.assertValue(objectName, 'objectName');
11784 for (var i = 0, len = objectDefns.length; i < len; i++) {
11785 var objectDefn = objectDefns[i];
11786 if (objectDefn.name === objectName)
11787 return objectDefn;
11788 }
11789 }
11790 })(DataViewObjectEvaluationUtils = data.DataViewObjectEvaluationUtils || (data.DataViewObjectEvaluationUtils = {}));
11791 })(data = powerbi.data || (powerbi.data = {}));
11792})(powerbi || (powerbi = {}));
11793/*
11794 * Power BI Visualizations
11795 *
11796 * Copyright (c) Microsoft Corporation
11797 * All rights reserved.
11798 * MIT License
11799 *
11800 * Permission is hereby granted, free of charge, to any person obtaining a copy
11801 * of this software and associated documentation files (the ""Software""), to deal
11802 * in the Software without restriction, including without limitation the rights
11803 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11804 * copies of the Software, and to permit persons to whom the Software is
11805 * furnished to do so, subject to the following conditions:
11806 *
11807 * The above copyright notice and this permission notice shall be included in
11808 * all copies or substantial portions of the Software.
11809 *
11810 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11811 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11812 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11813 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11814 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11815 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11816 * THE SOFTWARE.
11817 */
11818var powerbi;
11819(function (powerbi) {
11820 var data;
11821 (function (data) {
11822 /** Responsible for evaluating object property expressions to be applied at various scopes in a DataView. */
11823 var DataViewObjectEvaluator;
11824 (function (DataViewObjectEvaluator) {
11825 var colorValueType = powerbi.ValueType.fromDescriptor({ formatting: { color: true } });
11826 var numericType = powerbi.ValueType.fromDescriptor({ numeric: true });
11827 var textType = powerbi.ValueType.fromDescriptor({ text: true });
11828 function run(evalContext, objectDescriptor, propertyDefinitions) {
11829 debug.assertValue(evalContext, 'evalContext');
11830 debug.assertAnyValue(objectDescriptor, 'objectDescriptor');
11831 debug.assertValue(propertyDefinitions, 'propertyDefinitions');
11832 if (!objectDescriptor)
11833 return;
11834 var object, propertyDescriptors = objectDescriptor.properties;
11835 for (var propertyName in propertyDefinitions) {
11836 var propertyDefinition = propertyDefinitions[propertyName], propertyDescriptor = propertyDescriptors[propertyName];
11837 if (!propertyDescriptor)
11838 continue;
11839 var propertyValue = evaluateProperty(evalContext, propertyDescriptor, propertyDefinition);
11840 if (propertyValue === undefined)
11841 continue;
11842 if (!object)
11843 object = {};
11844 object[propertyName] = propertyValue;
11845 }
11846 return object;
11847 }
11848 DataViewObjectEvaluator.run = run;
11849 /** Note: Exported for testability */
11850 function evaluateProperty(evalContext, propertyDescriptor, propertyDefinition) {
11851 debug.assertValue(evalContext, 'evalContext');
11852 debug.assertValue(propertyDescriptor, 'propertyDescriptor');
11853 debug.assertValue(propertyDefinition, 'propertyDefinition');
11854 var structuralType = propertyDescriptor.type;
11855 if (structuralType && structuralType.expression)
11856 return propertyDefinition;
11857 var value = evaluateValue(evalContext, propertyDefinition, powerbi.ValueType.fromDescriptor(propertyDescriptor.type));
11858 if (value !== undefined || (propertyDefinition instanceof data.RuleEvaluation))
11859 return value;
11860 return evaluateFill(evalContext, propertyDefinition, structuralType)
11861 || evaluateFillRule(evalContext, propertyDefinition, structuralType)
11862 || evaluateImage(evalContext, propertyDefinition, structuralType)
11863 || evaluateParagraphs(evalContext, propertyDefinition, structuralType)
11864 || propertyDefinition;
11865 }
11866 DataViewObjectEvaluator.evaluateProperty = evaluateProperty;
11867 function evaluateFill(evalContext, fillDefn, type) {
11868 var fillType = type.fill;
11869 if (!fillType)
11870 return;
11871 if (fillType && fillType.solid && fillType.solid.color && fillDefn.solid) {
11872 return {
11873 solid: {
11874 color: evaluateValue(evalContext, fillDefn.solid.color, powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Color)),
11875 }
11876 };
11877 }
11878 }
11879 function evaluateFillRule(evalContext, fillRuleDefn, type) {
11880 if (!type.fillRule)
11881 return;
11882 if (fillRuleDefn.linearGradient2) {
11883 var linearGradient2 = fillRuleDefn.linearGradient2;
11884 return {
11885 linearGradient2: {
11886 min: evaluateColorStop(evalContext, linearGradient2.min),
11887 max: evaluateColorStop(evalContext, linearGradient2.max),
11888 }
11889 };
11890 }
11891 if (fillRuleDefn.linearGradient3) {
11892 var linearGradient3 = fillRuleDefn.linearGradient3;
11893 return {
11894 linearGradient3: {
11895 min: evaluateColorStop(evalContext, linearGradient3.min),
11896 mid: evaluateColorStop(evalContext, linearGradient3.mid),
11897 max: evaluateColorStop(evalContext, linearGradient3.max),
11898 }
11899 };
11900 }
11901 }
11902 function evaluateColorStop(evalContext, colorStop) {
11903 debug.assertValue(evalContext, 'evalContext');
11904 debug.assertValue(colorStop, 'colorStop');
11905 var step = {
11906 color: evaluateValue(evalContext, colorStop.color, colorValueType),
11907 };
11908 var value = evaluateValue(evalContext, colorStop.value, numericType);
11909 if (value != null)
11910 step.value = value;
11911 return step;
11912 }
11913 function evaluateImage(evalContext, definition, type) {
11914 debug.assertValue(evalContext, 'evalContext');
11915 debug.assertAnyValue(definition, 'definition');
11916 debug.assertValue(type, 'type');
11917 if (!type.image || !definition)
11918 return;
11919 var value = {
11920 name: evaluateValue(evalContext, definition.name, textType),
11921 url: evaluateValue(evalContext, definition.url, powerbi.ValueType.fromDescriptor(powerbi.ImageDefinition.urlType)),
11922 };
11923 if (definition.scaling)
11924 value.scaling = evaluateValue(evalContext, definition.scaling, textType);
11925 return value;
11926 }
11927 function evaluateParagraphs(evalContext, definition, type) {
11928 debug.assertValue(evalContext, 'evalContext');
11929 debug.assertAnyValue(definition, 'definition');
11930 debug.assertValue(type, 'type');
11931 if (!type.paragraphs || !definition)
11932 return;
11933 return evaluateArrayCopyOnChange(evalContext, definition, evaluateParagraph);
11934 }
11935 function evaluateParagraph(evalContext, definition) {
11936 debug.assertValue(evalContext, 'evalContext');
11937 debug.assertValue(definition, 'definition');
11938 var evaluated;
11939 var definitionTextRuns = definition.textRuns;
11940 var evaluatedTextRuns = evaluateArrayCopyOnChange(evalContext, definitionTextRuns, evaluateTextRun);
11941 if (definitionTextRuns !== evaluatedTextRuns) {
11942 evaluated = _.clone(definition);
11943 evaluated.textRuns = evaluatedTextRuns;
11944 }
11945 return evaluated || definition;
11946 }
11947 function evaluateTextRun(evalContext, definition) {
11948 debug.assertValue(evalContext, 'evalContext');
11949 debug.assertValue(definition, 'definition');
11950 var evaluated;
11951 var definitionValue = definition.value;
11952 var evaluatedValue = evaluateValue(evalContext, definitionValue, textType);
11953 if (evaluatedValue !== undefined) {
11954 evaluated = _.clone(definition);
11955 evaluated.value = evaluatedValue;
11956 }
11957 return evaluated || definition;
11958 }
11959 /**
11960 * Evaluates an array, and lazily copies on write whenever the evaluator function returns something
11961 * other than the input to it.
11962 */
11963 function evaluateArrayCopyOnChange(evalContext, definitions, evaluator) {
11964 debug.assertValue(evalContext, 'evalContext');
11965 debug.assertValue(definitions, 'definitions');
11966 debug.assertValue(evaluator, 'evaluator');
11967 var evaluatedValues;
11968 for (var i = 0, len = definitions.length; i < len; i++) {
11969 var definition = definitions[i];
11970 var evaluated = evaluator(evalContext, definition);
11971 // NOTE: the any casts here are necessary due to the compiler not knowing the relationship
11972 // between TEvaluated & TDefinition
11973 if (!evaluatedValues && definition !== evaluated) {
11974 evaluatedValues = _.take(definitions, i);
11975 }
11976 if (evaluatedValues) {
11977 evaluatedValues.push(evaluated);
11978 }
11979 }
11980 return evaluatedValues || definitions;
11981 }
11982 function evaluateValue(evalContext, definition, valueType) {
11983 if (definition instanceof data.SQExpr)
11984 return ExpressionEvaluator.evaluate(definition, evalContext);
11985 if (definition instanceof data.RuleEvaluation)
11986 return definition.evaluate(evalContext);
11987 }
11988 /** Responsible for evaluating SQExprs into values. */
11989 var ExpressionEvaluator = (function (_super) {
11990 __extends(ExpressionEvaluator, _super);
11991 function ExpressionEvaluator() {
11992 _super.apply(this, arguments);
11993 }
11994 ExpressionEvaluator.evaluate = function (expr, evalContext) {
11995 if (expr == null)
11996 return;
11997 return expr.accept(ExpressionEvaluator.instance, evalContext);
11998 };
11999 ExpressionEvaluator.prototype.visitColumnRef = function (expr, evalContext) {
12000 return evalContext.getExprValue(expr);
12001 };
12002 ExpressionEvaluator.prototype.visitConstant = function (expr, evalContext) {
12003 return expr.value;
12004 };
12005 ExpressionEvaluator.prototype.visitMeasureRef = function (expr, evalContext) {
12006 return evalContext.getExprValue(expr);
12007 };
12008 ExpressionEvaluator.prototype.visitAggr = function (expr, evalContext) {
12009 return evalContext.getExprValue(expr);
12010 };
12011 ExpressionEvaluator.prototype.visitFillRule = function (expr, evalContext) {
12012 var inputValue = expr.input.accept(this, evalContext);
12013 if (inputValue !== undefined) {
12014 var colorAllocator = evalContext.getColorAllocator(expr);
12015 if (colorAllocator) {
12016 return colorAllocator.color(inputValue);
12017 }
12018 }
12019 };
12020 ExpressionEvaluator.prototype.visitSelectRef = function (expr, evalContext) {
12021 return evalContext.getExprValue(expr);
12022 };
12023 ExpressionEvaluator.instance = new ExpressionEvaluator();
12024 return ExpressionEvaluator;
12025 }(data.DefaultSQExprVisitorWithArg));
12026 })(DataViewObjectEvaluator = data.DataViewObjectEvaluator || (data.DataViewObjectEvaluator = {}));
12027 })(data = powerbi.data || (powerbi.data = {}));
12028})(powerbi || (powerbi = {}));
12029/*
12030 * Power BI Visualizations
12031 *
12032 * Copyright (c) Microsoft Corporation
12033 * All rights reserved.
12034 * MIT License
12035 *
12036 * Permission is hereby granted, free of charge, to any person obtaining a copy
12037 * of this software and associated documentation files (the ""Software""), to deal
12038 * in the Software without restriction, including without limitation the rights
12039 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12040 * copies of the Software, and to permit persons to whom the Software is
12041 * furnished to do so, subject to the following conditions:
12042 *
12043 * The above copyright notice and this permission notice shall be included in
12044 * all copies or substantial portions of the Software.
12045 *
12046 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12047 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12048 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12049 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12050 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12051 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
12052 * THE SOFTWARE.
12053 */
12054var powerbi;
12055(function (powerbi) {
12056 var data;
12057 (function (data) {
12058 var inherit = powerbi.Prototype.inherit;
12059 var DataViewPivotCategorical;
12060 (function (DataViewPivotCategorical) {
12061 /**
12062 * Pivots categories in a categorical DataView into valueGroupings.
12063 * This is akin to a mathematical matrix transpose.
12064 */
12065 function apply(dataView) {
12066 debug.assertValue(dataView, 'dataView');
12067 var categorical = dataView.categorical;
12068 if (!categorical)
12069 return null;
12070 var categories = categorical.categories;
12071 if (!categories || categories.length !== 1)
12072 return null;
12073 var values = categorical.values;
12074 if (_.isEmpty(values) || values.source)
12075 return null;
12076 var category = categories[0], categoryIdentities = category.identity, categoryValues = category.values, pivotedColumns = [], pivotedValues = [];
12077 for (var rowIdx = 0, rowCount = categoryValues.length; rowIdx < rowCount; rowIdx++) {
12078 var categoryValue = categoryValues[rowIdx], categoryIdentity = categoryIdentities[rowIdx];
12079 for (var colIdx = 0, colCount = values.length; colIdx < colCount; colIdx++) {
12080 var value = values[colIdx], pivotedColumn = inherit(value.source);
12081 // A value has a series group, which is not implemented for pivoting -- just give up.
12082 if (value.identity)
12083 return null;
12084 pivotedColumn.groupName = categoryValue;
12085 var pivotedValue = {
12086 source: pivotedColumn,
12087 values: [value.values[rowIdx]],
12088 identity: categoryIdentity,
12089 min: value.min,
12090 max: value.max,
12091 subtotal: value.subtotal
12092 };
12093 var highlights = value.highlights;
12094 if (highlights) {
12095 pivotedValue.highlights = [highlights[rowIdx]];
12096 }
12097 pivotedColumns.push(pivotedColumn);
12098 pivotedValues.push(pivotedValue);
12099 }
12100 }
12101 var pivotedMetadata = inherit(dataView.metadata);
12102 pivotedMetadata.columns = pivotedColumns;
12103 values = data.DataViewTransform.createValueColumns(pivotedValues, category.identityFields, category.source);
12104 return {
12105 metadata: pivotedMetadata,
12106 categorical: {
12107 values: values,
12108 },
12109 matrix: dataView.matrix
12110 };
12111 }
12112 DataViewPivotCategorical.apply = apply;
12113 })(DataViewPivotCategorical = data.DataViewPivotCategorical || (data.DataViewPivotCategorical = {}));
12114 })(data = powerbi.data || (powerbi.data = {}));
12115})(powerbi || (powerbi = {}));
12116/*
12117 * Power BI Visualizations
12118 *
12119 * Copyright (c) Microsoft Corporation
12120 * All rights reserved.
12121 * MIT License
12122 *
12123 * Permission is hereby granted, free of charge, to any person obtaining a copy
12124 * of this software and associated documentation files (the ""Software""), to deal
12125 * in the Software without restriction, including without limitation the rights
12126 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12127 * copies of the Software, and to permit persons to whom the Software is
12128 * furnished to do so, subject to the following conditions:
12129 *
12130 * The above copyright notice and this permission notice shall be included in
12131 * all copies or substantial portions of the Software.
12132 *
12133 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12134 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12135 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12136 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12137 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12138 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
12139 * THE SOFTWARE.
12140 */
12141var powerbi;
12142(function (powerbi) {
12143 var data;
12144 (function (data) {
12145 var DataViewPivotMatrix;
12146 (function (DataViewPivotMatrix) {
12147 /** Pivots row hierarchy members in a matrix DataView into column hierarchy. */
12148 function apply(dataViewMatrix, context) {
12149 debug.assertValue(dataViewMatrix, 'dataViewMatrix');
12150 if (!context.columnHierarchyRewritten)
12151 dataViewMatrix.columns = powerbi.Prototype.inherit(dataViewMatrix.columns);
12152 var columns = dataViewMatrix.columns;
12153 if (!context.rowHierarchyRewritten)
12154 dataViewMatrix.rows = powerbi.Prototype.inherit(dataViewMatrix.rows);
12155 var rows = dataViewMatrix.rows;
12156 if (columns.levels.length > 1)
12157 return;
12158 var pivotedRowNode = {
12159 level: 0
12160 };
12161 var columnLeafNodes = columns.root.children;
12162 var measureCount = columnLeafNodes.length;
12163 // Notes related to VSTS 6999369: The level value of Measure Header nodes is not necessarily its parent node's level + 1.
12164 // In particular, the Measure Header column nodes directly under the Grand Total node at level 0 (i.e. _.last(pivotResultMatrix.columns.root.children))
12165 // will have level === (pivotResultMatrix.columns.levels.length - 1), which will be greater than the Grand Total node's 'level + 1'
12166 // in a matrix with 2+ column fields and 2+ measure fields.
12167 // In this code, all row levels will get pivoted over to the columns hierarchy, hence the level of any Measure Header nodes in the pivot result
12168 // is just (1 + the level of the deepest row node's level), which === rows.levels.length.
12169 var pivotResultMeasureHeaderLevel = rows.levels.length;
12170 if (measureCount > 0) {
12171 var index_1 = 0;
12172 var callback = function (node) {
12173 // Collect values and remove them from row leaves
12174 if (node.values) {
12175 if (!pivotedRowNode.values)
12176 pivotedRowNode.values = {};
12177 for (var i = 0; i < measureCount; i++)
12178 pivotedRowNode.values[index_1++] = node.values[i];
12179 delete node.values;
12180 }
12181 // Create measure headers if there are more than one measures
12182 if (measureCount > 1) {
12183 if (!node.children)
12184 node.children = [];
12185 for (var j = 0; j < measureCount; j++) {
12186 var measureHeaderLeaf = { level: pivotResultMeasureHeaderLevel };
12187 // Copy levelSourceIndex from columnLeafNodes (as they might have been reordered)
12188 var columnLeafNode = columnLeafNodes[j];
12189 measureHeaderLeaf.levelSourceIndex = columnLeafNode.levelSourceIndex;
12190 if (node.isSubtotal)
12191 measureHeaderLeaf.isSubtotal = true;
12192 node.children.push(measureHeaderLeaf);
12193 }
12194 }
12195 };
12196 if (context.hierarchyTreesRewritten) {
12197 forEachLeaf(rows.root, callback);
12198 }
12199 else {
12200 dataViewMatrix.columns.root = cloneTreeExecuteOnLeaf(rows.root, callback);
12201 }
12202 }
12203 else {
12204 if (!context.hierarchyTreesRewritten) {
12205 dataViewMatrix.columns.root = cloneTree(rows.root);
12206 }
12207 }
12208 if (measureCount > 1) {
12209 // Keep measure headers, but move them to the innermost level
12210 var level = { sources: columns.levels[0].sources };
12211 rows.levels.push(level);
12212 columns.levels.length = 0;
12213 }
12214 if (context.hierarchyTreesRewritten) {
12215 dataViewMatrix.columns.root = rows.root;
12216 dataViewMatrix.rows.root = {
12217 children: [pivotedRowNode]
12218 };
12219 }
12220 else {
12221 var updatedRowRoot = powerbi.Prototype.inherit(dataViewMatrix.rows.root);
12222 updatedRowRoot.children = [pivotedRowNode];
12223 dataViewMatrix.rows.root = updatedRowRoot;
12224 }
12225 dataViewMatrix.columns.levels = rows.levels;
12226 dataViewMatrix.rows.levels = [];
12227 }
12228 DataViewPivotMatrix.apply = apply;
12229 function forEachLeaf(root, callback) {
12230 var children = root.children;
12231 if (children && children.length > 0) {
12232 for (var i = 0, ilen = children.length; i < ilen; i++)
12233 forEachLeaf(children[i], callback);
12234 return;
12235 }
12236 callback(root);
12237 }
12238 function cloneTree(node) {
12239 return cloneTreeExecuteOnLeaf(node);
12240 }
12241 DataViewPivotMatrix.cloneTree = cloneTree;
12242 function cloneTreeExecuteOnLeaf(node, callback) {
12243 var updatedNode = powerbi.Prototype.inherit(node);
12244 var children = node.children;
12245 if (children && children.length > 0) {
12246 var newChildren = [];
12247 for (var i = 0, ilen = children.length; i < ilen; i++) {
12248 var updatedChild = cloneTreeExecuteOnLeaf(children[i], callback);
12249 newChildren.push(updatedChild);
12250 }
12251 updatedNode.children = newChildren;
12252 }
12253 else {
12254 if (callback)
12255 callback(updatedNode);
12256 }
12257 return updatedNode;
12258 }
12259 DataViewPivotMatrix.cloneTreeExecuteOnLeaf = cloneTreeExecuteOnLeaf;
12260 })(DataViewPivotMatrix = data.DataViewPivotMatrix || (data.DataViewPivotMatrix = {}));
12261 })(data = powerbi.data || (powerbi.data = {}));
12262})(powerbi || (powerbi = {}));
12263/*
12264 * Power BI Visualizations
12265 *
12266 * Copyright (c) Microsoft Corporation
12267 * All rights reserved.
12268 * MIT License
12269 *
12270 * Permission is hereby granted, free of charge, to any person obtaining a copy
12271 * of this software and associated documentation files (the ""Software""), to deal
12272 * in the Software without restriction, including without limitation the rights
12273 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12274 * copies of the Software, and to permit persons to whom the Software is
12275 * furnished to do so, subject to the following conditions:
12276 *
12277 * The above copyright notice and this permission notice shall be included in
12278 * all copies or substantial portions of the Software.
12279 *
12280 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12281 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12282 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12283 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12284 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12285 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
12286 * THE SOFTWARE.
12287 */
12288var powerbi;
12289(function (powerbi) {
12290 var data;
12291 (function (data) {
12292 var DataViewSelfCrossJoin;
12293 (function (DataViewSelfCrossJoin) {
12294 /**
12295 * Returns a new DataView based on the original, with a single DataViewCategorical category that is "cross joined"
12296 * to itself as a value grouping.
12297 * This is the mathematical equivalent of taking an array and turning it into an identity matrix.
12298 */
12299 function apply(dataView) {
12300 debug.assertValue(dataView, 'dataView');
12301 if (!dataView.categorical)
12302 return;
12303 var dataViewCategorical = dataView.categorical;
12304 if (!dataViewCategorical.categories || dataViewCategorical.categories.length !== 1)
12305 return;
12306 if (dataViewCategorical.values && dataViewCategorical.values.source)
12307 return;
12308 return applyCategorical(dataView.metadata, dataViewCategorical);
12309 }
12310 DataViewSelfCrossJoin.apply = apply;
12311 function applyCategorical(dataViewMetadata, dataViewCategorical) {
12312 debug.assertValue(dataViewMetadata, 'dataViewMetadata');
12313 debug.assertValue(dataViewCategorical, 'dataViewCategorical');
12314 debug.assertValue(dataViewCategorical.categories, 'dataViewCategorical.categories');
12315 var category = dataViewCategorical.categories[0], categoryValues = category.values, categoryLength = categoryValues.length;
12316 if (categoryLength === 0)
12317 return;
12318 var valuesArray = dataViewCategorical.values
12319 ? dataViewCategorical.values.grouped()[0].values
12320 : [];
12321 var transformedDataView = data.createCategoricalDataViewBuilder()
12322 .withCategories(dataViewCategorical.categories)
12323 .withGroupedValues(createGroupedValues(category, categoryValues, categoryLength, valuesArray))
12324 .build();
12325 dataViewMetadata = powerbi.Prototype.inherit(dataViewMetadata);
12326 dataViewMetadata.columns = transformedDataView.metadata.columns;
12327 return {
12328 metadata: dataViewMetadata,
12329 categorical: transformedDataView.categorical,
12330 };
12331 }
12332 function createGroupedValues(category, categoryValues, categoryLength, valuesArray) {
12333 debug.assertValue(category, 'category');
12334 debug.assertValue(categoryValues, 'categoryValues');
12335 debug.assertValue(categoryLength, 'categoryLength');
12336 debug.assertValue(valuesArray, 'valuesArray');
12337 var nullValuesArray = createNullValues(categoryLength), valuesArrayLen = valuesArray.length, seriesData = [];
12338 for (var i = 0; i < categoryLength; i++) {
12339 var seriesDataItem = [];
12340 for (var j = 0; j < valuesArrayLen; j++) {
12341 var originalValueColumn = valuesArray[j], originalHighlightValues = originalValueColumn.highlights;
12342 var seriesDataItemCategory = {
12343 values: inheritArrayWithValue(nullValuesArray, originalValueColumn.values, i),
12344 };
12345 if (originalHighlightValues)
12346 seriesDataItemCategory.highlights = inheritArrayWithValue(nullValuesArray, originalHighlightValues, i);
12347 seriesDataItem.push(seriesDataItemCategory);
12348 }
12349 seriesData.push(seriesDataItem);
12350 }
12351 return {
12352 groupColumn: {
12353 source: category.source,
12354 identityFrom: { fields: category.identityFields, identities: category.identity },
12355 values: category.values,
12356 },
12357 valueColumns: _.map(valuesArray, function (v) { return { source: v.source }; }),
12358 data: seriesData,
12359 };
12360 }
12361 })(DataViewSelfCrossJoin = data.DataViewSelfCrossJoin || (data.DataViewSelfCrossJoin = {}));
12362 function createNullValues(length) {
12363 debug.assertValue(length, 'length');
12364 var array = new Array(length);
12365 for (var i = 0; i < length; i++)
12366 array[i] = null;
12367 return array;
12368 }
12369 function inheritArrayWithValue(nullValues, original, index) {
12370 var inherited = powerbi.Prototype.inherit(nullValues);
12371 inherited[index] = original[index];
12372 return inherited;
12373 }
12374 })(data = powerbi.data || (powerbi.data = {}));
12375})(powerbi || (powerbi = {}));
12376/*
12377 * Power BI Visualizations
12378 *
12379 * Copyright (c) Microsoft Corporation
12380 * All rights reserved.
12381 * MIT License
12382 *
12383 * Permission is hereby granted, free of charge, to any person obtaining a copy
12384 * of this software and associated documentation files (the ""Software""), to deal
12385 * in the Software without restriction, including without limitation the rights
12386 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12387 * copies of the Software, and to permit persons to whom the Software is
12388 * furnished to do so, subject to the following conditions:
12389 *
12390 * The above copyright notice and this permission notice shall be included in
12391 * all copies or substantial portions of the Software.
12392 *
12393 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12394 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12395 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12396 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12397 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12398 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
12399 * THE SOFTWARE.
12400 */
12401var powerbi;
12402(function (powerbi) {
12403 var data;
12404 (function (data) {
12405 var ArrayExtensions = jsCommon.ArrayExtensions;
12406 var DataShapeBindingDataReduction = powerbi.data.DataShapeBindingDataReduction;
12407 var inheritSingle = powerbi.Prototype.inheritSingle;
12408 var DataViewPivotCategoricalToPrimaryGroups;
12409 (function (DataViewPivotCategoricalToPrimaryGroups) {
12410 /**
12411 * If mapping requests cross axis data reduction and the binding has secondary grouping, mutates the binding to
12412 * pivot the secondary before the primary.
12413 */
12414 function pivotBinding(binding, allMappings, finalMapping, defaultDataVolume) {
12415 // unpivot is inferred from result in DataViewTransform.apply but it does not have the
12416 // compiled mappings available, let alone the merged mapping, only the original
12417 // DataViewMappings. to keep that inference easy, only apply pivot when there's
12418 // only one matching mapping
12419 if (!allMappings || allMappings.length !== 1)
12420 return;
12421 if (!finalMapping.categorical || !finalMapping.categorical.dataReductionAlgorithm)
12422 return;
12423 if (!binding)
12424 return;
12425 if (!canPivotCategorical(binding, finalMapping))
12426 return;
12427 // pivot secondary onto front of primary
12428 binding.Primary.Groupings = [binding.Secondary.Groupings[0], binding.Primary.Groupings[0]];
12429 binding.Secondary = undefined;
12430 // set primary to pivot reduction
12431 binding.DataReduction = {
12432 Primary: DataShapeBindingDataReduction.createFrom(finalMapping.categorical.dataReductionAlgorithm),
12433 DataVolume: finalMapping.categorical.dataVolume || defaultDataVolume,
12434 };
12435 }
12436 DataViewPivotCategoricalToPrimaryGroups.pivotBinding = pivotBinding;
12437 /** narrowly targets scatter chart scenario for now to keep code simple */
12438 function isPivotableAxis(axis) {
12439 return axis
12440 && axis.Groupings
12441 && axis.Groupings.length === 1
12442 && !_.isEmpty(axis.Groupings[0].Projections)
12443 && !axis.Groupings[0].Subtotal
12444 && _.isEmpty(axis.Groupings[0].SuppressedProjections);
12445 }
12446 function canPivotCategorical(binding, mapping) {
12447 if (!isPivotableAxis(binding.Primary))
12448 return false;
12449 if (!isPivotableAxis(binding.Secondary) || binding.Secondary.Groupings[0].Projections.length !== 1)
12450 return false;
12451 // don't pivot if either axis has a data reduction
12452 if (binding.DataReduction && (binding.DataReduction.Primary || binding.DataReduction.Secondary))
12453 return false;
12454 return true;
12455 }
12456 function unpivotResult(oldDataView, selects, dataViewMappings, projectionActiveItems) {
12457 if (!inferUnpivotTransform(selects, dataViewMappings, oldDataView, projectionActiveItems))
12458 return oldDataView;
12459 // This returns a subsetted version of the DataView rather than using prototypal inheritance because
12460 // any dataviews in the old one (including ones invented after this code is written) will correspond
12461 // to a pivoted query result and therefore will be in the wrong shape for the unpivoted query the
12462 // querying code made.
12463 var newDataView = {
12464 metadata: {
12465 columns: ArrayExtensions.copy(oldDataView.metadata.columns),
12466 },
12467 };
12468 // preserve view types that aren't affected by pivoting
12469 if (oldDataView.single)
12470 newDataView.single = oldDataView.single;
12471 if (oldDataView.table)
12472 newDataView.table = oldDataView.table;
12473 // other views are derived from matrix
12474 if (oldDataView.matrix) {
12475 var newDataViewMatrix = unpivotMatrix(oldDataView.matrix);
12476 // categorical only if there's data
12477 if (!_.isEmpty(newDataViewMatrix.valueSources)) {
12478 // Guard against a DataViewMatrix with composite grouping in columns, because composite group in Series is
12479 // not yet expressible in the current version of DataViewValueColumns and DataViewValueColumnGroup interfaces.
12480 // this.canPivotCategorical() would have returned false in the first place for this query.
12481 var hasCompositeGroupInSeries = data.utils.DataViewMatrixUtils.containsCompositeGroup(newDataViewMatrix.columns);
12482 if (!hasCompositeGroupInSeries) {
12483 newDataView.categorical = categoricalFromUnpivotedMatrix(newDataViewMatrix, newDataView.metadata.columns);
12484 }
12485 }
12486 }
12487 return newDataView;
12488 }
12489 DataViewPivotCategoricalToPrimaryGroups.unpivotResult = unpivotResult;
12490 /**
12491 * Infer from the query result and the visual mappings whether the query was pivoted.
12492 * Narrowly targets scatter chart scenario for now to keep code simple
12493 */
12494 function inferUnpivotTransform(selects, dataViewMappings, dataView, projectionActiveItems) {
12495 if (_.isEmpty(selects) || _.isEmpty(dataViewMappings) || !dataView)
12496 return false;
12497 // select applicable mappings based on select roles
12498 var roleKinds = data.DataViewSelectTransform.createRoleKindFromMetadata(selects, dataView.metadata);
12499 var projections = data.DataViewSelectTransform.projectionsFromSelects(selects, projectionActiveItems);
12500 var supportedDataViewMappings = powerbi.DataViewAnalysis.chooseDataViewMappings(projections, dataViewMappings, roleKinds).supportedMappings;
12501 // NOTE: limiting to simple situation that handles scatter for now - see the other side in canPivotCategorical
12502 if (!supportedDataViewMappings || supportedDataViewMappings.length !== 1)
12503 return false;
12504 var categoricalMapping = supportedDataViewMappings[0].categorical;
12505 if (!categoricalMapping)
12506 return false;
12507 // pivoted query will have produced a matrix
12508 var matrixDataview = dataView.matrix;
12509 if (!matrixDataview)
12510 return false;
12511 // matrix must have two levels of grouping
12512 if (!matrixDataview.rows || !matrixDataview.rows.levels || matrixDataview.rows.levels.length !== 2)
12513 return false;
12514 // get category and value grouping roles
12515 var categoryGroups = [];
12516 var valueGroups = [];
12517 var addGroupingRole = function (roleName, groups) {
12518 var roleProjections = projections[roleName];
12519 if (!roleProjections)
12520 return;
12521 for (var _i = 0, _a = roleProjections.all(); _i < _a.length; _i++) {
12522 var roleProjection = _a[_i];
12523 if (roleKinds[roleProjection.queryRef] === powerbi.VisualDataRoleKind.Grouping)
12524 groups.push(roleProjection.queryRef);
12525 }
12526 };
12527 powerbi.DataViewMapping.visitCategoricalCategories(categoricalMapping.categories, {
12528 visitRole: function (roleName) { addGroupingRole(roleName, categoryGroups); }
12529 });
12530 powerbi.DataViewMapping.visitCategoricalValues(categoricalMapping.values, {
12531 visitRole: function (roleName) { addGroupingRole(roleName, valueGroups); }
12532 });
12533 // need both for pivot to have been done
12534 if (_.isEmpty(categoryGroups) || _.isEmpty(valueGroups))
12535 return false;
12536 // if there was a pivot, there won't be any measures left in the columns
12537 for (var _i = 0, _a = matrixDataview.columns.levels; _i < _a.length; _i++) {
12538 var level = _a[_i];
12539 for (var _b = 0, _c = level.sources; _b < _c.length; _b++) {
12540 var source = _c[_b];
12541 if (!source.isMeasure)
12542 return false;
12543 }
12544 }
12545 return true;
12546 }
12547 /**
12548 * matrix will have two groupings in the rows, outer (series) and inner (categories), and none in the columns.
12549 * this function changes that so that the categories become the rows and the series the columns.
12550 */
12551 function unpivotMatrix(oldMatrix) {
12552 var oldRows = oldMatrix.rows;
12553 var oldRoot = oldRows.root;
12554 var oldChildren = oldRoot.children;
12555 // series are the outer grouping
12556 var series = [];
12557 var seriesIdLevel = oldRows.levels[0];
12558 var seriesIdFields = oldRoot.childIdentityFields;
12559 // categories are the inner grouping.
12560 var categoryIndex = {};
12561 var categories = [];
12562 var categoryIdLevel = oldRows.levels[1];
12563 var categoryIdFields = _.isEmpty(oldChildren) ? undefined : oldChildren[0].childIdentityFields;
12564 var measureCount = oldMatrix.valueSources.length;
12565 // within each series value, the category list may not be complete so cannot simply use the inner loop index
12566 // to reference it.
12567 var findCategory = function (identity) {
12568 var index = categoryIndex[identity.key];
12569 debug.assert(index !== undefined, "findcat() !== undefined");
12570 return index;
12571 };
12572 // collect series and categories from the row hierarchy
12573 if (oldChildren) {
12574 var addCategory = function (categoryNode) {
12575 var key = categoryNode.identity.key;
12576 var index = categoryIndex[key];
12577 if (index === undefined) {
12578 index = categories.length;
12579 categoryIndex[key] = index;
12580 categories.push(categoryNode);
12581 }
12582 };
12583 for (var _i = 0, oldChildren_1 = oldChildren; _i < oldChildren_1.length; _i++) {
12584 var seriesNode = oldChildren_1[_i];
12585 series.push(seriesNode);
12586 for (var _a = 0, _b = seriesNode.children; _a < _b.length; _a++) {
12587 var categoryNode = _b[_a];
12588 addCategory(categoryNode);
12589 }
12590 }
12591 }
12592 // extract intersection values from pivoted matrix
12593 // values will be indexed by categories then series
12594 var matrixValues = new Array(categories.length);
12595 for (var j = 0; j < series.length; ++j) {
12596 var seriesNode = oldChildren[j];
12597 for (var _c = 0, _d = seriesNode.children; _c < _d.length; _c++) {
12598 var categoryNode = _d[_c];
12599 var i = findCategory(categoryNode.identity); // must lookup actual category index
12600 if (!matrixValues[i])
12601 matrixValues[i] = new Array(series.length);
12602 matrixValues[i][j] = categoryNode.values;
12603 }
12604 }
12605 // columns of the unpivoted matrix are the series
12606 var newColumns = {
12607 root: {
12608 children: _.map(series, function (s) {
12609 var inheritedNode = inheritSingle(s);
12610 inheritedNode.level = 0; // s.level should already be 0, but just in case...
12611 inheritedNode.children = undefined; // if Measure Headers exist in oldMatrix.columns, newColumns.root.children will get populated later in this function
12612 inheritedNode.childIdentityFields = undefined;
12613 return inheritedNode;
12614 }),
12615 childIdentityFields: seriesIdFields,
12616 },
12617 levels: [
12618 seriesIdLevel,
12619 ],
12620 };
12621 // Re-add any Measure Headers from oldMatrix.columns as leaf nodes under newColumns
12622 if (measureCount > 0) {
12623 var newColChildren = _.map(oldMatrix.columns.root.children, function (srcnode) {
12624 var dstnode = { level: 1 };
12625 if (srcnode.levelSourceIndex)
12626 dstnode.levelSourceIndex = srcnode.levelSourceIndex;
12627 return dstnode;
12628 });
12629 for (var i = 0; i < newColumns.root.children.length; ++i)
12630 newColumns.root.children[i].children = newColChildren;
12631 newColumns.levels.push(oldMatrix.columns.levels[0]);
12632 }
12633 // rows of the unpivoted matrix are the categories
12634 var newRows = {
12635 root: {
12636 children: _.map(categories, function (c) {
12637 var inheritedNode = inheritSingle(c);
12638 inheritedNode.level = 0;
12639 inheritedNode.children = undefined; // c.children should already be undefined, but just in case...
12640 inheritedNode.childIdentityFields = undefined; // c.children should already be undefined, but just in case...
12641 return inheritedNode;
12642 }),
12643 childIdentityFields: categoryIdFields,
12644 },
12645 levels: [
12646 categoryIdLevel,
12647 ],
12648 };
12649 // put values into rows
12650 if (measureCount > 0) {
12651 for (var i = 0; i < categories.length; ++i) {
12652 var row = newRows.root.children[i];
12653 var rowValues = {};
12654 for (var j = 0; j < series.length; ++j) {
12655 var mvalues = matrixValues[i] && matrixValues[i][j];
12656 for (var k = 0; k < measureCount; ++k) {
12657 var l = j * measureCount + k;
12658 rowValues[l] = !mvalues
12659 ? (k === 0 ? { value: null } : { value: null, valueSourceIndex: k })
12660 : mvalues[k];
12661 }
12662 }
12663 row.values = rowValues;
12664 }
12665 }
12666 var newMatrix = {
12667 rows: newRows,
12668 columns: newColumns,
12669 valueSources: oldMatrix.valueSources,
12670 };
12671 return newMatrix;
12672 }
12673 /** build a categorical data view from an unpivoted matrix. */
12674 function categoricalFromUnpivotedMatrix(matrix, columnMetadata) {
12675 var seriesCount = matrix.columns.root.children.length;
12676 var measureMetadata = matrix.valueSources;
12677 var measureCount = measureMetadata.length;
12678 var categories = createCategoryColumnsFromUnpivotedMatrix(matrix);
12679 // create grouped values
12680 var groups = [];
12681 for (var j = 0; j < seriesCount; ++j) {
12682 var seriesColumn = matrix.columns.root.children[j];
12683 var group = {
12684 values: [],
12685 identity: seriesColumn.identity,
12686 name: seriesColumn.value || null,
12687 };
12688 groups.push(group);
12689 for (var k = 0; k < measureCount; ++k) {
12690 var valueColumnMetadataSrc = measureMetadata[k];
12691 var valueColumnMetadataDst = {};
12692 for (var key in valueColumnMetadataSrc)
12693 valueColumnMetadataDst[key] = valueColumnMetadataSrc[key];
12694 valueColumnMetadataDst.groupName = group.name;
12695 columnMetadata.push(valueColumnMetadataDst);
12696 var valueColumn = {
12697 source: valueColumnMetadataDst,
12698 values: [],
12699 identity: group.identity,
12700 };
12701 group.values.push(valueColumn);
12702 // grab measure values in the group from across rows of matrix
12703 var index = k + j * measureCount;
12704 for (var _i = 0, _a = matrix.rows.root.children; _i < _a.length; _i++) {
12705 var categoryNode = _a[_i];
12706 var value = categoryNode.values[index].value;
12707 valueColumn.values.push(value);
12708 }
12709 }
12710 }
12711 // and now ungrouped
12712 var values = [];
12713 for (var _b = 0, groups_1 = groups; _b < groups_1.length; _b++) {
12714 var group = groups_1[_b];
12715 for (var k = 0; k < measureCount; ++k) {
12716 values.push(group.values[k]);
12717 }
12718 }
12719 values.grouped = function () { return groups; };
12720 values.identityFields = matrix.columns.root.childIdentityFields;
12721 values.source = matrix.columns.levels[0].sources[0];
12722 // final assembly
12723 var categorical = {
12724 categories: categories,
12725 values: values,
12726 };
12727 return categorical;
12728 }
12729 function createCategoryColumnsFromUnpivotedMatrix(unpivotedMatrix) {
12730 debug.assertValue(unpivotedMatrix, 'unpivotedMatrix');
12731 debug.assert(unpivotedMatrix && unpivotedMatrix.rows && unpivotedMatrix.rows.levels && (unpivotedMatrix.rows.levels.length === 1), 'pre-condition: unpivotedMatrix should have exactly one level in row hierarchy');
12732 // Create categories from rows. If matrix.rows.levels[0].sources represents a composite group, expand each column in the
12733 // composite group into a separate DataViewCategoryColumn. The identity and childIdentityFields properties will be the
12734 // same amongst the resulting DataViewCategoryColumns.
12735 var categoryIdentity = _.map(unpivotedMatrix.rows.root.children, function (x) { return x.identity; });
12736 var categoryIdentityFields = unpivotedMatrix.rows.root.childIdentityFields;
12737 var categorySourceColumns = unpivotedMatrix.rows.levels[0].sources;
12738 var categories = [];
12739 for (var i = 0, ilen = categorySourceColumns.length; i < ilen; i++) {
12740 var groupLevelValues = _.map(unpivotedMatrix.rows.root.children, function (categoryNode) {
12741 var levelValues = categoryNode.levelValues;
12742 // Please refer to the interface comments on when this is undefined... But in today's code
12743 // I believe we will not see undefined levelValues in the rows of any unpivotedMatrix.
12744 if (levelValues !== undefined) {
12745 debug.assert(levelValues[i] && (levelValues[i].levelSourceIndex === i), 'pre-condition: DataViewMatrixNode.levelValues is expected to have one DataViewMatrixGroupValue node per level source column, sorted by levelSourceIndex.');
12746 return levelValues[i].value;
12747 }
12748 });
12749 categories.push({
12750 source: categorySourceColumns[i],
12751 values: groupLevelValues,
12752 identity: categoryIdentity,
12753 identityFields: categoryIdentityFields,
12754 });
12755 }
12756 return categories;
12757 }
12758 })(DataViewPivotCategoricalToPrimaryGroups = data.DataViewPivotCategoricalToPrimaryGroups || (data.DataViewPivotCategoricalToPrimaryGroups = {}));
12759 })(data = powerbi.data || (powerbi.data = {}));
12760})(powerbi || (powerbi = {}));
12761/*
12762 * Power BI Visualizations
12763 *
12764 * Copyright (c) Microsoft Corporation
12765 * All rights reserved.
12766 * MIT License
12767 *
12768 * Permission is hereby granted, free of charge, to any person obtaining a copy
12769 * of this software and associated documentation files (the ""Software""), to deal
12770 * in the Software without restriction, including without limitation the rights
12771 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12772 * copies of the Software, and to permit persons to whom the Software is
12773 * furnished to do so, subject to the following conditions:
12774 *
12775 * The above copyright notice and this permission notice shall be included in
12776 * all copies or substantial portions of the Software.
12777 *
12778 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12779 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12780 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12781 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12782 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12783 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
12784 * THE SOFTWARE.
12785 */
12786var powerbi;
12787(function (powerbi) {
12788 var data;
12789 (function (data) {
12790 var inherit = powerbi.Prototype.inherit;
12791 var inheritSingle = powerbi.Prototype.inheritSingle;
12792 var ArrayExtensions = jsCommon.ArrayExtensions;
12793 var EnumExtensions = jsCommon.EnumExtensions;
12794 // TODO: refactor & focus DataViewTransform into a service with well-defined dependencies.
12795 var DataViewTransform;
12796 (function (DataViewTransform) {
12797 var fillRulePropertyDescriptor = { type: { fillRule: {} } };
12798 function apply(options) {
12799 debug.assertValue(options, 'options');
12800 // TODO: Flow a context object through to capture errors/warnings about what happens here for better diagnosability.
12801 var prototype = options.prototype, objectDescriptors = options.objectDescriptors, dataViewMappings = options.dataViewMappings, transforms = options.transforms, projectionActiveItems = transforms && transforms.roles && transforms.roles.activeItems, colorAllocatorFactory = options.colorAllocatorFactory, dataRoles = options.dataRoles;
12802 if (!prototype)
12803 return transformEmptyDataView(objectDescriptors, transforms, colorAllocatorFactory);
12804 if (!transforms)
12805 return [prototype];
12806 // Transform Query DataView
12807 prototype = data.DataViewPivotCategoricalToPrimaryGroups.unpivotResult(prototype, transforms.selects, dataViewMappings, projectionActiveItems);
12808 var visualDataViews = transformQueryToVisualDataView(prototype, transforms, objectDescriptors, dataViewMappings, colorAllocatorFactory, dataRoles);
12809 // Transform and generate derived visual DataViews
12810 visualDataViews = data.DataViewRegression.run({
12811 dataViewMappings: dataViewMappings,
12812 visualDataViews: visualDataViews,
12813 dataRoles: dataRoles,
12814 objectDescriptors: objectDescriptors,
12815 objectDefinitions: transforms.objects,
12816 colorAllocatorFactory: colorAllocatorFactory,
12817 transformSelects: transforms.selects,
12818 metadata: prototype.metadata,
12819 projectionActiveItems: projectionActiveItems,
12820 });
12821 return visualDataViews;
12822 }
12823 DataViewTransform.apply = apply;
12824 function transformQueryToVisualDataView(prototype, transforms, objectDescriptors, dataViewMappings, colorAllocatorFactory, dataRoles) {
12825 var transformedDataViews = [];
12826 var splits = transforms.splits;
12827 if (_.isEmpty(splits)) {
12828 transformedDataViews.push(transformDataView(prototype, objectDescriptors, dataViewMappings, transforms, colorAllocatorFactory, dataRoles));
12829 }
12830 else {
12831 for (var _i = 0, splits_1 = splits; _i < splits_1.length; _i++) {
12832 var split = splits_1[_i];
12833 var transformed = transformDataView(prototype, objectDescriptors, dataViewMappings, transforms, colorAllocatorFactory, dataRoles, split.selects);
12834 transformedDataViews.push(transformed);
12835 }
12836 }
12837 return transformedDataViews;
12838 }
12839 function transformEmptyDataView(objectDescriptors, transforms, colorAllocatorFactory) {
12840 if (transforms && transforms.objects) {
12841 var emptyDataView = {
12842 metadata: {
12843 columns: [],
12844 }
12845 };
12846 transformObjects(emptyDataView, 0 /* None */, objectDescriptors, transforms.objects, transforms.selects, colorAllocatorFactory);
12847 return [emptyDataView];
12848 }
12849 return [];
12850 }
12851 function transformDataView(prototype, objectDescriptors, roleMappings, transforms, colorAllocatorFactory, dataRoles, selectsToInclude) {
12852 debug.assertValue(prototype, 'prototype');
12853 debug.assertValue(transforms, 'transforms');
12854 debug.assert(!selectsToInclude ||
12855 _.filter(Object.keys(selectsToInclude), function (selectIndex) { return selectsToInclude[selectIndex] && (!transforms.selects || !transforms.selects[selectIndex]); })
12856 .length === 0, // asserts that the number of select indices in selectsToInclude without a corresponding Select Transform === 0
12857 'If selectsToInclude is specified, every Select Index in it must have a corresponding Select Transform.');
12858 var targetKinds = getTargetKinds(roleMappings);
12859 var transformed = inherit(prototype);
12860 transformed.metadata = inherit(prototype.metadata);
12861 var projectionOrdering = transforms.roles && transforms.roles.ordering;
12862 var projectionActiveItems = transforms.roles && transforms.roles.activeItems;
12863 transformed = transformSelects(transformed, targetKinds, roleMappings, transforms.selects, projectionOrdering, selectsToInclude);
12864 transformObjects(transformed, targetKinds, objectDescriptors, transforms.objects, transforms.selects, colorAllocatorFactory);
12865 // Note: Do this step after transformObjects() so that metadata columns in 'transformed' have roles and objects.general.formatString populated
12866 transformed = data.DataViewConcatenateCategoricalColumns.detectAndApply(transformed, objectDescriptors, roleMappings, projectionOrdering, transforms.selects, projectionActiveItems);
12867 data.DataViewNormalizeValues.apply({
12868 dataview: transformed,
12869 dataViewMappings: roleMappings,
12870 dataRoles: dataRoles,
12871 });
12872 return transformed;
12873 }
12874 function getTargetKinds(roleMappings) {
12875 debug.assertAnyValue(roleMappings, 'roleMappings');
12876 if (!roleMappings)
12877 return 0 /* None */;
12878 var result = 0 /* None */;
12879 for (var _i = 0, roleMappings_1 = roleMappings; _i < roleMappings_1.length; _i++) {
12880 var roleMapping = roleMappings_1[_i];
12881 if (roleMapping.categorical)
12882 result |= 1 /* Categorical */;
12883 if (roleMapping.matrix)
12884 result |= 2 /* Matrix */;
12885 if (roleMapping.single)
12886 result |= 4 /* Single */;
12887 if (roleMapping.table)
12888 result |= 8 /* Table */;
12889 if (roleMapping.tree)
12890 result |= 16 /* Tree */;
12891 }
12892 return result;
12893 }
12894 function transformSelects(dataView, targetDataViewKinds, roleMappings, selectTransforms, projectionOrdering, selectsToInclude) {
12895 var columnRewrites = [];
12896 if (selectTransforms) {
12897 dataView.metadata.columns = applyTransformsToColumns(dataView.metadata.columns, selectTransforms, columnRewrites);
12898 }
12899 // NOTE: no rewrites necessary for Tree (it doesn't reference the columns)
12900 if (dataView.categorical && EnumExtensions.hasFlag(targetDataViewKinds, 1 /* Categorical */)) {
12901 dataView.categorical = applyRewritesToCategorical(dataView.categorical, columnRewrites, selectsToInclude);
12902 // TODO VSTS 7024199: separate out structural transformations from dataViewTransform.transformSelects(...)
12903 // NOTE: This is slightly DSR-specific.
12904 dataView = pivotIfNecessary(dataView, roleMappings);
12905 }
12906 // Don't perform this potentially expensive transform unless we actually have a matrix.
12907 // When we switch to lazy per-visual DataView creation, we'll be able to remove this check.
12908 if (dataView.matrix && EnumExtensions.hasFlag(targetDataViewKinds, 2 /* Matrix */)) {
12909 var matrixTransformationContext = {
12910 rowHierarchyRewritten: false,
12911 columnHierarchyRewritten: false,
12912 hierarchyTreesRewritten: false
12913 };
12914 dataView.matrix = applyRewritesToMatrix(dataView.matrix, columnRewrites, roleMappings, projectionOrdering, matrixTransformationContext);
12915 // TODO VSTS 7024199: separate out structural transformations from dataViewTransform.transformSelects(...)
12916 if (shouldPivotMatrix(dataView.matrix, roleMappings))
12917 data.DataViewPivotMatrix.apply(dataView.matrix, matrixTransformationContext);
12918 }
12919 // Don't perform this potentially expensive transform unless we actually have a table.
12920 // When we switch to lazy per-visual DataView creation, we'll be able to remove this check.
12921 if (dataView.table && EnumExtensions.hasFlag(targetDataViewKinds, 8 /* Table */)) {
12922 dataView.table = applyRewritesToTable(dataView.table, columnRewrites, projectionOrdering);
12923 }
12924 return dataView;
12925 }
12926 function applyTransformsToColumns(prototypeColumns, selects, rewrites) {
12927 debug.assertValue(prototypeColumns, 'columns');
12928 if (!selects)
12929 return prototypeColumns;
12930 //column may contain undefined entries
12931 var columns = inherit(prototypeColumns);
12932 for (var i = 0, len = prototypeColumns.length; i < len; i++) {
12933 var prototypeColumn = prototypeColumns[i];
12934 var select = selects[prototypeColumn.index];
12935 if (!select)
12936 continue;
12937 var column = columns[i] = inherit(prototypeColumn);
12938 if (select.roles)
12939 column.roles = select.roles;
12940 if (select.type)
12941 column.type = select.type;
12942 column.format = getFormatForColumn(select, column);
12943 if (select.displayName)
12944 column.displayName = select.displayName;
12945 if (select.queryName)
12946 column.queryName = select.queryName;
12947 if (select.kpi)
12948 column.kpi = select.kpi;
12949 if (select.sort)
12950 column.sort = select.sort;
12951 if (select.discourageAggregationAcrossGroups)
12952 column.discourageAggregationAcrossGroups = select.discourageAggregationAcrossGroups;
12953 rewrites.push({
12954 from: prototypeColumn,
12955 to: column,
12956 });
12957 }
12958 return columns;
12959 }
12960 /**
12961 * Get the column format. Order of precendence is:
12962 * 1. Select format
12963 * 2. Column format
12964 */
12965 function getFormatForColumn(select, column) {
12966 // TODO: we already copied the select.Format to column.format, we probably don't need this check
12967 return select.format || column.format;
12968 }
12969 function applyRewritesToCategorical(prototype, columnRewrites, selectsToInclude) {
12970 debug.assertValue(prototype, 'prototype');
12971 debug.assertValue(columnRewrites, 'columnRewrites');
12972 var categorical = inherit(prototype);
12973 function override(value) {
12974 var rewrittenSource = findOverride(value.source, columnRewrites);
12975 if (rewrittenSource) {
12976 var rewritten = inherit(value);
12977 rewritten.source = rewrittenSource;
12978 return rewritten;
12979 }
12980 }
12981 var categories = powerbi.Prototype.overrideArray(prototype.categories, override);
12982 if (categories)
12983 categorical.categories = categories;
12984 var valuesOverride = powerbi.Prototype.overrideArray(prototype.values, override);
12985 var valueColumns = valuesOverride || prototype.values;
12986 if (valueColumns) {
12987 if (valueColumns.source) {
12988 if (selectsToInclude && !selectsToInclude[valueColumns.source.index]) {
12989 // if processing a split and this is the split without series...
12990 valueColumns.source = undefined;
12991 }
12992 else {
12993 var rewrittenValuesSource = findOverride(valueColumns.source, columnRewrites);
12994 if (rewrittenValuesSource)
12995 valueColumns.source = rewrittenValuesSource;
12996 }
12997 }
12998 if (selectsToInclude) {
12999 // Apply selectsToInclude to values by removing value columns not included
13000 for (var i = valueColumns.length - 1; i >= 0; i--) {
13001 if (!selectsToInclude[valueColumns[i].source.index]) {
13002 valueColumns.splice(i, 1);
13003 }
13004 }
13005 }
13006 var isDynamicSeries_1 = !!valueColumns.source;
13007 debug.assert(_.every(valueColumns, function (valueColumn) { return isDynamicSeries_1 === !!valueColumn.identity; }), 'After applying selectsToInclude, all remaining DataViewValueColumn objects should have a consistent scope type (static vs. dynamic) with the parent DataViewValueColumns object.');
13008 // Dynamic or not, always update the return values of grouped() to have the rewritten 'source' property
13009 var seriesGroups_1;
13010 if (isDynamicSeries_1) {
13011 // We have a dynamic series, so update the return value of grouped() to have the DataViewValueColumn objects with rewritten 'source'.
13012 // Also, exclude any column that belongs to a static series.
13013 seriesGroups_1 = inherit(valueColumns.grouped());
13014 // The following assert is not a rule that's set in stone. If it becomes false someday, update the code below to remove static series from seriesGroups.
13015 debug.assert(_.every(seriesGroups_1, function (group) { return !!group.identity; }), 'If the categorical has a dynamic series, query DataView is expected to have a grouped() function that returns only dynamic series groups, even when there is any column that belongs to a static group (in the case of combo chart and splits). If this assertion becomes false someday, update the code below to remove static series from seriesGroups.');
13016 var nextSeriesGroupIndex = 0;
13017 var currentSeriesGroup = void 0;
13018 for (var i = 0, ilen = valueColumns.length; i < ilen; i++) {
13019 var currentValueColumn = valueColumns[i];
13020 if (!currentSeriesGroup || (currentValueColumn.identity !== currentSeriesGroup.identity)) {
13021 currentSeriesGroup = inherit(seriesGroups_1[nextSeriesGroupIndex]);
13022 seriesGroups_1[nextSeriesGroupIndex] = currentSeriesGroup;
13023 currentSeriesGroup.values = [];
13024 nextSeriesGroupIndex++;
13025 debug.assert(currentValueColumn.identity === currentSeriesGroup.identity, 'expecting the value columns are sequenced by series groups');
13026 }
13027 currentSeriesGroup.values.push(currentValueColumn);
13028 }
13029 }
13030 else {
13031 // We are in a static series, so we should throw away the grouped and recreate it using the static values
13032 // which have already been filtered
13033 seriesGroups_1 = [{ values: valueColumns }];
13034 }
13035 valueColumns.grouped = function () { return seriesGroups_1; };
13036 categorical.values = valueColumns;
13037 }
13038 return categorical;
13039 }
13040 function applyRewritesToTable(prototype, columnRewrites, projectionOrdering) {
13041 debug.assertValue(prototype, 'prototype');
13042 debug.assertValue(columnRewrites, 'columnRewrites');
13043 var table = inherit(prototype);
13044 // Copy the rewritten columns into the table view
13045 var override = function (metadata) { return findOverride(metadata, columnRewrites); };
13046 var columns = powerbi.Prototype.overrideArray(prototype.columns, override);
13047 if (columns)
13048 table.columns = columns;
13049 if (!projectionOrdering)
13050 return table;
13051 var newToOldPositions = createTableColumnPositionMapping(projectionOrdering, columnRewrites);
13052 if (!newToOldPositions)
13053 return table;
13054 // Reorder the columns
13055 var columnsClone = columns.slice(0);
13056 var keys = Object.keys(newToOldPositions);
13057 for (var i = 0, len = keys.length; i < len; i++) {
13058 var sourceColumn = columnsClone[newToOldPositions[keys[i]]];
13059 // In the case we've hit the end of our columns array, but still have position reordering keys,
13060 // there is a duplicate column so we will need to add a new column for the duplicate data
13061 if (i === columns.length)
13062 columns.push(sourceColumn);
13063 else {
13064 debug.assert(i < columns.length, 'The column index is out of range for reordering.');
13065 columns[i] = sourceColumn;
13066 }
13067 }
13068 // Reorder the rows
13069 var rows = powerbi.Prototype.overrideArray(table.rows, function (row) {
13070 var newRow = [];
13071 for (var i = 0, len = keys.length; i < len; ++i)
13072 newRow[i] = row[newToOldPositions[keys[i]]];
13073 return newRow;
13074 });
13075 if (rows)
13076 table.rows = rows;
13077 return table;
13078 }
13079 /** Creates a mapping of new position to original position. */
13080 function createTableColumnPositionMapping(projectionOrdering, columnRewrites) {
13081 var roles = Object.keys(projectionOrdering);
13082 // If we have more than one role then the ordering of columns between roles is ambiguous, so don't reorder anything.
13083 if (roles.length !== 1)
13084 return;
13085 var role = roles[0], originalOrder = _.map(columnRewrites, function (rewrite) { return rewrite.from.index; }), newOrder = projectionOrdering[role];
13086 return createOrderMapping(originalOrder, newOrder);
13087 }
13088 function applyRewritesToMatrix(prototype, columnRewrites, roleMappings, projectionOrdering, context) {
13089 debug.assertValue(prototype, 'prototype');
13090 debug.assertValue(columnRewrites, 'columnRewrites');
13091 debug.assertValue(roleMappings, 'roleMappings');
13092 var firstRoleMappingWithMatrix = _.find(roleMappings, function (roleMapping) { return !!roleMapping.matrix; });
13093 debug.assertValue(firstRoleMappingWithMatrix, 'roleMappings - at least one role mapping is expected to target DataViewMatrix');
13094 var matrixMapping = firstRoleMappingWithMatrix.matrix;
13095 var matrix = inherit(prototype);
13096 function override(metadata) {
13097 return findOverride(metadata, columnRewrites);
13098 }
13099 function overrideHierarchy(hierarchy) {
13100 var rewrittenHierarchy = null;
13101 var newLevels = powerbi.Prototype.overrideArray(hierarchy.levels, function (level) {
13102 var newLevel = null;
13103 var levelSources = powerbi.Prototype.overrideArray(level.sources, override);
13104 if (levelSources)
13105 newLevel = ensureRewritten(newLevel, level, function (h) { return h.sources = levelSources; });
13106 return newLevel;
13107 });
13108 if (newLevels)
13109 rewrittenHierarchy = ensureRewritten(rewrittenHierarchy, hierarchy, function (r) { return r.levels = newLevels; });
13110 return rewrittenHierarchy;
13111 }
13112 var rows = overrideHierarchy(matrix.rows);
13113 if (rows) {
13114 matrix.rows = rows;
13115 context.rowHierarchyRewritten = true;
13116 }
13117 var columns = overrideHierarchy(matrix.columns);
13118 if (columns) {
13119 matrix.columns = columns;
13120 context.columnHierarchyRewritten = true;
13121 }
13122 var valueSources = powerbi.Prototype.overrideArray(matrix.valueSources, override);
13123 if (valueSources) {
13124 matrix.valueSources = valueSources;
13125 // Only need to reorder if we have more than one value source, and they are all bound to the same role
13126 var matrixValues = matrixMapping.values;
13127 if (projectionOrdering && valueSources.length > 1 && matrixValues && matrixValues.for) {
13128 var columnLevels = columns.levels.length;
13129 if (columnLevels > 0) {
13130 var newToOldPositions_1 = createMatrixValuesPositionMapping(matrixValues, projectionOrdering, valueSources, columnRewrites);
13131 if (newToOldPositions_1) {
13132 var keys_1 = Object.keys(newToOldPositions_1);
13133 var numKeys_1 = keys_1.length;
13134 // Reorder the value columns
13135 columns.root = data.DataViewPivotMatrix.cloneTree(columns.root);
13136 if (columnLevels === 1)
13137 reorderChildNodes(columns.root, newToOldPositions_1);
13138 else
13139 forEachNodeAtLevel(columns.root, columnLevels - 2, function (node) { return reorderChildNodes(node, newToOldPositions_1); });
13140 // Reorder the value rows
13141 matrix.rows.root = data.DataViewPivotMatrix.cloneTreeExecuteOnLeaf(matrix.rows.root, function (node) {
13142 if (!node.values)
13143 return;
13144 var newValues = {};
13145 var iterations = Object.keys(node.values).length / numKeys_1;
13146 for (var i = 0, len = iterations; i < len; i++) {
13147 var offset = i * numKeys_1;
13148 for (var keysIndex = 0; keysIndex < numKeys_1; keysIndex++)
13149 newValues[offset + keysIndex] = node.values[offset + newToOldPositions_1[keys_1[keysIndex]]];
13150 }
13151 node.values = newValues;
13152 });
13153 context.hierarchyTreesRewritten = true;
13154 }
13155 }
13156 }
13157 }
13158 reorderMatrixCompositeGroups(matrix, matrixMapping, projectionOrdering);
13159 return matrix;
13160 }
13161 function reorderChildNodes(node, newToOldPositions) {
13162 var keys = Object.keys(newToOldPositions);
13163 var numKeys = keys.length;
13164 var children = node.children;
13165 var childrenClone = children.slice(0);
13166 for (var i = 0, len = numKeys; i < len; i++) {
13167 var sourceColumn = childrenClone[newToOldPositions[keys[i]]];
13168 // In the case we've hit the end of our columns array, but still have position reordering keys,
13169 // there is a duplicate column so we will need to add a new column for the duplicate data
13170 if (i === children.length)
13171 children.push(sourceColumn);
13172 else {
13173 debug.assert(i < children.length, 'The column index is out of range for reordering.');
13174 children[i] = sourceColumn;
13175 }
13176 }
13177 }
13178 /**
13179 * Returns a inheritSingle() version of the specified prototype DataViewMatrix with any composite group levels
13180 * and values re-ordered by projection ordering.
13181 * Returns undefined if no re-ordering under the specified prototype is necessary.
13182 */
13183 function reorderMatrixCompositeGroups(prototype, supportedDataViewMapping, projection) {
13184 var transformedDataView;
13185 if (prototype && supportedDataViewMapping && projection) {
13186 // reorder levelValues in any composite groups in rows hierarchy
13187 var transformedRowsHierarchy_1;
13188 powerbi.DataViewMapping.visitMatrixItems(supportedDataViewMapping.rows, {
13189 visitRole: function (role, context) {
13190 transformedRowsHierarchy_1 = reorderMatrixHierarchyCompositeGroups(transformedRowsHierarchy_1 || prototype.rows, role, projection);
13191 }
13192 });
13193 // reorder levelValues in any composite groups in columns hierarchy
13194 var transformedColumnsHierarchy_1;
13195 powerbi.DataViewMapping.visitMatrixItems(supportedDataViewMapping.columns, {
13196 visitRole: function (role, context) {
13197 transformedColumnsHierarchy_1 = reorderMatrixHierarchyCompositeGroups(transformedColumnsHierarchy_1 || prototype.columns, role, projection);
13198 }
13199 });
13200 if (transformedRowsHierarchy_1 || transformedColumnsHierarchy_1) {
13201 transformedDataView = inheritSingle(prototype);
13202 transformedDataView.rows = transformedRowsHierarchy_1 || transformedDataView.rows;
13203 transformedDataView.columns = transformedColumnsHierarchy_1 || transformedDataView.columns;
13204 }
13205 }
13206 return transformedDataView;
13207 }
13208 /**
13209 * Returns a inheritSingle() version of the specified matrixHierarchy with any composite group levels and
13210 * values re-ordered by projection ordering.
13211 * Returns undefined if no re-ordering under the specified matrixHierarchy is necessary.
13212 */
13213 function reorderMatrixHierarchyCompositeGroups(matrixHierarchy, hierarchyRole, projection) {
13214 debug.assertValue(matrixHierarchy, 'matrixHierarchy');
13215 debug.assertValue(hierarchyRole, 'hierarchyRole');
13216 debug.assertValue(projection, 'projection');
13217 var transformedHierarchy;
13218 var selectIndicesInProjectionOrder = projection[hierarchyRole];
13219 // reordering needs to happen only if there are multiple columns for the hierarchy's role in the projection
13220 var hasMultipleColumnsInProjection = selectIndicesInProjectionOrder && selectIndicesInProjectionOrder.length >= 2;
13221 if (hasMultipleColumnsInProjection && !_.isEmpty(matrixHierarchy.levels)) {
13222 for (var i = matrixHierarchy.levels.length - 1; i >= 0; i--) {
13223 var hierarchyLevel = matrixHierarchy.levels[i];
13224 // compute a mapping for any necessary reordering of columns at this given level, based on projection ordering
13225 var newToOldLevelSourceIndicesMapping = createMatrixHierarchyLevelSourcesPositionMapping(hierarchyLevel, hierarchyRole, projection);
13226 if (newToOldLevelSourceIndicesMapping) {
13227 if (_.isUndefined(transformedHierarchy)) {
13228 // Because we start inspecting the hierarchy from the deepest level and work backwards to the root,
13229 // the current hierarchyLevel is therefore the inner-most level that needs re-ordering of composite group values...
13230 transformedHierarchy = inheritSingle(matrixHierarchy);
13231 transformedHierarchy.levels = inheritSingle(matrixHierarchy.levels);
13232 // Because the current hierarchyLevel is the inner-most level that needs re-ordering of composite group values,
13233 // inheriting all nodes from root down to this level will also prepare the nodes for any transform that needs to
13234 // happen in other hierarchy levels in the later iterations of this for-loop.
13235 transformedHierarchy.root = data.utils.DataViewMatrixUtils.inheritMatrixNodeHierarchy(matrixHierarchy.root, i, true);
13236 }
13237 // reorder the metadata columns in the sources array at that level
13238 var transformingHierarchyLevel = inheritSingle(matrixHierarchy.levels[i]); // inherit at most once during the whole dataViewTransform for this obj...
13239 transformedHierarchy.levels[i] = reorderMatrixHierarchyLevelColumnSources(transformingHierarchyLevel, newToOldLevelSourceIndicesMapping);
13240 // reorder the level values in the composite group nodes at the current hierarchy level
13241 reorderMatrixHierarchyLevelValues(transformedHierarchy.root, i, newToOldLevelSourceIndicesMapping);
13242 }
13243 }
13244 }
13245 return transformedHierarchy;
13246 }
13247 /**
13248 * If reordering is needed on the level's metadata column sources (i.e. hierarchyLevel.sources),
13249 * returns the mapping from the target LevelSourceIndex (based on projection order) to original LevelSourceIndex.
13250 *
13251 * The returned value maps level source indices from the new target order (calculated from projection order)
13252 * back to the original order as they appear in the specified hierarchyLevel's sources.
13253 * Please refer to comments on the createOrderMapping() function for more explanation on the mappings in the return value.
13254 *
13255 * Note: The return value is the mapping from new index to old index, for consistency with existing and similar functions in this module.
13256 *
13257 * @param hierarchyLevel The hierarchy level that contains the metadata column sources.
13258 * @param hierarchyRoleName The role name for the hierarchy where the specified hierarchyLevel belongs.
13259 * @param projection The projection ordering that includes an ordering for the specified hierarchyRoleName.
13260 */
13261 function createMatrixHierarchyLevelSourcesPositionMapping(hierarchyLevel, hierarchyRole, projection) {
13262 debug.assertValue(hierarchyLevel, 'hierarchyLevel');
13263 debug.assertValue(hierarchyRole, 'hierarchyRole');
13264 debug.assertValue(projection, 'projection');
13265 debug.assertValue(projection[hierarchyRole], 'pre-condition: The specified projection must contain an ordering for the specified hierarchyRoleName.');
13266 var newToOldLevelSourceIndicesMapping;
13267 var levelSourceColumns = hierarchyLevel.sources;
13268 if (levelSourceColumns && levelSourceColumns.length >= 2) {
13269 // The hierarchy level has multiple columns, so it is possible to have composite group, go on to check other conditions...
13270 var columnsForHierarchyRoleOrderedByLevelSourceIndex = data.utils.DataViewMetadataColumnUtils.joinMetadataColumnsAndProjectionOrder(levelSourceColumns, projection, hierarchyRole);
13271 if (columnsForHierarchyRoleOrderedByLevelSourceIndex && columnsForHierarchyRoleOrderedByLevelSourceIndex.length >= 2) {
13272 // The hierarchy level has multiple columns for the hierarchy's role, go on to calculate newToOldLevelSourceIndicesMapping...
13273 var columnsForHierarchyRoleOrderedByProjection = _.sortBy(columnsForHierarchyRoleOrderedByLevelSourceIndex, function (columnInfo) { return columnInfo.projectionOrderIndex; });
13274 newToOldLevelSourceIndicesMapping = createOrderMapping(_.map(columnsForHierarchyRoleOrderedByLevelSourceIndex, function (columnInfo) { return columnInfo.sourceIndex; }), _.map(columnsForHierarchyRoleOrderedByProjection, function (columnInfo) { return columnInfo.sourceIndex; }));
13275 }
13276 }
13277 return newToOldLevelSourceIndicesMapping;
13278 }
13279 /**
13280 * Applies re-ordering on the specified transformingHierarchyLevel's sources.
13281 * Returns the same object as the specified transformingHierarchyLevel.
13282 */
13283 function reorderMatrixHierarchyLevelColumnSources(transformingHierarchyLevel, newToOldLevelSourceIndicesMapping) {
13284 debug.assertValue(transformingHierarchyLevel, 'transformingHierarchyLevel');
13285 debug.assertValue(newToOldLevelSourceIndicesMapping, 'newToOldLevelSourceIndicesMapping');
13286 var originalLevelSources = transformingHierarchyLevel.sources;
13287 transformingHierarchyLevel.sources = originalLevelSources.slice(0); // make a clone of the array before modifying it, because the for-loop depends on the origin array.
13288 var newLevelSourceIndices = Object.keys(newToOldLevelSourceIndicesMapping);
13289 for (var i = 0, ilen = newLevelSourceIndices.length; i < ilen; i++) {
13290 var newLevelSourceIndex = newLevelSourceIndices[i];
13291 var oldLevelSourceIndex = newToOldLevelSourceIndicesMapping[newLevelSourceIndex];
13292 debug.assert(oldLevelSourceIndex < originalLevelSources.length, 'pre-condition: The value in every mapping in the specified levelSourceIndicesReorderingMap must be a valid index to the specified hierarchyLevel.sources array property');
13293 transformingHierarchyLevel.sources[newLevelSourceIndex] = originalLevelSources[oldLevelSourceIndex];
13294 }
13295 return transformingHierarchyLevel;
13296 }
13297 /**
13298 * Reorders the elements in levelValues in each node under transformingHierarchyRootNode at the specified hierarchyLevel,
13299 * and updates their DataViewMatrixGroupValue.levelSourceIndex property.
13300 *
13301 * Returns the same object as the specified transformingHierarchyRootNode.
13302 */
13303 function reorderMatrixHierarchyLevelValues(transformingHierarchyRootNode, transformingHierarchyLevelIndex, newToOldLevelSourceIndicesMapping) {
13304 debug.assertValue(transformingHierarchyRootNode, 'transformingHierarchyRootNode');
13305 debug.assertValue(newToOldLevelSourceIndicesMapping, 'newToOldLevelSourceIndicesMapping');
13306 var oldToNewLevelSourceIndicesMapping = createReversedMapping(newToOldLevelSourceIndicesMapping);
13307 forEachNodeAtLevel(transformingHierarchyRootNode, transformingHierarchyLevelIndex, function (transformingMatrixNode) {
13308 var originalLevelValues = transformingMatrixNode.levelValues;
13309 // Note: Technically this function is incorrect, because the driving source of the new LevelValues is really
13310 // the "projection for this composite group", a concept that isn't yet implemented in DataViewProjectionOrdering.
13311 // The following code isn't correct in the special case where a column is projected twice in this composite group,
13312 // in which case the DSR will not have the duplicate columns; DataViewTransform is supposed to expand the duplicates.
13313 // Until we fully implement composite group projection, though, we'll just sort what we have in transformingMatrixNode.levelValues.
13314 if (!_.isEmpty(originalLevelValues)) {
13315 // First, re-order the elements in transformingMatrixNode.levelValues by the new levelSourceIndex order.
13316 // _.sortBy() also creates a new array, which we want to do for all nodes (including when levelValues.length === 1)
13317 // because we don't want to accidentally modify the array AND its value references in Query DataView
13318 var newlyOrderedLevelValues = _.sortBy(originalLevelValues, function (levelValue) { return oldToNewLevelSourceIndicesMapping[levelValue.levelSourceIndex]; });
13319 for (var i = 0, ilen = newlyOrderedLevelValues.length; i < ilen; i++) {
13320 var transformingLevelValue = inheritSingle(newlyOrderedLevelValues[i]);
13321 transformingLevelValue.levelSourceIndex = oldToNewLevelSourceIndicesMapping[transformingLevelValue.levelSourceIndex];
13322 newlyOrderedLevelValues[i] = transformingLevelValue;
13323 }
13324 transformingMatrixNode.levelValues = newlyOrderedLevelValues;
13325 // For consistency with how DataViewTreeNode.value works, and for a bit of backward compatibility,
13326 // copy the last value from DataViewMatrixNode.levelValues to DataViewMatrixNode.value.
13327 var newlyOrderedLastLevelValue = _.last(newlyOrderedLevelValues);
13328 if (transformingMatrixNode.value !== newlyOrderedLastLevelValue.value) {
13329 transformingMatrixNode.value = newlyOrderedLastLevelValue.value;
13330 }
13331 if ((transformingMatrixNode.levelSourceIndex || 0) !== newlyOrderedLastLevelValue.levelSourceIndex) {
13332 transformingMatrixNode.levelSourceIndex = newlyOrderedLastLevelValue.levelSourceIndex;
13333 }
13334 }
13335 });
13336 return transformingHierarchyRootNode;
13337 }
13338 /**
13339 * Creates a mapping of new position to original position.
13340 *
13341 * The return value is a mapping where each key-value pair represent the order mapping of a particular column:
13342 * - the key in the key-value pair is the index of the particular column in the new order (e.g. projection order)
13343 * - the value in the key-value pair is the index of the particular column in the original order
13344 */
13345 function createMatrixValuesPositionMapping(matrixValues, projectionOrdering, valueSources, columnRewrites) {
13346 var role = matrixValues.for.in;
13347 var newOrder = projectionOrdering[role];
13348 var originalOrder = _.chain(columnRewrites)
13349 .filter(function (rewrite) { return _.contains(valueSources, rewrite.to); })
13350 .map(function (rewrite) { return rewrite.from.index; })
13351 .value();
13352 return createOrderMapping(originalOrder, newOrder);
13353 }
13354 /**
13355 * Creates a mapping of indices, from indices to the specified newOrder array, back to indices to the specified
13356 * originalOrder array.
13357 * Each of the number value in originalOrder and newOrder is actually the unique key of a column (unqiue
13358 * under the context of the caller code), e.g. the Select Index in projection ordering array.
13359 * Also, the specified originalOrder must contain every value that exists in newOrder.
13360 *
13361 * If the specified originalOrder and newOrder are different in sequence order, then this function returns a collection of
13362 * key-value pair, each of which represents the new and old indices of a particular column:
13363 * - the key in each key-value pair is the index of the particular column key as it exists in the specified newOrder array
13364 * - the value in each key-value pair is the index of the particular column key as it exists in the specified originalOrder array
13365 *
13366 * For example on how the return value is consumed, see functions such as reorderMatrixHierarchyLevelColumnSources(...).
13367 *
13368 * If the specified originalOrder and newOrder are same, then this function returns undefined.
13369 *
13370 * @param originalOrder E.g. an array of metadata column "select indices", in the original order as they exist in Query DataView.
13371 * @param newOrder E.g. an array of metadata column "select indices", in rojection ordering.
13372 */
13373 function createOrderMapping(originalOrder, newOrder) {
13374 // Optimization: avoid rewriting if the current order is correct
13375 if (ArrayExtensions.sequenceEqual(originalOrder, newOrder, function (x, y) { return x === y; }))
13376 return;
13377 var mapping = {};
13378 for (var i = 0, len = newOrder.length; i < len; ++i) {
13379 var newPosition = newOrder[i];
13380 mapping[i] = originalOrder.indexOf(newPosition);
13381 }
13382 return mapping;
13383 }
13384 function createReversedMapping(mapping) {
13385 debug.assertValue(mapping, 'mapping');
13386 var reversed = {};
13387 for (var key in mapping) {
13388 // Note: key is a string after we get it out from mapping, thus we need to parse it
13389 // back into a number before putting it as the value in the reversed mapping
13390 var value = mapping[key];
13391 var keyAsNumber = parseInt(key, 10);
13392 reversed[value] = keyAsNumber;
13393 }
13394 debug.assertValue(Object.keys(mapping).length === Object.keys(reversed).length, 'pre-condition: The specified mapping must not contain any duplicate value because duplicate values are obmitted from the reversed mapping.');
13395 return reversed;
13396 }
13397 function forEachNodeAtLevel(node, targetLevel, callback) {
13398 debug.assertValue(node, 'node');
13399 debug.assert(targetLevel >= 0, 'argetLevel >= 0');
13400 debug.assertValue(callback, 'callback');
13401 if (node.level === targetLevel) {
13402 callback(node);
13403 return;
13404 }
13405 var children = node.children;
13406 if (children && children.length > 0) {
13407 for (var i = 0, ilen = children.length; i < ilen; i++)
13408 forEachNodeAtLevel(children[i], targetLevel, callback);
13409 }
13410 }
13411 DataViewTransform.forEachNodeAtLevel = forEachNodeAtLevel;
13412 function findOverride(source, columnRewrites) {
13413 for (var i = 0, len = columnRewrites.length; i < len; i++) {
13414 var columnRewrite = columnRewrites[i];
13415 if (columnRewrite.from === source)
13416 return columnRewrite.to;
13417 }
13418 }
13419 function ensureRewritten(rewritten, prototype, callback) {
13420 if (!rewritten)
13421 rewritten = inherit(prototype);
13422 if (callback)
13423 callback(rewritten);
13424 return rewritten;
13425 }
13426 function transformObjects(dataView, targetDataViewKinds, objectDescriptors, objectDefinitions, selectTransforms, colorAllocatorFactory) {
13427 debug.assertValue(dataView, 'dataView');
13428 debug.assertValue(targetDataViewKinds, 'targetDataViewKinds');
13429 debug.assertAnyValue(objectDescriptors, 'objectDescriptors');
13430 debug.assertAnyValue(objectDefinitions, 'objectDefinitions');
13431 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13432 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13433 if (!objectDescriptors)
13434 return;
13435 var objectsForAllSelectors = data.DataViewObjectEvaluationUtils.groupObjectsBySelector(objectDefinitions);
13436 data.DataViewObjectEvaluationUtils.addImplicitObjects(objectsForAllSelectors, objectDescriptors, dataView.metadata.columns, selectTransforms);
13437 var metadataOnce = objectsForAllSelectors.metadataOnce;
13438 var dataObjects = objectsForAllSelectors.data;
13439 if (metadataOnce)
13440 evaluateMetadataObjects(dataView, selectTransforms, objectDescriptors, metadataOnce.objects, dataObjects, colorAllocatorFactory);
13441 var metadataObjects = objectsForAllSelectors.metadata;
13442 if (metadataObjects) {
13443 for (var i = 0, len = metadataObjects.length; i < len; i++) {
13444 var metadataObject = metadataObjects[i];
13445 var objectDefns = metadataObject.objects;
13446 var colorAllocatorCache = populateColorAllocatorCache(dataView, selectTransforms, objectDefns, colorAllocatorFactory);
13447 evaluateMetadataRepetition(dataView, selectTransforms, objectDescriptors, metadataObject.selector, objectDefns, colorAllocatorCache);
13448 }
13449 }
13450 for (var i = 0, len = dataObjects.length; i < len; i++) {
13451 var dataObject = dataObjects[i];
13452 var objectDefns = dataObject.objects;
13453 var colorAllocatorCache = populateColorAllocatorCache(dataView, selectTransforms, objectDefns, colorAllocatorFactory);
13454 evaluateDataRepetition(dataView, targetDataViewKinds, selectTransforms, objectDescriptors, dataObject.selector, dataObject.rules, objectDefns, colorAllocatorCache);
13455 }
13456 var userDefined = objectsForAllSelectors.userDefined;
13457 if (userDefined) {
13458 // TODO: We only handle user defined objects at the metadata level, but should be able to support them with arbitrary repetition.
13459 evaluateUserDefinedObjects(dataView, selectTransforms, objectDescriptors, userDefined, colorAllocatorFactory);
13460 }
13461 }
13462 DataViewTransform.transformObjects = transformObjects;
13463 function evaluateUserDefinedObjects(dataView, selectTransforms, objectDescriptors, objectDefns, colorAllocatorFactory) {
13464 debug.assertValue(dataView, 'dataView');
13465 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13466 debug.assertValue(objectDescriptors, 'objectDescriptors');
13467 debug.assertValue(objectDefns, 'objectDefns');
13468 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13469 var dataViewObjects = dataView.metadata.objects;
13470 if (!dataViewObjects) {
13471 dataViewObjects = dataView.metadata.objects = {};
13472 }
13473 for (var _i = 0, objectDefns_1 = objectDefns; _i < objectDefns_1.length; _i++) {
13474 var objectDefn = objectDefns_1[_i];
13475 var id = objectDefn.selector.id;
13476 var colorAllocatorCache = populateColorAllocatorCache(dataView, selectTransforms, objectDefn.objects, colorAllocatorFactory);
13477 var evalContext = data.createStaticEvalContext(colorAllocatorCache, dataView, selectTransforms);
13478 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefn.objects);
13479 for (var objectName in objects) {
13480 var object = objects[objectName];
13481 var map = dataViewObjects[objectName];
13482 if (!map)
13483 map = dataViewObjects[objectName] = [];
13484 debug.assert(powerbi.DataViewObjects.isUserDefined(map), 'expected DataViewObjectMap');
13485 // NOTE: We do not check for duplicate ids.
13486 map.push({ id: id, object: object });
13487 }
13488 }
13489 }
13490 /** Evaluates and sets properties on the DataView metadata. */
13491 function evaluateMetadataObjects(dataView, selectTransforms, objectDescriptors, objectDefns, dataObjects, colorAllocatorFactory) {
13492 debug.assertValue(dataView, 'dataView');
13493 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13494 debug.assertValue(objectDescriptors, 'objectDescriptors');
13495 debug.assertValue(objectDefns, 'objectDefns');
13496 debug.assertValue(dataObjects, 'dataObjects');
13497 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13498 var colorAllocatorCache = populateColorAllocatorCache(dataView, selectTransforms, objectDefns, colorAllocatorFactory);
13499 var evalContext = data.createStaticEvalContext(colorAllocatorCache, dataView, selectTransforms);
13500 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns);
13501 if (objects) {
13502 dataView.metadata.objects = objects;
13503 for (var objectName in objects) {
13504 var object = objects[objectName], objectDesc = objectDescriptors[objectName];
13505 for (var propertyName in object) {
13506 var propertyDesc = objectDesc.properties[propertyName], ruleDesc = propertyDesc.rule;
13507 if (!ruleDesc)
13508 continue;
13509 var definition = createRuleEvaluationInstance(dataView, colorAllocatorFactory, ruleDesc, objectName, object[propertyName], propertyDesc.type);
13510 if (!definition)
13511 continue;
13512 dataObjects.push(definition);
13513 }
13514 }
13515 }
13516 }
13517 function createRuleEvaluationInstance(dataView, colorAllocatorFactory, ruleDesc, objectName, propertyValue, ruleType) {
13518 debug.assertValue(dataView, 'dataView');
13519 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13520 debug.assertValue(ruleDesc, 'ruleDesc');
13521 debug.assertValue(propertyValue, 'propertyValue');
13522 debug.assertValue(ruleType, 'ruleType');
13523 var ruleOutput = ruleDesc.output;
13524 if (!ruleOutput)
13525 return;
13526 var selectorToCreate = findSelectorForRuleInput(dataView, ruleOutput.selector);
13527 if (!selectorToCreate)
13528 return;
13529 if (ruleType.fillRule) {
13530 return createRuleEvaluationInstanceFillRule(dataView, colorAllocatorFactory, ruleDesc, selectorToCreate, objectName, propertyValue);
13531 }
13532 }
13533 function createRuleEvaluationInstanceFillRule(dataView, colorAllocatorFactory, ruleDesc, selectorToCreate, objectName, propertyValue) {
13534 debug.assertValue(dataView, 'dataView');
13535 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13536 debug.assertValue(ruleDesc, 'ruleDesc');
13537 debug.assertValue(selectorToCreate, 'selectorToCreate');
13538 debug.assertValue(propertyValue, 'propertyValue');
13539 var colorAllocator = tryCreateColorAllocatorForFillRule(dataView, colorAllocatorFactory, ruleDesc.inputRole, 1 /* Role */, propertyValue);
13540 if (!colorAllocator)
13541 return;
13542 var rule = new data.ColorRuleEvaluation(ruleDesc.inputRole, colorAllocator);
13543 var fillRuleProperties = {};
13544 fillRuleProperties[ruleDesc.output.property] = {
13545 solid: { color: rule }
13546 };
13547 return {
13548 selector: selectorToCreate,
13549 rules: [rule],
13550 objects: [{
13551 name: objectName,
13552 properties: fillRuleProperties,
13553 }]
13554 };
13555 }
13556 function tryCreateColorAllocatorForFillRule(dataView, colorAllocatorFactory, identifier, identifierKind, propertyValue) {
13557 debug.assertValue(dataView, 'dataView');
13558 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13559 debug.assertValue(identifier, 'identifier');
13560 debug.assertValue(identifierKind, 'identifierKind');
13561 debug.assertValue(propertyValue, 'propertyValue');
13562 if (propertyValue.linearGradient2)
13563 return createColorAllocatorLinearGradient2(dataView, colorAllocatorFactory, identifier, identifierKind, propertyValue, propertyValue.linearGradient2);
13564 if (propertyValue.linearGradient3)
13565 return createColorAllocatorLinearGradient3(dataView, colorAllocatorFactory, identifier, identifierKind, propertyValue, propertyValue.linearGradient3);
13566 }
13567 function createColorAllocatorLinearGradient2(dataView, colorAllocatorFactory, identifier, identifierKind, propertyValueFillRule, linearGradient2) {
13568 debug.assertValue(dataView, 'dataView');
13569 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13570 debug.assertValue(identifier, 'identifier');
13571 debug.assertValue(identifierKind, 'identifierKind');
13572 debug.assertValue(linearGradient2, 'linearGradient2');
13573 linearGradient2 = propertyValueFillRule.linearGradient2;
13574 if (linearGradient2.min.value === undefined ||
13575 linearGradient2.max.value === undefined) {
13576 var inputRange = findRuleInputColumnNumberRange(dataView, identifier, identifierKind);
13577 if (!inputRange)
13578 return;
13579 if (linearGradient2.min.value === undefined)
13580 linearGradient2.min.value = inputRange.min;
13581 if (linearGradient2.max.value === undefined)
13582 linearGradient2.max.value = inputRange.max;
13583 }
13584 return colorAllocatorFactory.linearGradient2(propertyValueFillRule.linearGradient2);
13585 }
13586 function createColorAllocatorLinearGradient3(dataView, colorAllocatorFactory, identifier, identifierKind, propertyValueFillRule, linearGradient3) {
13587 debug.assertValue(dataView, 'dataView');
13588 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13589 debug.assertValue(identifier, 'identifier');
13590 debug.assertValue(identifierKind, 'identifierKind');
13591 debug.assertValue(linearGradient3, 'linearGradient3');
13592 var splitScales;
13593 linearGradient3 = propertyValueFillRule.linearGradient3;
13594 if (linearGradient3.min.value === undefined ||
13595 linearGradient3.mid.value === undefined ||
13596 linearGradient3.max.value === undefined) {
13597 var inputRange = findRuleInputColumnNumberRange(dataView, identifier, identifierKind);
13598 if (!inputRange)
13599 return;
13600 splitScales =
13601 linearGradient3.min.value === undefined &&
13602 linearGradient3.max.value === undefined &&
13603 linearGradient3.mid.value !== undefined;
13604 if (linearGradient3.min.value === undefined) {
13605 linearGradient3.min.value = inputRange.min;
13606 }
13607 if (linearGradient3.max.value === undefined) {
13608 linearGradient3.max.value = inputRange.max;
13609 }
13610 if (linearGradient3.mid.value === undefined) {
13611 var midValue = (linearGradient3.max.value + linearGradient3.min.value) / 2;
13612 linearGradient3.mid.value = midValue;
13613 }
13614 }
13615 return colorAllocatorFactory.linearGradient3(propertyValueFillRule.linearGradient3, splitScales);
13616 }
13617 function populateColorAllocatorCache(dataView, selectTransforms, objectDefns, colorAllocatorFactory) {
13618 debug.assertValue(dataView, 'dataView');
13619 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13620 debug.assertValue(objectDefns, 'objectDefns');
13621 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
13622 var cache = data.createColorAllocatorCache();
13623 var staticEvalContext = data.createStaticEvalContext();
13624 for (var i = 0, len = objectDefns.length; i < len; i++) {
13625 var objectDefnProperties = objectDefns[i].properties;
13626 for (var propertyName in objectDefnProperties) {
13627 var fillProperty = objectDefnProperties[propertyName];
13628 if (fillProperty &&
13629 fillProperty.solid &&
13630 fillProperty.solid.color &&
13631 fillProperty.solid.color.kind === 23 /* FillRule */) {
13632 var fillRuleExpr = fillProperty.solid.color;
13633 var inputExprQueryName = findFirstQueryNameForExpr(selectTransforms, fillRuleExpr.input);
13634 if (!inputExprQueryName)
13635 continue;
13636 var fillRule = data.DataViewObjectEvaluator.evaluateProperty(staticEvalContext, fillRulePropertyDescriptor, fillRuleExpr.rule);
13637 var colorAllocator = tryCreateColorAllocatorForFillRule(dataView, colorAllocatorFactory, inputExprQueryName, 0 /* QueryName */, fillRule);
13638 if (colorAllocator)
13639 cache.register(fillRuleExpr, colorAllocator);
13640 }
13641 }
13642 }
13643 return cache;
13644 }
13645 function evaluateDataRepetition(dataView, targetDataViewKinds, selectTransforms, objectDescriptors, selector, rules, objectDefns, colorAllocatorCache) {
13646 debug.assertValue(dataView, 'dataView');
13647 debug.assertValue(targetDataViewKinds, 'targetDataViewKinds');
13648 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13649 debug.assertValue(objectDescriptors, 'objectDescriptors');
13650 debug.assertValue(selector, 'selector');
13651 debug.assertAnyValue(rules, 'rules');
13652 debug.assertValue(objectDefns, 'objectDefns');
13653 debug.assertValue(colorAllocatorCache, 'colorAllocatorFactory');
13654 var containsWildcard = data.Selector.containsWildcard(selector);
13655 var dataViewCategorical = dataView.categorical;
13656 if (dataViewCategorical && EnumExtensions.hasFlag(targetDataViewKinds, 1 /* Categorical */)) {
13657 // 1) Match against categories
13658 evaluateDataRepetitionCategoricalCategory(dataViewCategorical, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache);
13659 // 2) Match against valueGrouping
13660 evaluateDataRepetitionCategoricalValueGrouping(dataViewCategorical, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache);
13661 }
13662 var dataViewMatrix = dataView.matrix;
13663 if (dataViewMatrix && EnumExtensions.hasFlag(targetDataViewKinds, 2 /* Matrix */)) {
13664 var rewrittenMatrix = evaluateDataRepetitionMatrix(dataViewMatrix, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache);
13665 if (rewrittenMatrix) {
13666 // TODO: This mutates the DataView -- the assumption is that prototypal inheritance has already occurred. We should
13667 // revisit this, likely when we do lazy evaluation of DataView.
13668 dataView.matrix = rewrittenMatrix;
13669 }
13670 }
13671 var dataViewTable = dataView.table;
13672 if (dataViewTable && EnumExtensions.hasFlag(targetDataViewKinds, 8 /* Table */)) {
13673 var rewrittenSelector = rewriteTableRoleSelector(dataViewTable, selector);
13674 var rewrittenTable = evaluateDataRepetitionTable(dataViewTable, selectTransforms, objectDescriptors, rewrittenSelector, rules, containsWildcard, objectDefns, colorAllocatorCache);
13675 if (rewrittenTable) {
13676 // TODO: This mutates the DataView -- the assumption is that prototypal inheritance has already occurred. We should
13677 // revisit this, likely when we do lazy evaluation of DataView.
13678 dataView.table = rewrittenTable;
13679 }
13680 }
13681 }
13682 function rewriteTableRoleSelector(dataViewTable, selector) {
13683 if (data.Selector.hasRoleWildcard(selector)) {
13684 selector = findSelectorForRoleWildcard(dataViewTable, selector);
13685 }
13686 return selector;
13687 }
13688 function findSelectorForRoleWildcard(dataViewTable, selector) {
13689 var resultingSelector = {
13690 data: [],
13691 id: selector.id,
13692 metadata: selector.metadata
13693 };
13694 for (var _i = 0, _a = selector.data; _i < _a.length; _i++) {
13695 var dataSelector = _a[_i];
13696 if (data.Selector.isRoleWildcard(dataSelector)) {
13697 var selectorRoles = dataSelector.roles;
13698 var allColumnsBelongToSelectorRole = allColumnsBelongToRole(dataViewTable.columns, selectorRoles);
13699 var exprs = dataViewTable.identityFields;
13700 if (allColumnsBelongToSelectorRole && exprs) {
13701 resultingSelector.data.push(data.DataViewScopeWildcard.fromExprs(exprs));
13702 continue;
13703 }
13704 }
13705 if (isUniqueDataSelector(resultingSelector.data, dataSelector)) {
13706 resultingSelector.data.push(dataSelector);
13707 }
13708 }
13709 return resultingSelector;
13710 }
13711 function isUniqueDataSelector(dataSelectors, newSelector) {
13712 if (_.isEmpty(dataSelectors))
13713 return true;
13714 return !_.any(dataSelectors, function (dataSelector) { return dataSelector.key === newSelector.key; });
13715 }
13716 function allColumnsBelongToRole(columns, selectorRoles) {
13717 for (var _i = 0, columns_6 = columns; _i < columns_6.length; _i++) {
13718 var column = columns_6[_i];
13719 var roles = column.roles;
13720 if (!roles || !_.any(selectorRoles, function (selectorRole) { return roles[selectorRole]; }))
13721 return false;
13722 }
13723 return true;
13724 }
13725 function evaluateDataRepetitionCategoricalCategory(dataViewCategorical, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache) {
13726 debug.assertValue(dataViewCategorical, 'dataViewCategorical');
13727 debug.assertValue(objectDescriptors, 'objectDescriptors');
13728 debug.assertValue(selector, 'selector');
13729 debug.assertAnyValue(rules, 'rules');
13730 debug.assertValue(containsWildcard, 'containsWildcard');
13731 debug.assertValue(objectDefns, 'objectDefns');
13732 debug.assertValue(colorAllocatorCache, 'colorAllocatorCache');
13733 if (!dataViewCategorical.categories || dataViewCategorical.categories.length === 0)
13734 return;
13735 var targetColumn = findSelectedCategoricalColumn(dataViewCategorical, selector);
13736 if (!targetColumn)
13737 return;
13738 var identities = targetColumn.identities, foundMatch, evalContext = data.createCategoricalEvalContext(colorAllocatorCache, dataViewCategorical);
13739 if (!identities)
13740 return;
13741 debug.assert(targetColumn.column.values.length === identities.length, 'Column length mismatch');
13742 for (var i = 0, len = identities.length; i < len; i++) {
13743 var identity = identities[i];
13744 if (containsWildcard || data.Selector.matchesData(selector, [identity])) {
13745 evalContext.setCurrentRowIndex(i);
13746 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns);
13747 if (objects) {
13748 // TODO: This mutates the DataView -- the assumption is that prototypal inheritance has already occurred. We should
13749 // revisit this, likely when we do lazy evaluation of DataView.
13750 if (!targetColumn.column.objects) {
13751 targetColumn.column.objects = [];
13752 targetColumn.column.objects.length = len;
13753 }
13754 targetColumn.column.objects[i] = objects;
13755 }
13756 if (!containsWildcard)
13757 return true;
13758 foundMatch = true;
13759 }
13760 }
13761 return foundMatch;
13762 }
13763 function evaluateDataRepetitionCategoricalValueGrouping(dataViewCategorical, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache) {
13764 debug.assertValue(dataViewCategorical, 'dataViewCategorical');
13765 debug.assertValue(objectDescriptors, 'objectDescriptors');
13766 debug.assertValue(selector, 'selector');
13767 debug.assertAnyValue(rules, 'rules');
13768 debug.assertValue(containsWildcard, 'containsWildcard');
13769 debug.assertValue(objectDefns, 'objectDefns');
13770 debug.assertValue(colorAllocatorCache, 'colorAllocatorCache');
13771 var dataViewCategoricalValues = dataViewCategorical.values;
13772 if (!dataViewCategoricalValues || !dataViewCategoricalValues.identityFields)
13773 return;
13774 if (!data.Selector.matchesKeys(selector, [dataViewCategoricalValues.identityFields]))
13775 return;
13776 var valuesGrouped = dataViewCategoricalValues.grouped();
13777 if (!valuesGrouped)
13778 return;
13779 // NOTE: We do not set the evalContext row index below because iteration is over value groups (i.e., columns, no rows).
13780 // This should be enhanced in the future.
13781 var evalContext = data.createCategoricalEvalContext(colorAllocatorCache, dataViewCategorical);
13782 var foundMatch;
13783 for (var i = 0, len = valuesGrouped.length; i < len; i++) {
13784 var valueGroup = valuesGrouped[i];
13785 var selectorMetadata = selector.metadata;
13786 var valuesInGroup = valueGroup.values;
13787 if (containsWildcard || data.Selector.matchesData(selector, [valueGroup.identity])) {
13788 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns);
13789 if (objects) {
13790 // TODO: This mutates the DataView -- the assumption is that prototypal inheritance has already occurred. We should
13791 // revisit this, likely when we do lazy evaluation of DataView.
13792 if (selectorMetadata) {
13793 for (var j = 0, jlen = valuesInGroup.length; j < jlen; j++) {
13794 var valueColumn = valuesInGroup[j], valueSource = valueColumn.source;
13795 if (valueSource.queryName === selectorMetadata) {
13796 var valueSourceOverwrite = powerbi.Prototype.inherit(valueSource);
13797 valueSourceOverwrite.objects = objects;
13798 valueColumn.source = valueSourceOverwrite;
13799 foundMatch = true;
13800 break;
13801 }
13802 }
13803 }
13804 else {
13805 valueGroup.objects = objects;
13806 setGrouped(dataViewCategoricalValues, valuesGrouped);
13807 foundMatch = true;
13808 }
13809 }
13810 if (!containsWildcard)
13811 return true;
13812 }
13813 }
13814 return foundMatch;
13815 }
13816 function evaluateDataRepetitionMatrix(dataViewMatrix, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache) {
13817 var evalContext = data.createMatrixEvalContext(colorAllocatorCache, dataViewMatrix);
13818 var rewrittenRows = evaluateDataRepetitionMatrixHierarchy(evalContext, dataViewMatrix.rows, objectDescriptors, selector, rules, containsWildcard, objectDefns);
13819 var rewrittenCols = evaluateDataRepetitionMatrixHierarchy(evalContext, dataViewMatrix.columns, objectDescriptors, selector, rules, containsWildcard, objectDefns);
13820 if (rewrittenRows || rewrittenCols) {
13821 var rewrittenMatrix = inheritSingle(dataViewMatrix);
13822 if (rewrittenRows)
13823 rewrittenMatrix.rows = rewrittenRows;
13824 if (rewrittenCols)
13825 rewrittenMatrix.columns = rewrittenCols;
13826 return rewrittenMatrix;
13827 }
13828 }
13829 function evaluateDataRepetitionMatrixHierarchy(evalContext, dataViewMatrixHierarchy, objectDescriptors, selector, rules, containsWildcard, objectDefns) {
13830 debug.assertAnyValue(dataViewMatrixHierarchy, 'dataViewMatrixHierarchy');
13831 debug.assertValue(objectDescriptors, 'objectDescriptors');
13832 debug.assertValue(selector, 'selector');
13833 debug.assertAnyValue(rules, 'rules');
13834 debug.assertValue(objectDefns, 'objectDefns');
13835 if (!dataViewMatrixHierarchy)
13836 return;
13837 var root = dataViewMatrixHierarchy.root;
13838 if (!root)
13839 return;
13840 var rewrittenRoot = evaluateDataRepetitionMatrixNode(evalContext, root, objectDescriptors, selector, rules, containsWildcard, objectDefns);
13841 if (rewrittenRoot) {
13842 var rewrittenHierarchy = inheritSingle(dataViewMatrixHierarchy);
13843 rewrittenHierarchy.root = rewrittenRoot;
13844 return rewrittenHierarchy;
13845 }
13846 }
13847 function evaluateDataRepetitionMatrixNode(evalContext, dataViewNode, objectDescriptors, selector, rules, containsWildcard, objectDefns) {
13848 debug.assertValue(evalContext, 'evalContext');
13849 debug.assertValue(dataViewNode, 'dataViewNode');
13850 debug.assertValue(objectDescriptors, 'objectDescriptors');
13851 debug.assertValue(selector, 'selector');
13852 debug.assertAnyValue(rules, 'rules');
13853 debug.assertValue(objectDefns, 'objectDefns');
13854 var childNodes = dataViewNode.children;
13855 if (!childNodes)
13856 return;
13857 var rewrittenNode;
13858 var shouldSearchChildren;
13859 var childIdentityFields = dataViewNode.childIdentityFields;
13860 if (childIdentityFields) {
13861 // NOTE: selector matching in matrix currently only considers the current node, and does not consider parents as part of the match.
13862 shouldSearchChildren = data.Selector.matchesKeys(selector, [childIdentityFields]);
13863 }
13864 for (var i = 0, len = childNodes.length; i < len; i++) {
13865 var childNode = childNodes[i], identity = childNode.identity, rewrittenChildNode = null;
13866 if (shouldSearchChildren) {
13867 if (containsWildcard || data.Selector.matchesData(selector, [identity])) {
13868 // TODO: Need to initialize context for rule-based properties. Rule-based properties
13869 // (such as fillRule/gradients) are not currently implemented.
13870 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns);
13871 if (objects) {
13872 rewrittenChildNode = inheritSingle(childNode);
13873 rewrittenChildNode.objects = objects;
13874 }
13875 }
13876 }
13877 else {
13878 rewrittenChildNode = evaluateDataRepetitionMatrixNode(evalContext, childNode, objectDescriptors, selector, rules, containsWildcard, objectDefns);
13879 }
13880 if (rewrittenChildNode) {
13881 if (!rewrittenNode)
13882 rewrittenNode = inheritNodeAndChildren(dataViewNode);
13883 rewrittenNode.children[i] = rewrittenChildNode;
13884 if (!containsWildcard) {
13885 // NOTE: once we find a match for a non-wildcard selector, stop looking.
13886 break;
13887 }
13888 }
13889 }
13890 return rewrittenNode;
13891 }
13892 function inheritNodeAndChildren(node) {
13893 if (Object.getPrototypeOf(node) !== Object.prototype) {
13894 return node;
13895 }
13896 var inherited = inheritSingle(node);
13897 inherited.children = inherit(node.children);
13898 return inherited;
13899 }
13900 function evaluateDataRepetitionTable(dataViewTable, selectTransforms, objectDescriptors, selector, rules, containsWildcard, objectDefns, colorAllocatorCache) {
13901 debug.assertValue(dataViewTable, 'dataViewTable');
13902 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13903 debug.assertValue(objectDescriptors, 'objectDescriptors');
13904 debug.assertValue(selector, 'selector');
13905 debug.assertAnyValue(rules, 'rules');
13906 debug.assertValue(objectDefns, 'objectDefns');
13907 debug.assertValue(colorAllocatorCache, 'colorAllocatorCache');
13908 var evalContext = data.createTableEvalContext(colorAllocatorCache, dataViewTable, selectTransforms);
13909 var rewrittenRows = evaluateDataRepetitionTableRows(evalContext, dataViewTable.columns, dataViewTable.rows, dataViewTable.identity, dataViewTable.identityFields, objectDescriptors, selector, rules, containsWildcard, objectDefns);
13910 if (rewrittenRows) {
13911 var rewrittenTable = inheritSingle(dataViewTable);
13912 rewrittenTable.rows = rewrittenRows;
13913 return rewrittenTable;
13914 }
13915 }
13916 function evaluateDataRepetitionTableRows(evalContext, columns, rows, identities, identityFields, objectDescriptors, selector, rules, containsWildcard, objectDefns) {
13917 debug.assertValue(evalContext, 'evalContext');
13918 debug.assertValue(columns, 'columns');
13919 debug.assertValue(rows, 'rows');
13920 debug.assertAnyValue(identities, 'identities');
13921 debug.assertAnyValue(identityFields, 'identityFields');
13922 debug.assertValue(objectDescriptors, 'objectDescriptors');
13923 debug.assertValue(selector, 'selector');
13924 debug.assertAnyValue(rules, 'rules');
13925 debug.assertValue(objectDefns, 'objectDefns');
13926 if (_.isEmpty(identities) || _.isEmpty(identityFields))
13927 return;
13928 if (!selector.metadata ||
13929 !data.Selector.matchesKeys(selector, [identityFields]))
13930 return;
13931 var colIdx = _.findIndex(columns, function (col) { return col.queryName === selector.metadata; });
13932 if (colIdx < 0)
13933 return;
13934 debug.assert(rows.length === identities.length, 'row length mismatch');
13935 var colLen = columns.length;
13936 var inheritedRows;
13937 for (var rowIdx = 0, rowLen = identities.length; rowIdx < rowLen; rowIdx++) {
13938 var identity = identities[rowIdx];
13939 if (containsWildcard || data.Selector.matchesData(selector, [identity])) {
13940 evalContext.setCurrentRowIndex(rowIdx);
13941 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns);
13942 if (objects) {
13943 if (!inheritedRows)
13944 inheritedRows = inheritSingle(rows);
13945 var inheritedRow = inheritedRows[rowIdx] = inheritSingle(inheritedRows[rowIdx]);
13946 var objectsForColumns = inheritedRow.objects;
13947 if (!objectsForColumns)
13948 inheritedRow.objects = objectsForColumns = new Array(colLen);
13949 objectsForColumns[colIdx] = objects;
13950 }
13951 if (!containsWildcard)
13952 break;
13953 }
13954 }
13955 return inheritedRows;
13956 }
13957 function evaluateMetadataRepetition(dataView, selectTransforms, objectDescriptors, selector, objectDefns, colorAllocatorCache) {
13958 debug.assertValue(dataView, 'dataView');
13959 debug.assertAnyValue(selectTransforms, 'selectTransforms');
13960 debug.assertValue(objectDescriptors, 'objectDescriptors');
13961 debug.assertValue(selector, 'selector');
13962 debug.assertValue(objectDefns, 'objectDefns');
13963 debug.assertValue(colorAllocatorCache, 'colorAllocatorCache');
13964 // TODO: This mutates the DataView -- the assumption is that prototypal inheritance has already occurred. We should
13965 // revisit this, likely when we do lazy evaluation of DataView.
13966 var columns = dataView.metadata.columns, metadataId = selector.metadata, evalContext = data.createStaticEvalContext(colorAllocatorCache, dataView, selectTransforms);
13967 for (var i = 0, len = columns.length; i < len; i++) {
13968 var column = columns[i];
13969 if (column.queryName === metadataId) {
13970 var objects = data.DataViewObjectEvaluationUtils.evaluateDataViewObjects(evalContext, objectDescriptors, objectDefns);
13971 if (objects)
13972 column.objects = objects;
13973 }
13974 }
13975 }
13976 /** Attempts to find a column that can possibly match the selector. */
13977 function findSelectedCategoricalColumn(dataViewCategorical, selector) {
13978 debug.assertValue(dataViewCategorical.categories[0], 'dataViewCategorical.categories[0]');
13979 var categoricalColumn = dataViewCategorical.categories[0];
13980 if (!categoricalColumn.identityFields)
13981 return;
13982 if (!data.Selector.matchesKeys(selector, [categoricalColumn.identityFields]))
13983 return;
13984 var identities = categoricalColumn.identity, targetColumn = categoricalColumn;
13985 var selectedMetadataId = selector.metadata;
13986 if (selectedMetadataId) {
13987 var valueColumns = dataViewCategorical.values;
13988 if (valueColumns) {
13989 for (var i = 0, len = valueColumns.length; i < len; i++) {
13990 var valueColumn = valueColumns[i];
13991 if (valueColumn.source.queryName === selectedMetadataId) {
13992 targetColumn = valueColumn;
13993 break;
13994 }
13995 }
13996 }
13997 }
13998 return {
13999 column: targetColumn,
14000 identities: identities,
14001 };
14002 }
14003 function findSelectorForRuleInput(dataView, selectorRoles) {
14004 debug.assertValue(dataView, 'dataView');
14005 debug.assertValue(selectorRoles, 'selectorRoles');
14006 if (selectorRoles.length !== 1)
14007 return;
14008 var dataViewCategorical = dataView.categorical;
14009 if (!dataViewCategorical)
14010 return;
14011 var categories = dataViewCategorical.categories;
14012 if (!categories || categories.length !== 1)
14013 return;
14014 var categoryColumn = categories[0], categoryRoles = categoryColumn.source.roles, categoryIdentityFields = categoryColumn.identityFields;
14015 if (!categoryRoles || !categoryIdentityFields || !categoryRoles[selectorRoles[0]])
14016 return;
14017 return { data: [data.DataViewScopeWildcard.fromExprs(categoryIdentityFields)] };
14018 }
14019 function findFirstQueryNameForExpr(selectTransforms, expr) {
14020 debug.assertAnyValue(selectTransforms, 'selectTransforms');
14021 debug.assertValue(expr, 'expr');
14022 if (data.SQExpr.isSelectRef(expr))
14023 return expr.expressionName;
14024 if (!selectTransforms)
14025 return;
14026 for (var i = 0, len = selectTransforms.length; i < len; i++) {
14027 var select = selectTransforms[i], columnExpr = select.expr;
14028 if (!columnExpr || !data.SQExpr.equals(expr, select.expr))
14029 continue;
14030 return select.queryName;
14031 }
14032 }
14033 /** Attempts to find the value range for the single column with the given identifier/identifierKind. */
14034 function findRuleInputColumnNumberRange(dataView, identifier, identifierKind) {
14035 debug.assertValue(dataView, 'dataView');
14036 debug.assertValue(identifier, 'identifier');
14037 debug.assertValue(identifierKind, 'identifierKind');
14038 var columns = dataView.metadata.columns;
14039 for (var i = 0, len = columns.length; i < len; i++) {
14040 var column = columns[i];
14041 if (identifierKind === 1 /* Role */) {
14042 var valueColRoles = column.roles;
14043 if (!valueColRoles || !valueColRoles[identifier])
14044 continue;
14045 }
14046 else {
14047 debug.assert(identifierKind === 0 /* QueryName */, 'identifierKind === ColumnIdentifierKind.QueryName');
14048 if (column.queryName !== identifier)
14049 continue;
14050 }
14051 var aggregates = column.aggregates;
14052 if (!aggregates)
14053 continue;
14054 var min = aggregates.min;
14055 if (min === undefined)
14056 min = aggregates.minLocal;
14057 if (min === undefined)
14058 continue;
14059 var max = aggregates.max;
14060 if (max === undefined)
14061 max = aggregates.maxLocal;
14062 if (max === undefined)
14063 continue;
14064 return { min: min, max: max };
14065 }
14066 }
14067 // TODO: refactor this, setGrouped, and groupValues to a test helper to stop using it in the product
14068 function createValueColumns(values, valueIdentityFields, source) {
14069 if (values === void 0) { values = []; }
14070 var result = values;
14071 setGrouped(values);
14072 if (valueIdentityFields)
14073 result.identityFields = valueIdentityFields;
14074 if (source)
14075 result.source = source;
14076 return result;
14077 }
14078 DataViewTransform.createValueColumns = createValueColumns;
14079 function setGrouped(values, groupedResult) {
14080 values.grouped = groupedResult
14081 ? function () { return groupedResult; }
14082 : function () { return groupValues(values); };
14083 }
14084 DataViewTransform.setGrouped = setGrouped;
14085 /** Group together the values with a common identity. */
14086 function groupValues(values) {
14087 debug.assertValue(values, 'values');
14088 var groups = [], currentGroup;
14089 for (var i = 0, len = values.length; i < len; i++) {
14090 var value = values[i];
14091 if (!currentGroup || currentGroup.identity !== value.identity) {
14092 currentGroup = {
14093 values: []
14094 };
14095 if (value.identity) {
14096 currentGroup.identity = value.identity;
14097 var source = value.source;
14098 // allow null, which will be formatted as (Blank).
14099 if (source.groupName !== undefined)
14100 currentGroup.name = source.groupName;
14101 else if (source.displayName)
14102 currentGroup.name = source.displayName;
14103 }
14104 groups.push(currentGroup);
14105 }
14106 currentGroup.values.push(value);
14107 }
14108 return groups;
14109 }
14110 function pivotIfNecessary(dataView, dataViewMappings) {
14111 debug.assertValue(dataView, 'dataView');
14112 var transformedDataView;
14113 switch (determineCategoricalTransformation(dataView.categorical, dataViewMappings)) {
14114 case 1 /* Pivot */:
14115 transformedDataView = data.DataViewPivotCategorical.apply(dataView);
14116 break;
14117 case 2 /* SelfCrossJoin */:
14118 transformedDataView = data.DataViewSelfCrossJoin.apply(dataView);
14119 break;
14120 }
14121 return transformedDataView || dataView;
14122 }
14123 function determineCategoricalTransformation(categorical, dataViewMappings) {
14124 if (!categorical || _.isEmpty(dataViewMappings))
14125 return;
14126 var categories = categorical.categories;
14127 if (!categories || categories.length !== 1)
14128 return;
14129 var values = categorical.values;
14130 if (_.isEmpty(values))
14131 return;
14132 if (values.grouped().some(function (vg) { return !!vg.identity; }))
14133 return;
14134 // If we made it here, the DataView has a single category and no valueGrouping.
14135 var categoryRoles = categories[0].source.roles;
14136 for (var i = 0, len = dataViewMappings.length; i < len; i++) {
14137 var roleMappingCategorical = dataViewMappings[i].categorical;
14138 if (!roleMappingCategorical)
14139 continue;
14140 if (!hasRolesGrouped(categoryRoles, roleMappingCategorical.values))
14141 continue;
14142 // If we made it here, the DataView's single category has the value grouping role.
14143 var categoriesMapping = roleMappingCategorical.categories;
14144 var hasCategoryRole = hasRolesBind(categoryRoles, categoriesMapping) ||
14145 hasRolesFor(categoryRoles, categoriesMapping);
14146 if (hasCategoryRole)
14147 return 2 /* SelfCrossJoin */;
14148 return 1 /* Pivot */;
14149 }
14150 }
14151 function shouldPivotMatrix(matrix, dataViewMappings) {
14152 if (!matrix || _.isEmpty(dataViewMappings))
14153 return;
14154 var rowLevels = matrix.rows.levels;
14155 if (rowLevels.length < 1)
14156 return;
14157 var rows = matrix.rows.root.children;
14158 if (!rows || rows.length === 0)
14159 return;
14160 var rowRoles = rowLevels[0].sources[0].roles;
14161 for (var i = 0, len = dataViewMappings.length; i < len; i++) {
14162 var roleMappingMatrix = dataViewMappings[i].matrix;
14163 if (!roleMappingMatrix)
14164 continue;
14165 if (!hasRolesFor(rowRoles, roleMappingMatrix.rows) &&
14166 hasRolesFor(rowRoles, roleMappingMatrix.columns)) {
14167 return true;
14168 }
14169 }
14170 }
14171 function hasRolesBind(roles, roleMapping) {
14172 if (roles && roleMapping && roleMapping.bind)
14173 return roles[roleMapping.bind.to];
14174 }
14175 function hasRolesFor(roles, roleMapping) {
14176 if (roles && roleMapping && roleMapping.for)
14177 return roles[roleMapping.for.in];
14178 }
14179 function hasRolesGrouped(roles, roleMapping) {
14180 if (roles && roleMapping && roleMapping.group)
14181 return roles[roleMapping.group.by];
14182 }
14183 })(DataViewTransform = data.DataViewTransform || (data.DataViewTransform = {}));
14184 })(data = powerbi.data || (powerbi.data = {}));
14185})(powerbi || (powerbi = {}));
14186/*
14187 * Power BI Visualizations
14188 *
14189 * Copyright (c) Microsoft Corporation
14190 * All rights reserved.
14191 * MIT License
14192 *
14193 * Permission is hereby granted, free of charge, to any person obtaining a copy
14194 * of this software and associated documentation files (the ""Software""), to deal
14195 * in the Software without restriction, including without limitation the rights
14196 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14197 * copies of the Software, and to permit persons to whom the Software is
14198 * furnished to do so, subject to the following conditions:
14199 *
14200 * The above copyright notice and this permission notice shall be included in
14201 * all copies or substantial portions of the Software.
14202 *
14203 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14204 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14205 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14206 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14207 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14208 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14209 * THE SOFTWARE.
14210 */
14211var powerbi;
14212(function (powerbi) {
14213 var data;
14214 (function (data) {
14215 function createDisplayNameGetter(displayNameKey) {
14216 return function (resourceProvider) { return resourceProvider.get(displayNameKey); };
14217 }
14218 data.createDisplayNameGetter = createDisplayNameGetter;
14219 function getDisplayName(displayNameGetter, resourceProvider) {
14220 if (typeof displayNameGetter === 'function')
14221 return displayNameGetter(resourceProvider);
14222 if (typeof displayNameGetter === 'string')
14223 return displayNameGetter;
14224 }
14225 data.getDisplayName = getDisplayName;
14226 })(data = powerbi.data || (powerbi.data = {}));
14227})(powerbi || (powerbi = {}));
14228/*
14229 * Power BI Visualizations
14230 *
14231 * Copyright (c) Microsoft Corporation
14232 * All rights reserved.
14233 * MIT License
14234 *
14235 * Permission is hereby granted, free of charge, to any person obtaining a copy
14236 * of this software and associated documentation files (the ""Software""), to deal
14237 * in the Software without restriction, including without limitation the rights
14238 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14239 * copies of the Software, and to permit persons to whom the Software is
14240 * furnished to do so, subject to the following conditions:
14241 *
14242 * The above copyright notice and this permission notice shall be included in
14243 * all copies or substantial portions of the Software.
14244 *
14245 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14246 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14247 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14248 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14249 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14250 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14251 * THE SOFTWARE.
14252 */
14253/*
14254 * Power BI Visualizations
14255 *
14256 * Copyright (c) Microsoft Corporation
14257 * All rights reserved.
14258 * MIT License
14259 *
14260 * Permission is hereby granted, free of charge, to any person obtaining a copy
14261 * of this software and associated documentation files (the ""Software""), to deal
14262 * in the Software without restriction, including without limitation the rights
14263 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14264 * copies of the Software, and to permit persons to whom the Software is
14265 * furnished to do so, subject to the following conditions:
14266 *
14267 * The above copyright notice and this permission notice shall be included in
14268 * all copies or substantial portions of the Software.
14269 *
14270 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14271 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14272 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14273 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14274 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14275 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14276 * THE SOFTWARE.
14277 */
14278var powerbi;
14279(function (powerbi) {
14280 /** Enumeration of DateTimeUnits */
14281 (function (DateTimeUnit) {
14282 DateTimeUnit[DateTimeUnit["Year"] = 0] = "Year";
14283 DateTimeUnit[DateTimeUnit["Month"] = 1] = "Month";
14284 DateTimeUnit[DateTimeUnit["Week"] = 2] = "Week";
14285 DateTimeUnit[DateTimeUnit["Day"] = 3] = "Day";
14286 DateTimeUnit[DateTimeUnit["Hour"] = 4] = "Hour";
14287 DateTimeUnit[DateTimeUnit["Minute"] = 5] = "Minute";
14288 DateTimeUnit[DateTimeUnit["Second"] = 6] = "Second";
14289 DateTimeUnit[DateTimeUnit["Millisecond"] = 7] = "Millisecond";
14290 })(powerbi.DateTimeUnit || (powerbi.DateTimeUnit = {}));
14291 var DateTimeUnit = powerbi.DateTimeUnit;
14292})(powerbi || (powerbi = {}));
14293/*
14294 * Power BI Visualizations
14295 *
14296 * Copyright (c) Microsoft Corporation
14297 * All rights reserved.
14298 * MIT License
14299 *
14300 * Permission is hereby granted, free of charge, to any person obtaining a copy
14301 * of this software and associated documentation files (the ""Software""), to deal
14302 * in the Software without restriction, including without limitation the rights
14303 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14304 * copies of the Software, and to permit persons to whom the Software is
14305 * furnished to do so, subject to the following conditions:
14306 *
14307 * The above copyright notice and this permission notice shall be included in
14308 * all copies or substantial portions of the Software.
14309 *
14310 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14311 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14312 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14313 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14314 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14315 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14316 * THE SOFTWARE.
14317 */
14318var powerbi;
14319(function (powerbi) {
14320 var data;
14321 (function (data) {
14322 var SQExprBuilder;
14323 (function (SQExprBuilder) {
14324 function fieldExpr(fieldExpr) {
14325 var sqExpr = FieldExprPattern.visit(fieldExpr, FieldExprToSQExprVisitor.instance);
14326 debug.assertValue(sqExpr, 'Failed to convert FieldExprPattern into SQExpr');
14327 return sqExpr;
14328 }
14329 SQExprBuilder.fieldExpr = fieldExpr;
14330 function fromColumnAggr(columnAggr) {
14331 return SQExprBuilder.aggregate(fromColumn(columnAggr), columnAggr.aggregate);
14332 }
14333 SQExprBuilder.fromColumnAggr = fromColumnAggr;
14334 function fromColumn(column) {
14335 return SQExprBuilder.columnRef(fromEntity(column), column.name);
14336 }
14337 SQExprBuilder.fromColumn = fromColumn;
14338 function fromEntity(entityPattern) {
14339 return SQExprBuilder.entity(entityPattern.schema, entityPattern.entity, entityPattern.entityVar);
14340 }
14341 SQExprBuilder.fromEntity = fromEntity;
14342 function fromEntityAggr(entityAggr) {
14343 return SQExprBuilder.aggregate(fromEntity(entityAggr), entityAggr.aggregate);
14344 }
14345 SQExprBuilder.fromEntityAggr = fromEntityAggr;
14346 function fromHierarchyLevelAggr(hierarchyLevelAggr) {
14347 return SQExprBuilder.aggregate(fromHierarchyLevel(hierarchyLevelAggr), hierarchyLevelAggr.aggregate);
14348 }
14349 SQExprBuilder.fromHierarchyLevelAggr = fromHierarchyLevelAggr;
14350 function fromHierarchyLevel(hierarchyLevelPattern) {
14351 return SQExprBuilder.hierarchyLevel(fromHierarchy(hierarchyLevelPattern), hierarchyLevelPattern.level);
14352 }
14353 SQExprBuilder.fromHierarchyLevel = fromHierarchyLevel;
14354 function fromHierarchy(hierarchyPattern) {
14355 return SQExprBuilder.hierarchy(fromEntity(hierarchyPattern), hierarchyPattern.name);
14356 }
14357 SQExprBuilder.fromHierarchy = fromHierarchy;
14358 var FieldExprToSQExprVisitor = (function () {
14359 function FieldExprToSQExprVisitor() {
14360 }
14361 FieldExprToSQExprVisitor.prototype.visitColumn = function (column) {
14362 return fromColumn(column);
14363 };
14364 FieldExprToSQExprVisitor.prototype.visitColumnAggr = function (columnAggr) {
14365 return fromColumnAggr(columnAggr);
14366 };
14367 FieldExprToSQExprVisitor.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariationPattern) {
14368 return SQExprBuilder.propertyVariationSource(this.visitEntity(columnHierarchyLevelVariationPattern.source), columnHierarchyLevelVariationPattern.source.name, columnHierarchyLevelVariationPattern.level.name);
14369 };
14370 FieldExprToSQExprVisitor.prototype.visitEntity = function (entityPattern) {
14371 return fromEntity(entityPattern);
14372 };
14373 FieldExprToSQExprVisitor.prototype.visitEntityAggr = function (entityAggr) {
14374 return fromEntityAggr(entityAggr);
14375 };
14376 FieldExprToSQExprVisitor.prototype.visitHierarchy = function (hierarchyPattern) {
14377 return fromHierarchy(hierarchyPattern);
14378 };
14379 FieldExprToSQExprVisitor.prototype.visitHierarchyLevel = function (level) {
14380 return fromHierarchyLevel(level);
14381 };
14382 FieldExprToSQExprVisitor.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
14383 return fromHierarchyLevelAggr(hierarchyLevelAggr);
14384 };
14385 FieldExprToSQExprVisitor.prototype.visitMeasure = function (measure) {
14386 return SQExprBuilder.measureRef(this.visitEntity(measure), measure.name);
14387 };
14388 FieldExprToSQExprVisitor.prototype.visitPercentile = function (percentile) {
14389 var arg = SQExprBuilder.fieldExpr(percentile.arg);
14390 return SQExprBuilder.percentile(arg, percentile.k, percentile.exclusive);
14391 };
14392 FieldExprToSQExprVisitor.prototype.visitPercentOfGrandTotal = function (percentOfGrandTotal) {
14393 var baseSQExpr = SQExprBuilder.fieldExpr(percentOfGrandTotal.baseExpr);
14394 return SQExprBuilder.arithmetic(baseSQExpr, SQExprBuilder.scopedEval(baseSQExpr, []), 3 /* Divide */);
14395 };
14396 FieldExprToSQExprVisitor.prototype.visitSelectRef = function (selectRef) {
14397 return SQExprBuilder.selectRef(selectRef.expressionName);
14398 };
14399 FieldExprToSQExprVisitor.instance = new FieldExprToSQExprVisitor();
14400 return FieldExprToSQExprVisitor;
14401 }());
14402 })(SQExprBuilder = data.SQExprBuilder || (data.SQExprBuilder = {}));
14403 var SQExprConverter;
14404 (function (SQExprConverter) {
14405 function asFieldPattern(sqExpr) {
14406 return sqExpr.accept(FieldExprPatternBuilder.instance);
14407 }
14408 SQExprConverter.asFieldPattern = asFieldPattern;
14409 })(SQExprConverter = data.SQExprConverter || (data.SQExprConverter = {}));
14410 var FieldExprPatternBuilder = (function (_super) {
14411 __extends(FieldExprPatternBuilder, _super);
14412 function FieldExprPatternBuilder() {
14413 _super.apply(this, arguments);
14414 }
14415 FieldExprPatternBuilder.prototype.visitColumnRef = function (expr) {
14416 var sourceRef = expr.source.accept(SourceExprPatternBuilder.instance);
14417 if (!sourceRef)
14418 return;
14419 if (sourceRef.entity) {
14420 var columnRef = sourceRef.entity;
14421 columnRef.name = expr.ref;
14422 return { column: columnRef };
14423 }
14424 };
14425 FieldExprPatternBuilder.prototype.visitMeasureRef = function (expr) {
14426 var sourceRef = expr.source.accept(SourceExprPatternBuilder.instance);
14427 if (!sourceRef)
14428 return;
14429 if (sourceRef.entity) {
14430 var measureRef = sourceRef.entity;
14431 measureRef.name = expr.ref;
14432 return { measure: measureRef };
14433 }
14434 };
14435 FieldExprPatternBuilder.prototype.visitEntity = function (expr) {
14436 var entityRef = {
14437 schema: expr.schema,
14438 entity: expr.entity
14439 };
14440 if (expr.variable)
14441 entityRef.entityVar = expr.variable;
14442 return { entity: entityRef };
14443 };
14444 FieldExprPatternBuilder.prototype.visitAggr = function (expr) {
14445 var fieldPattern = expr.arg.accept(this);
14446 if (fieldPattern && fieldPattern.column) {
14447 var argAggr = fieldPattern.column;
14448 argAggr.aggregate = expr.func;
14449 return { columnAggr: argAggr };
14450 }
14451 else if (fieldPattern && fieldPattern.columnAggr) {
14452 var argAggr = fieldPattern.columnAggr;
14453 argAggr.aggregate = expr.func;
14454 return { columnAggr: argAggr };
14455 }
14456 else if (fieldPattern && fieldPattern.hierarchyLevel) {
14457 var argAggr = fieldPattern.hierarchyLevel;
14458 argAggr.aggregate = expr.func;
14459 return { hierarchyLevelAggr: argAggr };
14460 }
14461 var sourcePattern = expr.arg.accept(SourceExprPatternBuilder.instance);
14462 if (sourcePattern && sourcePattern.entity) {
14463 var argAggr = sourcePattern.entity;
14464 argAggr.aggregate = expr.func;
14465 return { entityAggr: argAggr };
14466 }
14467 };
14468 FieldExprPatternBuilder.prototype.visitPercentile = function (expr) {
14469 return {
14470 percentile: {
14471 arg: expr.arg.accept(this),
14472 k: expr.k,
14473 exclusive: expr.exclusive,
14474 }
14475 };
14476 };
14477 FieldExprPatternBuilder.prototype.visitHierarchy = function (expr) {
14478 var sourcePattern = expr.arg.accept(SourceExprPatternBuilder.instance);
14479 if (sourcePattern && sourcePattern.entity) {
14480 var hierarchyRef = (sourcePattern.entity);
14481 hierarchyRef.name = expr.hierarchy;
14482 return { hierarchy: hierarchyRef };
14483 }
14484 };
14485 FieldExprPatternBuilder.prototype.visitHierarchyLevel = function (expr) {
14486 var hierarchySourceExprPattern = expr.arg.accept(HierarchyExprPatternBuiler.instance);
14487 if (!hierarchySourceExprPattern)
14488 return;
14489 var hierarchyLevel;
14490 if (hierarchySourceExprPattern.hierarchy) {
14491 hierarchyLevel = {
14492 entity: hierarchySourceExprPattern.hierarchy.entity,
14493 schema: hierarchySourceExprPattern.hierarchy.schema,
14494 name: hierarchySourceExprPattern.hierarchy.name,
14495 level: expr.level,
14496 };
14497 }
14498 if (hierarchySourceExprPattern.variation) {
14499 return {
14500 columnHierarchyLevelVariation: {
14501 source: {
14502 entity: hierarchySourceExprPattern.variation.column.entity,
14503 schema: hierarchySourceExprPattern.variation.column.schema,
14504 name: hierarchySourceExprPattern.variation.column.name,
14505 },
14506 level: hierarchyLevel,
14507 variationName: hierarchySourceExprPattern.variation.variationName,
14508 }
14509 };
14510 }
14511 return { hierarchyLevel: hierarchyLevel };
14512 };
14513 FieldExprPatternBuilder.prototype.visitArithmetic = function (expr) {
14514 var percentOfGrandTotalPattern = {
14515 percentOfGrandTotal: {
14516 baseExpr: expr.left.accept(this)
14517 }
14518 };
14519 if (data.SQExpr.equals(expr, SQExprBuilder.fieldExpr(percentOfGrandTotalPattern))) {
14520 return percentOfGrandTotalPattern;
14521 }
14522 };
14523 FieldExprPatternBuilder.prototype.visitSelectRef = function (expr) {
14524 return {
14525 selectRef: {
14526 expressionName: expr.expressionName,
14527 }
14528 };
14529 };
14530 FieldExprPatternBuilder.instance = new FieldExprPatternBuilder();
14531 return FieldExprPatternBuilder;
14532 }(data.DefaultSQExprVisitor));
14533 var SourceExprPatternBuilder = (function (_super) {
14534 __extends(SourceExprPatternBuilder, _super);
14535 function SourceExprPatternBuilder() {
14536 _super.apply(this, arguments);
14537 }
14538 SourceExprPatternBuilder.prototype.visitEntity = function (expr) {
14539 var entityRef = {
14540 schema: expr.schema,
14541 entity: expr.entity
14542 };
14543 if (expr.variable)
14544 entityRef.entityVar = expr.variable;
14545 return { entity: entityRef };
14546 };
14547 SourceExprPatternBuilder.prototype.visitPropertyVariationSource = function (expr) {
14548 var entityExpr = expr.arg;
14549 if (entityExpr instanceof data.SQEntityExpr) {
14550 var propertyVariationSource = {
14551 schema: entityExpr.schema,
14552 entity: entityExpr.entity,
14553 name: expr.property,
14554 };
14555 if (entityExpr.variable)
14556 propertyVariationSource.entityVar = entityExpr.variable;
14557 return {
14558 variation: {
14559 column: propertyVariationSource,
14560 variationName: expr.name,
14561 }
14562 };
14563 }
14564 };
14565 SourceExprPatternBuilder.instance = new SourceExprPatternBuilder();
14566 return SourceExprPatternBuilder;
14567 }(data.DefaultSQExprVisitor));
14568 var HierarchyExprPatternBuiler = (function (_super) {
14569 __extends(HierarchyExprPatternBuiler, _super);
14570 function HierarchyExprPatternBuiler() {
14571 _super.apply(this, arguments);
14572 }
14573 HierarchyExprPatternBuiler.prototype.visitHierarchy = function (expr) {
14574 var exprPattern = expr.arg.accept(SourceExprPatternBuilder.instance);
14575 var hierarchyRef;
14576 var variationRef;
14577 if (exprPattern.variation) {
14578 hierarchyRef = {
14579 name: expr.hierarchy,
14580 schema: exprPattern.variation.column.schema,
14581 entity: exprPattern.variation.column.entity,
14582 };
14583 variationRef = exprPattern.variation;
14584 }
14585 else
14586 hierarchyRef = {
14587 name: expr.hierarchy,
14588 schema: exprPattern.entity.schema,
14589 entity: exprPattern.entity.entity,
14590 };
14591 return {
14592 hierarchy: hierarchyRef,
14593 variation: variationRef
14594 };
14595 };
14596 HierarchyExprPatternBuiler.instance = new HierarchyExprPatternBuiler();
14597 return HierarchyExprPatternBuiler;
14598 }(data.DefaultSQExprVisitor));
14599 var FieldExprPattern;
14600 (function (FieldExprPattern) {
14601 function visit(expr, visitor) {
14602 debug.assertValue(expr, 'expr');
14603 debug.assertValue(visitor, 'visitor');
14604 var fieldExprPattern = expr instanceof data.SQExpr ? SQExprConverter.asFieldPattern(expr) : expr;
14605 debug.assertValue(fieldExprPattern, 'expected sqExpr to conform to a fieldExprPattern');
14606 if (fieldExprPattern.column)
14607 return visitColumn(fieldExprPattern.column, visitor);
14608 if (fieldExprPattern.columnAggr)
14609 return visitColumnAggr(fieldExprPattern.columnAggr, visitor);
14610 if (fieldExprPattern.columnHierarchyLevelVariation)
14611 return visitColumnHierarchyLevelVariation(fieldExprPattern.columnHierarchyLevelVariation, visitor);
14612 if (fieldExprPattern.entity)
14613 return visitEntity(fieldExprPattern.entity, visitor);
14614 if (fieldExprPattern.entityAggr)
14615 return visitEntityAggr(fieldExprPattern.entityAggr, visitor);
14616 if (fieldExprPattern.hierarchy)
14617 return visitHierarchy(fieldExprPattern.hierarchy, visitor);
14618 if (fieldExprPattern.hierarchyLevel)
14619 return visitHierarchyLevel(fieldExprPattern.hierarchyLevel, visitor);
14620 if (fieldExprPattern.hierarchyLevelAggr)
14621 return visitHierarchyLevelAggr(fieldExprPattern.hierarchyLevelAggr, visitor);
14622 if (fieldExprPattern.measure)
14623 return visitMeasure(fieldExprPattern.measure, visitor);
14624 if (fieldExprPattern.percentile)
14625 return visitPercentile(fieldExprPattern.percentile, visitor);
14626 if (fieldExprPattern.percentOfGrandTotal)
14627 return visitPercentOfGrandTotal(fieldExprPattern.percentOfGrandTotal, visitor);
14628 if (fieldExprPattern.selectRef)
14629 return visitSelectRef(fieldExprPattern.selectRef, visitor);
14630 debug.assertFail('failed to visit a fieldExprPattern.');
14631 return;
14632 }
14633 FieldExprPattern.visit = visit;
14634 function visitColumn(column, visitor) {
14635 debug.assertValue(column, 'column');
14636 debug.assertValue(visitor, 'visitor');
14637 return visitor.visitColumn(column);
14638 }
14639 function visitColumnAggr(columnAggr, visitor) {
14640 debug.assertValue(columnAggr, 'columnAggr');
14641 debug.assertValue(visitor, 'visitor');
14642 return visitor.visitColumnAggr(columnAggr);
14643 }
14644 function visitColumnHierarchyLevelVariation(columnHierarchyLevelVariation, visitor) {
14645 debug.assertValue(columnHierarchyLevelVariation, 'columnHierarchyLevelVariation');
14646 debug.assertValue(visitor, 'visitor');
14647 return visitor.visitColumnHierarchyLevelVariation(columnHierarchyLevelVariation);
14648 }
14649 function visitEntity(entity, visitor) {
14650 debug.assertValue(entity, 'entity');
14651 debug.assertValue(visitor, 'visitor');
14652 return visitor.visitEntity(entity);
14653 }
14654 function visitEntityAggr(entityAggr, visitor) {
14655 debug.assertValue(entityAggr, 'entityAggr');
14656 debug.assertValue(visitor, 'visitor');
14657 return visitor.visitEntityAggr(entityAggr);
14658 }
14659 function visitHierarchy(hierarchy, visitor) {
14660 debug.assertValue(hierarchy, 'hierarchy');
14661 debug.assertValue(visitor, 'visitor');
14662 return visitor.visitHierarchy(hierarchy);
14663 }
14664 function visitHierarchyLevel(hierarchyLevel, visitor) {
14665 debug.assertValue(hierarchyLevel, 'hierarchyLevel');
14666 debug.assertValue(visitor, 'visitor');
14667 return visitor.visitHierarchyLevel(hierarchyLevel);
14668 }
14669 function visitHierarchyLevelAggr(hierarchyLevelAggr, visitor) {
14670 debug.assertValue(hierarchyLevelAggr, 'hierarchyLevelAggr');
14671 debug.assertValue(visitor, 'visitor');
14672 return visitor.visitHierarchyLevelAggr(hierarchyLevelAggr);
14673 }
14674 function visitMeasure(measure, visitor) {
14675 debug.assertValue(measure, 'measure');
14676 debug.assertValue(visitor, 'visitor');
14677 return visitor.visitMeasure(measure);
14678 }
14679 function visitSelectRef(selectRef, visitor) {
14680 debug.assertValue(selectRef, 'selectRef');
14681 debug.assertValue(visitor, 'visitor');
14682 return visitor.visitSelectRef(selectRef);
14683 }
14684 function visitPercentile(percentile, visitor) {
14685 debug.assertValue(percentile, 'percentile');
14686 debug.assertValue(visitor, 'visitor');
14687 return visitor.visitPercentile(percentile);
14688 }
14689 function visitPercentOfGrandTotal(percentOfGrandTotal, visitor) {
14690 debug.assertValue(percentOfGrandTotal, 'percentOfGrandTotal');
14691 debug.assertValue(visitor, 'visitor');
14692 return visitor.visitPercentOfGrandTotal(percentOfGrandTotal);
14693 }
14694 function toColumnRefSQExpr(columnPattern) {
14695 return SQExprBuilder.columnRef(SQExprBuilder.entity(columnPattern.schema, columnPattern.entity, columnPattern.entityVar), columnPattern.name);
14696 }
14697 FieldExprPattern.toColumnRefSQExpr = toColumnRefSQExpr;
14698 function getAggregate(fieldExpr) {
14699 debug.assertValue(fieldExpr, 'fieldExpr');
14700 return visit(fieldExpr, FieldExprPatternAggregateVisitor.instance);
14701 }
14702 FieldExprPattern.getAggregate = getAggregate;
14703 function isAggregation(fieldExpr) {
14704 debug.assertValue(fieldExpr, 'fieldExpr');
14705 return visit(fieldExpr, FieldExprPatternIsAggregationVisitor.instance);
14706 }
14707 FieldExprPattern.isAggregation = isAggregation;
14708 function hasFieldExprName(fieldExpr) {
14709 return (fieldExpr.column ||
14710 fieldExpr.columnAggr ||
14711 fieldExpr.measure) !== undefined;
14712 }
14713 FieldExprPattern.hasFieldExprName = hasFieldExprName;
14714 function getPropertyName(fieldExpr) {
14715 return FieldExprPattern.visit(fieldExpr, FieldExprPropertyNameVisitor.instance);
14716 }
14717 FieldExprPattern.getPropertyName = getPropertyName;
14718 function getHierarchyName(fieldExpr) {
14719 var hierarchy = fieldExpr.hierarchy;
14720 if (hierarchy)
14721 return hierarchy.name;
14722 }
14723 FieldExprPattern.getHierarchyName = getHierarchyName;
14724 function getColumnRef(fieldExpr) {
14725 if (fieldExpr.columnHierarchyLevelVariation)
14726 return fieldExpr.columnHierarchyLevelVariation.source;
14727 return fieldExpr.column || fieldExpr.measure || fieldExpr.columnAggr;
14728 }
14729 FieldExprPattern.getColumnRef = getColumnRef;
14730 function getFieldExprName(fieldExpr) {
14731 var name = getPropertyName(fieldExpr);
14732 if (name)
14733 return name;
14734 // In case it is an entity
14735 return toFieldExprEntityPattern(fieldExpr).entity;
14736 }
14737 FieldExprPattern.getFieldExprName = getFieldExprName;
14738 function getSchema(fieldExpr) {
14739 debug.assertValue(fieldExpr, 'fieldExpr');
14740 var item = FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
14741 debug.assertAnyValue(item, 'expected fieldExpr to be an entity item');
14742 return item.schema;
14743 }
14744 FieldExprPattern.getSchema = getSchema;
14745 function toFieldExprEntityPattern(fieldExpr) {
14746 return FieldExprPattern.visit(fieldExpr, FieldExprToEntityExprPatternBuilder.instance);
14747 }
14748 FieldExprPattern.toFieldExprEntityPattern = toFieldExprEntityPattern;
14749 function toFieldExprEntityItemPattern(fieldExpr) {
14750 return FieldExprPattern.visit(fieldExpr, FieldExprToEntityExprPatternBuilder.instance);
14751 }
14752 FieldExprPattern.toFieldExprEntityItemPattern = toFieldExprEntityItemPattern;
14753 var FieldExprPatternAggregateVisitor = (function () {
14754 function FieldExprPatternAggregateVisitor() {
14755 }
14756 FieldExprPatternAggregateVisitor.prototype.visitColumn = function (column) {
14757 return;
14758 };
14759 FieldExprPatternAggregateVisitor.prototype.visitColumnAggr = function (columnAggr) {
14760 return columnAggr.aggregate;
14761 };
14762 FieldExprPatternAggregateVisitor.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
14763 return;
14764 };
14765 FieldExprPatternAggregateVisitor.prototype.visitEntity = function (entity) {
14766 return;
14767 };
14768 FieldExprPatternAggregateVisitor.prototype.visitEntityAggr = function (entityAggr) {
14769 return entityAggr.aggregate;
14770 };
14771 FieldExprPatternAggregateVisitor.prototype.visitHierarchy = function (hierarchy) {
14772 return;
14773 };
14774 FieldExprPatternAggregateVisitor.prototype.visitHierarchyLevel = function (hierarchyLevel) {
14775 return;
14776 };
14777 FieldExprPatternAggregateVisitor.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
14778 return hierarchyLevelAggr.aggregate;
14779 };
14780 FieldExprPatternAggregateVisitor.prototype.visitMeasure = function (measure) {
14781 return;
14782 };
14783 FieldExprPatternAggregateVisitor.prototype.visitSelectRef = function (selectRef) {
14784 return;
14785 };
14786 FieldExprPatternAggregateVisitor.prototype.visitPercentile = function (percentile) {
14787 // NOTE: Percentile behaves like an aggregate (i.e., can be performed over numeric columns like a SUM), but
14788 // this function can't really convey that because percentile (intentionally) isn't in QueryAggregateFunction enum.
14789 // This should be revisited when we have UI support for the Percentile aggregate.
14790 return;
14791 };
14792 FieldExprPatternAggregateVisitor.prototype.visitPercentOfGrandTotal = function (percentOfGrandTotal) {
14793 return data.SQExprInfo.getAggregate(SQExprBuilder.fieldExpr(percentOfGrandTotal.baseExpr));
14794 };
14795 FieldExprPatternAggregateVisitor.instance = new FieldExprPatternAggregateVisitor();
14796 return FieldExprPatternAggregateVisitor;
14797 }());
14798 var FieldExprPatternIsAggregationVisitor = (function () {
14799 function FieldExprPatternIsAggregationVisitor() {
14800 }
14801 FieldExprPatternIsAggregationVisitor.prototype.visitColumn = function (column) {
14802 return false;
14803 };
14804 FieldExprPatternIsAggregationVisitor.prototype.visitColumnAggr = function (columnAggr) {
14805 return true;
14806 };
14807 FieldExprPatternIsAggregationVisitor.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
14808 return false;
14809 };
14810 FieldExprPatternIsAggregationVisitor.prototype.visitEntity = function (entity) {
14811 return false;
14812 };
14813 FieldExprPatternIsAggregationVisitor.prototype.visitEntityAggr = function (entityAggr) {
14814 return true;
14815 };
14816 FieldExprPatternIsAggregationVisitor.prototype.visitHierarchy = function (hierarchy) {
14817 return false;
14818 };
14819 FieldExprPatternIsAggregationVisitor.prototype.visitHierarchyLevel = function (hierarchyLevel) {
14820 return false;
14821 };
14822 FieldExprPatternIsAggregationVisitor.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
14823 return true;
14824 };
14825 FieldExprPatternIsAggregationVisitor.prototype.visitMeasure = function (measure) {
14826 return true;
14827 };
14828 FieldExprPatternIsAggregationVisitor.prototype.visitSelectRef = function (selectRef) {
14829 return false;
14830 };
14831 FieldExprPatternIsAggregationVisitor.prototype.visitPercentile = function (percentile) {
14832 return true;
14833 };
14834 FieldExprPatternIsAggregationVisitor.prototype.visitPercentOfGrandTotal = function (percentOfGrandTotal) {
14835 return true;
14836 };
14837 FieldExprPatternIsAggregationVisitor.instance = new FieldExprPatternIsAggregationVisitor();
14838 return FieldExprPatternIsAggregationVisitor;
14839 }());
14840 var FieldExprToEntityExprPatternBuilder = (function () {
14841 function FieldExprToEntityExprPatternBuilder() {
14842 }
14843 FieldExprToEntityExprPatternBuilder.prototype.visitColumn = function (column) {
14844 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(column);
14845 };
14846 FieldExprToEntityExprPatternBuilder.prototype.visitColumnAggr = function (columnAggr) {
14847 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(columnAggr);
14848 };
14849 FieldExprToEntityExprPatternBuilder.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
14850 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(columnHierarchyLevelVariation.source);
14851 };
14852 FieldExprToEntityExprPatternBuilder.prototype.visitEntity = function (entity) {
14853 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(entity);
14854 };
14855 FieldExprToEntityExprPatternBuilder.prototype.visitEntityAggr = function (entityAggr) {
14856 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(entityAggr);
14857 };
14858 FieldExprToEntityExprPatternBuilder.prototype.visitHierarchy = function (hierarchy) {
14859 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(hierarchy);
14860 };
14861 FieldExprToEntityExprPatternBuilder.prototype.visitHierarchyLevel = function (hierarchyLevel) {
14862 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(hierarchyLevel);
14863 };
14864 FieldExprToEntityExprPatternBuilder.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
14865 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(hierarchyLevelAggr);
14866 };
14867 FieldExprToEntityExprPatternBuilder.prototype.visitMeasure = function (measure) {
14868 return FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern(measure);
14869 };
14870 FieldExprToEntityExprPatternBuilder.prototype.visitSelectRef = function (selectRef) {
14871 return;
14872 };
14873 FieldExprToEntityExprPatternBuilder.prototype.visitPercentile = function (percentile) {
14874 return FieldExprPattern.visit(percentile.arg, this);
14875 };
14876 FieldExprToEntityExprPatternBuilder.prototype.visitPercentOfGrandTotal = function (percentOfGrandTotal) {
14877 return FieldExprPattern.visit(percentOfGrandTotal.baseExpr, this);
14878 };
14879 FieldExprToEntityExprPatternBuilder.toEntityItemExprPattern = function (exprPattern) {
14880 debug.assertValue(exprPattern, 'exprPattern');
14881 var pattern = { schema: exprPattern.schema, entity: exprPattern.entity };
14882 if (exprPattern.entityVar) {
14883 pattern.entityVar = exprPattern.entityVar;
14884 }
14885 return pattern;
14886 };
14887 FieldExprToEntityExprPatternBuilder.instance = new FieldExprToEntityExprPatternBuilder();
14888 return FieldExprToEntityExprPatternBuilder;
14889 }());
14890 var FieldExprPropertyNameVisitor = (function () {
14891 function FieldExprPropertyNameVisitor() {
14892 }
14893 FieldExprPropertyNameVisitor.prototype.visitColumn = function (column) {
14894 return column.name;
14895 };
14896 FieldExprPropertyNameVisitor.prototype.visitColumnAggr = function (columnAggr) {
14897 return columnAggr.name;
14898 };
14899 FieldExprPropertyNameVisitor.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
14900 return;
14901 };
14902 FieldExprPropertyNameVisitor.prototype.visitEntity = function (entity) {
14903 return;
14904 };
14905 FieldExprPropertyNameVisitor.prototype.visitEntityAggr = function (entityAggr) {
14906 return;
14907 };
14908 FieldExprPropertyNameVisitor.prototype.visitHierarchy = function (hierarchy) {
14909 return;
14910 };
14911 FieldExprPropertyNameVisitor.prototype.visitHierarchyLevel = function (hierarchyLevel) {
14912 return;
14913 };
14914 FieldExprPropertyNameVisitor.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
14915 return;
14916 };
14917 FieldExprPropertyNameVisitor.prototype.visitMeasure = function (measure) {
14918 return measure.name;
14919 };
14920 FieldExprPropertyNameVisitor.prototype.visitSelectRef = function (selectRef) {
14921 return;
14922 };
14923 FieldExprPropertyNameVisitor.prototype.visitPercentile = function (percentile) {
14924 return FieldExprPattern.visit(percentile.arg, this);
14925 };
14926 FieldExprPropertyNameVisitor.prototype.visitPercentOfGrandTotal = function (percentOfGrandTotal) {
14927 return FieldExprPattern.visit(percentOfGrandTotal.baseExpr, this);
14928 };
14929 FieldExprPropertyNameVisitor.instance = new FieldExprPropertyNameVisitor();
14930 return FieldExprPropertyNameVisitor;
14931 }());
14932 })(FieldExprPattern = data.FieldExprPattern || (data.FieldExprPattern = {}));
14933 })(data = powerbi.data || (powerbi.data = {}));
14934})(powerbi || (powerbi = {}));
14935/*
14936 * Power BI Visualizations
14937 *
14938 * Copyright (c) Microsoft Corporation
14939 * All rights reserved.
14940 * MIT License
14941 *
14942 * Permission is hereby granted, free of charge, to any person obtaining a copy
14943 * of this software and associated documentation files (the ""Software""), to deal
14944 * in the Software without restriction, including without limitation the rights
14945 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14946 * copies of the Software, and to permit persons to whom the Software is
14947 * furnished to do so, subject to the following conditions:
14948 *
14949 * The above copyright notice and this permission notice shall be included in
14950 * all copies or substantial portions of the Software.
14951 *
14952 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14953 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14954 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14955 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14956 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14957 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14958 * THE SOFTWARE.
14959 */
14960var powerbi;
14961(function (powerbi) {
14962 var DataViewAnalysis;
14963 (function (DataViewAnalysis) {
14964 var ArrayExtensions = jsCommon.ArrayExtensions;
14965 var DataViewObjectDefinitions = powerbi.data.DataViewObjectDefinitions;
14966 (function (DataViewMappingMatchErrorCode) {
14967 DataViewMappingMatchErrorCode[DataViewMappingMatchErrorCode["conditionRangeTooLarge"] = 0] = "conditionRangeTooLarge";
14968 DataViewMappingMatchErrorCode[DataViewMappingMatchErrorCode["conditionRangeTooSmall"] = 1] = "conditionRangeTooSmall";
14969 DataViewMappingMatchErrorCode[DataViewMappingMatchErrorCode["conditionKindExpectedMeasure"] = 2] = "conditionKindExpectedMeasure";
14970 DataViewMappingMatchErrorCode[DataViewMappingMatchErrorCode["conditionKindExpectedGrouping"] = 3] = "conditionKindExpectedGrouping";
14971 DataViewMappingMatchErrorCode[DataViewMappingMatchErrorCode["conditionKindExpectedGroupingOrMeasure"] = 4] = "conditionKindExpectedGroupingOrMeasure";
14972 })(DataViewAnalysis.DataViewMappingMatchErrorCode || (DataViewAnalysis.DataViewMappingMatchErrorCode = {}));
14973 var DataViewMappingMatchErrorCode = DataViewAnalysis.DataViewMappingMatchErrorCode;
14974 /** Reshapes the data view to match the provided schema if possible. If not, returns null */
14975 function validateAndReshape(dataView, dataViewMappings) {
14976 if (!dataViewMappings || dataViewMappings.length === 0)
14977 return { dataView: dataView, isValid: true };
14978 if (dataView) {
14979 for (var _i = 0, dataViewMappings_3 = dataViewMappings; _i < dataViewMappings_3.length; _i++) {
14980 var dataViewMapping = dataViewMappings_3[_i];
14981 // Keep the original when possible.
14982 if (supports(dataView, dataViewMapping))
14983 return { dataView: dataView, isValid: true };
14984 if (dataViewMapping.categorical && dataView.categorical)
14985 return reshapeCategorical(dataView, dataViewMapping);
14986 if (dataViewMapping.tree && dataView.tree)
14987 return reshapeTree(dataView, dataViewMapping.tree);
14988 if (dataViewMapping.single && dataView.single)
14989 return reshapeSingle(dataView, dataViewMapping.single);
14990 if (dataViewMapping.table && dataView.table)
14991 return reshapeTable(dataView, dataViewMapping.table);
14992 }
14993 }
14994 else if (powerbi.ScriptResultUtil.findScriptResult(dataViewMappings)) {
14995 // Currently, PBI Service treats R Script Visuals as static images.
14996 // This causes validation to fail, since in PBI service no DataView is generated, but there are DataViewMappings,
14997 // to support the PBI Desktop scenario.
14998 // This code will be removed once PBI Service fully supports R Script Visuals.
14999 // VSTS: 6217994 - [R Viz] Remove temporary DataViewAnalysis validation workaround of static R Script Visual mappings
15000 return { dataView: dataView, isValid: true };
15001 }
15002 return { isValid: false };
15003 }
15004 DataViewAnalysis.validateAndReshape = validateAndReshape;
15005 function reshapeCategorical(dataView, dataViewMapping) {
15006 debug.assertValue(dataViewMapping, 'dataViewMapping');
15007 //The functionality that used to compare categorical.values.length to schema.values doesn't apply any more, we don't want to use the same logic for re-shaping.
15008 var categoryRoleMapping = dataViewMapping.categorical;
15009 var categorical = dataView.categorical;
15010 if (!categorical)
15011 return { isValid: false };
15012 var rowCount;
15013 if (categoryRoleMapping.rowCount) {
15014 rowCount = categoryRoleMapping.rowCount.supported;
15015 if (rowCount && rowCount.max) {
15016 var updated = void 0;
15017 var categories = categorical.categories;
15018 var maxRowCount = rowCount.max;
15019 var originalLength = undefined;
15020 if (categories) {
15021 for (var i = 0, len = categories.length; i < len; i++) {
15022 var category = categories[i];
15023 originalLength = category.values.length;
15024 if (maxRowCount !== undefined && originalLength > maxRowCount) {
15025 // Row count too large: Trim it to fit.
15026 var updatedCategories = ArrayExtensions.range(category.values, 0, maxRowCount - 1);
15027 updated = updated || { categories: [] };
15028 updated.categories.push({
15029 source: category.source,
15030 values: updatedCategories
15031 });
15032 }
15033 }
15034 }
15035 if (categorical.values && categorical.values.length > 0 && maxRowCount) {
15036 if (!originalLength)
15037 originalLength = categorical.values[0].values.length;
15038 if (maxRowCount !== undefined && originalLength > maxRowCount) {
15039 updated = updated || {};
15040 updated.values = powerbi.data.DataViewTransform.createValueColumns();
15041 for (var i = 0, len = categorical.values.length; i < len; i++) {
15042 var column = categorical.values[i], updatedColumn = {
15043 source: column.source,
15044 values: ArrayExtensions.range(column.values, 0, maxRowCount - 1)
15045 };
15046 if (column.min !== undefined)
15047 updatedColumn.min = column.min;
15048 if (column.max !== undefined)
15049 updatedColumn.max = column.max;
15050 if (column.subtotal !== undefined)
15051 updatedColumn.subtotal = column.subtotal;
15052 updated.values.push(updatedColumn);
15053 }
15054 }
15055 }
15056 if (updated) {
15057 dataView = {
15058 metadata: dataView.metadata,
15059 categorical: updated,
15060 };
15061 }
15062 }
15063 }
15064 if (supportsCategorical(dataView, dataViewMapping))
15065 return { dataView: dataView, isValid: true };
15066 return null;
15067 }
15068 function reshapeSingle(dataView, singleRoleMapping) {
15069 debug.assertValue(dataView, 'dataView');
15070 debug.assertValue(singleRoleMapping, 'singleRoleMapping');
15071 if (dataView.single)
15072 return { dataView: dataView, isValid: true };
15073 return { isValid: false };
15074 }
15075 function reshapeTree(dataView, treeRoleMapping) {
15076 debug.assertValue(dataView, 'dataView');
15077 debug.assertValue(treeRoleMapping, 'treeRoleMapping');
15078 // TODO: Need to implement the reshaping of Tree
15079 var metadata = dataView.metadata;
15080 if (validateRange(countGroups(metadata.columns), treeRoleMapping.depth) == null /*&& conforms(countMeasures(metadata.columns), treeRoleMapping.aggregates)*/)
15081 return { dataView: dataView, isValid: true };
15082 return { isValid: false };
15083 }
15084 function reshapeTable(dataView, tableRoleMapping) {
15085 debug.assertValue(dataView, 'dataView');
15086 debug.assertValue(tableRoleMapping, 'tableRoleMapping');
15087 if (dataView.table)
15088 return { dataView: dataView, isValid: true };
15089 return { isValid: false };
15090 }
15091 function countGroups(columns) {
15092 var count = 0;
15093 for (var i = 0, len = columns.length; i < len; i++) {
15094 if (!columns[i].isMeasure)
15095 ++count;
15096 }
15097 return count;
15098 }
15099 DataViewAnalysis.countGroups = countGroups;
15100 function countMeasures(columns) {
15101 var count = 0;
15102 for (var i = 0, len = columns.length; i < len; i++) {
15103 if (columns[i].isMeasure)
15104 ++count;
15105 }
15106 return count;
15107 }
15108 DataViewAnalysis.countMeasures = countMeasures;
15109 /** Indicates whether the dataView conforms to the specified schema. */
15110 function supports(dataView, roleMapping, usePreferredDataViewSchema) {
15111 if (!roleMapping || !dataView)
15112 return false;
15113 if (roleMapping.scriptResult && !supportsScriptResult(dataView.scriptResult, roleMapping.scriptResult))
15114 return false;
15115 if (roleMapping.categorical && !supportsCategorical(dataView, roleMapping.categorical, usePreferredDataViewSchema))
15116 return false;
15117 if (roleMapping.tree && !supportsTree(dataView, roleMapping.tree))
15118 return false;
15119 if (roleMapping.single && !supportsSingle(dataView.single, roleMapping.single))
15120 return false;
15121 if (roleMapping.table && !supportsTable(dataView.table, roleMapping.table, usePreferredDataViewSchema))
15122 return false;
15123 return true;
15124 }
15125 DataViewAnalysis.supports = supports;
15126 function supportsCategorical(dataView, categoryRoleMapping, usePreferredDataViewSchema) {
15127 debug.assertValue(categoryRoleMapping, 'categoryRoleMapping');
15128 var dataViewCategorical = dataView.categorical;
15129 if (!dataViewCategorical)
15130 return false;
15131 // TODO: Disabling this implementation isn't right.
15132 //if (!conforms(countMeasures(dataView.metadata.columns), categoryRoleMapping.values.roles.length))
15133 // return false;
15134 if (categoryRoleMapping.rowCount) {
15135 var rowCount = categoryRoleMapping.rowCount.supported;
15136 if (usePreferredDataViewSchema && categoryRoleMapping.rowCount.preferred)
15137 rowCount = categoryRoleMapping.rowCount.preferred;
15138 if (rowCount) {
15139 var len = 0;
15140 if (dataViewCategorical.values && dataViewCategorical.values.length)
15141 len = dataViewCategorical.values[0].values.length;
15142 else if (dataViewCategorical.categories && dataViewCategorical.categories.length)
15143 len = dataViewCategorical.categories[0].values.length;
15144 if (validateRange(len, rowCount) != null)
15145 return false;
15146 }
15147 }
15148 return true;
15149 }
15150 function supportsSingle(dataViewSingle, singleRoleMapping) {
15151 debug.assertValue(singleRoleMapping, 'singleRoleMapping');
15152 if (!dataViewSingle)
15153 return false;
15154 return true;
15155 }
15156 function supportsTree(dataView, treeRoleMapping) {
15157 debug.assertValue(treeRoleMapping, 'treeRoleMapping');
15158 var metadata = dataView.metadata;
15159 return validateRange(countGroups(metadata.columns), treeRoleMapping.depth) == null;
15160 }
15161 function supportsTable(dataViewTable, tableRoleMapping, usePreferredDataViewSchema) {
15162 debug.assertValue(tableRoleMapping, 'tableRoleMapping');
15163 if (!dataViewTable)
15164 return false;
15165 if (tableRoleMapping.rowCount) {
15166 var rowCount = tableRoleMapping.rowCount.supported;
15167 if (usePreferredDataViewSchema && tableRoleMapping.rowCount.preferred)
15168 rowCount = tableRoleMapping.rowCount.preferred;
15169 if (rowCount) {
15170 var len = 0;
15171 if (dataViewTable.rows && dataViewTable.rows.length)
15172 len = dataViewTable.rows.length;
15173 if (validateRange(len, rowCount) != null)
15174 return false;
15175 }
15176 }
15177 return true;
15178 }
15179 function supportsScriptResult(dataView, scriptResultRoleMapping) {
15180 debug.assertValue(scriptResultRoleMapping, 'scriptResultRoleMapping');
15181 if (!dataView)
15182 return false;
15183 if (!dataView.imageBase64)
15184 return false;
15185 return true;
15186 }
15187 /**
15188 * Determines whether the value conforms to the range in the role condition, returning undefined
15189 * if so or an appropriate error code if not.
15190 */
15191 function validateRange(value, roleCondition, ignoreMin) {
15192 debug.assertValue(value, 'value');
15193 if (!roleCondition)
15194 return;
15195 if (!ignoreMin && roleCondition.min !== undefined && roleCondition.min > value)
15196 return DataViewMappingMatchErrorCode.conditionRangeTooSmall;
15197 if (roleCondition.max !== undefined && roleCondition.max < value)
15198 return DataViewMappingMatchErrorCode.conditionRangeTooLarge;
15199 }
15200 DataViewAnalysis.validateRange = validateRange;
15201 /**
15202 * Determines whether the value conforms to the kind in the role condition, returning undefined
15203 * if so or an appropriate error code if not.
15204 */
15205 function validateKind(roleCondition, roleName, projections, roleKindByQueryRef) {
15206 if (!roleCondition || roleCondition.kind === undefined) {
15207 return;
15208 }
15209 var expectedKind = roleCondition.kind;
15210 var roleCollection = projections[roleName];
15211 if (roleCollection) {
15212 var roleProjections = roleCollection.all();
15213 for (var _i = 0, roleProjections_1 = roleProjections; _i < roleProjections_1.length; _i++) {
15214 var roleProjection = roleProjections_1[_i];
15215 if (roleKindByQueryRef[roleProjection.queryRef] !== expectedKind) {
15216 switch (expectedKind) {
15217 case powerbi.VisualDataRoleKind.Measure:
15218 return DataViewMappingMatchErrorCode.conditionKindExpectedMeasure;
15219 case powerbi.VisualDataRoleKind.Grouping:
15220 return DataViewMappingMatchErrorCode.conditionKindExpectedGrouping;
15221 case powerbi.VisualDataRoleKind.GroupingOrMeasure:
15222 return DataViewMappingMatchErrorCode.conditionKindExpectedGroupingOrMeasure;
15223 }
15224 }
15225 }
15226 }
15227 }
15228 /** Determines the appropriate DataViewMappings for the projections. */
15229 function chooseDataViewMappings(projections, mappings, roleKindByQueryRef, objectDescriptors, objectDefinitions) {
15230 debug.assertValue(projections, 'projections');
15231 debug.assertAnyValue(mappings, 'mappings');
15232 var supportedMappings = [];
15233 var errors = [];
15234 if (!_.isEmpty(mappings)) {
15235 for (var mappingIndex = 0, mappingCount = mappings.length; mappingIndex < mappingCount; mappingIndex++) {
15236 var mapping = mappings[mappingIndex], mappingConditions = mapping.conditions, requiredProperties = mapping.requiredProperties;
15237 var allPropertiesValid = areAllPropertiesValid(requiredProperties, objectDescriptors, objectDefinitions);
15238 var conditionsMet = [];
15239 if (!_.isEmpty(mappingConditions)) {
15240 for (var conditionIndex = 0, conditionCount = mappingConditions.length; conditionIndex < conditionCount; conditionIndex++) {
15241 var condition = mappingConditions[conditionIndex];
15242 var currentConditionErrors = checkForConditionErrors(projections, condition, roleKindByQueryRef);
15243 if (!_.isEmpty(currentConditionErrors)) {
15244 for (var _i = 0, currentConditionErrors_1 = currentConditionErrors; _i < currentConditionErrors_1.length; _i++) {
15245 var error = currentConditionErrors_1[_i];
15246 error.mappingIndex = mappingIndex;
15247 error.conditionIndex = conditionIndex;
15248 errors.push(error);
15249 }
15250 }
15251 else
15252 conditionsMet.push(condition);
15253 }
15254 }
15255 else {
15256 conditionsMet.push({});
15257 }
15258 if (!_.isEmpty(conditionsMet) && allPropertiesValid) {
15259 var supportedMapping = _.cloneDeep(mapping);
15260 var updatedConditions = _.filter(conditionsMet, function (condition) { return Object.keys(condition).length > 0; });
15261 if (!_.isEmpty(updatedConditions))
15262 supportedMapping.conditions = updatedConditions;
15263 supportedMappings.push(supportedMapping);
15264 }
15265 }
15266 }
15267 return {
15268 supportedMappings: ArrayExtensions.emptyToNull(supportedMappings),
15269 mappingErrors: ArrayExtensions.emptyToNull(errors),
15270 };
15271 }
15272 DataViewAnalysis.chooseDataViewMappings = chooseDataViewMappings;
15273 function checkForConditionErrors(projections, condition, roleKindByQueryRef) {
15274 debug.assertValue(projections, 'projections');
15275 debug.assertValue(condition, 'condition');
15276 var conditionRoles = Object.keys(condition);
15277 var errors = [];
15278 for (var i = 0, len = conditionRoles.length; i < len; i++) {
15279 var roleName = conditionRoles[i], isDrillable = projections[roleName] && !_.isEmpty(projections[roleName].activeProjectionRefs), roleCondition = condition[roleName];
15280 var roleCount = getPropertyCount(roleName, projections, isDrillable);
15281 var rangeError = validateRange(roleCount, roleCondition);
15282 if (rangeError != null) {
15283 errors.push({
15284 code: rangeError,
15285 roleName: roleName,
15286 });
15287 }
15288 var kindError = validateKind(roleCondition, roleName, projections, roleKindByQueryRef);
15289 if (kindError != null) {
15290 errors.push({
15291 code: kindError,
15292 roleName: roleName,
15293 });
15294 }
15295 }
15296 return errors;
15297 }
15298 function areAllPropertiesValid(requiredProperties, objectDescriptors, objectDefinitions) {
15299 if (_.isEmpty(requiredProperties))
15300 return true;
15301 if (!objectDescriptors || !objectDefinitions)
15302 return false;
15303 var staticEvalContext = powerbi.data.createStaticEvalContext();
15304 return _.every(requiredProperties, function (requiredProperty) {
15305 var objectDescriptorValue = null;
15306 var objectDescriptorProperty = objectDescriptors[requiredProperty.objectName];
15307 if (objectDescriptorProperty)
15308 objectDescriptorValue = objectDescriptorProperty.properties[requiredProperty.propertyName];
15309 var objectDefinitionValue = DataViewObjectDefinitions.getValue(objectDefinitions, requiredProperty, null);
15310 if (!objectDescriptorValue || !objectDefinitionValue)
15311 return false;
15312 return powerbi.data.DataViewObjectEvaluator.evaluateProperty(staticEvalContext, objectDescriptorValue, objectDefinitionValue);
15313 });
15314 }
15315 function getPropertyCount(roleName, projections, useActiveIfAvailable) {
15316 debug.assertValue(roleName, 'roleName');
15317 debug.assertValue(projections, 'projections');
15318 var projectionsForRole = projections[roleName];
15319 if (projectionsForRole) {
15320 if (useActiveIfAvailable)
15321 return 1;
15322 return projectionsForRole.all().length;
15323 }
15324 return 0;
15325 }
15326 DataViewAnalysis.getPropertyCount = getPropertyCount;
15327 function hasSameCategoryIdentity(dataView1, dataView2) {
15328 if (dataView1
15329 && dataView2
15330 && dataView1.categorical
15331 && dataView2.categorical) {
15332 var dv1Categories = dataView1.categorical.categories;
15333 var dv2Categories = dataView2.categorical.categories;
15334 if (dv1Categories
15335 && dv2Categories
15336 && dv1Categories.length === dv2Categories.length) {
15337 for (var i = 0, len = dv1Categories.length; i < len; i++) {
15338 var dv1Identity = dv1Categories[i].identity;
15339 var dv2Identity = dv2Categories[i].identity;
15340 var dv1Length = getLengthOptional(dv1Identity);
15341 if (dv1Length !== getLengthOptional(dv2Identity))
15342 return false;
15343 for (var j = 0; j < dv1Length; j++) {
15344 if (!powerbi.DataViewScopeIdentity.equals(dv1Identity[j], dv2Identity[j]))
15345 return false;
15346 }
15347 }
15348 return true;
15349 }
15350 }
15351 return false;
15352 }
15353 DataViewAnalysis.hasSameCategoryIdentity = hasSameCategoryIdentity;
15354 function getLengthOptional(identity) {
15355 if (identity)
15356 return identity.length;
15357 return 0;
15358 }
15359 function areMetadataColumnsEquivalent(column1, column2) {
15360 if (!column1 && !column2)
15361 return true;
15362 if (!column1 || !column2)
15363 return false;
15364 if (column1.displayName !== column2.displayName)
15365 return false;
15366 if (column1.queryName !== column2.queryName)
15367 return false;
15368 if (column1.isMeasure !== column2.isMeasure)
15369 return false;
15370 if (column1.type !== column2.type)
15371 return false;
15372 if (column1.sort !== column2.sort)
15373 return false;
15374 return true;
15375 }
15376 DataViewAnalysis.areMetadataColumnsEquivalent = areMetadataColumnsEquivalent;
15377 /* Returns true if the metadata columns at the same positions in the array are equivalent. */
15378 function isMetadataEquivalent(metadata1, metadata2) {
15379 if (!metadata1 && !metadata2)
15380 return true;
15381 if (!metadata1 || !metadata2)
15382 return false;
15383 var previousColumnsLength = metadata1.columns.length;
15384 var newColumnsLength = metadata2.columns.length;
15385 if (previousColumnsLength !== newColumnsLength)
15386 return false;
15387 for (var i = 0; i < newColumnsLength; i++) {
15388 if (!DataViewAnalysis.areMetadataColumnsEquivalent(metadata1.columns[i], metadata2.columns[i]))
15389 return false;
15390 }
15391 return true;
15392 }
15393 DataViewAnalysis.isMetadataEquivalent = isMetadataEquivalent;
15394 })(DataViewAnalysis = powerbi.DataViewAnalysis || (powerbi.DataViewAnalysis = {}));
15395})(powerbi || (powerbi = {}));
15396/*
15397 * Power BI Visualizations
15398 *
15399 * Copyright (c) Microsoft Corporation
15400 * All rights reserved.
15401 * MIT License
15402 *
15403 * Permission is hereby granted, free of charge, to any person obtaining a copy
15404 * of this software and associated documentation files (the ""Software""), to deal
15405 * in the Software without restriction, including without limitation the rights
15406 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15407 * copies of the Software, and to permit persons to whom the Software is
15408 * furnished to do so, subject to the following conditions:
15409 *
15410 * The above copyright notice and this permission notice shall be included in
15411 * all copies or substantial portions of the Software.
15412 *
15413 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15414 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15415 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15416 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15417 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15418 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15419 * THE SOFTWARE.
15420 */
15421var powerbi;
15422(function (powerbi) {
15423 var data;
15424 (function (data) {
15425 var ArrayExtensions = jsCommon.ArrayExtensions;
15426 var Lazy = jsCommon.Lazy;
15427 var DataViewRoleWildcard;
15428 (function (DataViewRoleWildcard) {
15429 function fromRoles(roles) {
15430 return new DataViewRoleWildcardImpl(roles);
15431 }
15432 DataViewRoleWildcard.fromRoles = fromRoles;
15433 function equals(firstRoleWildcard, secondRoleWildcard) {
15434 return firstRoleWildcard.key &&
15435 secondRoleWildcard.key &&
15436 firstRoleWildcard.key === secondRoleWildcard.key &&
15437 ArrayExtensions.sequenceEqual(firstRoleWildcard.roles, secondRoleWildcard.roles, function (role1, role2) { return role1 === role2; });
15438 }
15439 DataViewRoleWildcard.equals = equals;
15440 var DataViewRoleWildcardImpl = (function () {
15441 function DataViewRoleWildcardImpl(roles) {
15442 var _this = this;
15443 debug.assertNonEmpty(roles, 'roles');
15444 this._roles = roles;
15445 this._key = new Lazy(function () { return JSON.stringify(_this.roles); });
15446 }
15447 Object.defineProperty(DataViewRoleWildcardImpl.prototype, "roles", {
15448 get: function () {
15449 return this._roles;
15450 },
15451 enumerable: true,
15452 configurable: true
15453 });
15454 Object.defineProperty(DataViewRoleWildcardImpl.prototype, "key", {
15455 get: function () {
15456 return this._key.getValue();
15457 },
15458 enumerable: true,
15459 configurable: true
15460 });
15461 return DataViewRoleWildcardImpl;
15462 }());
15463 })(DataViewRoleWildcard = data.DataViewRoleWildcard || (data.DataViewRoleWildcard = {}));
15464 })(data = powerbi.data || (powerbi.data = {}));
15465})(powerbi || (powerbi = {}));
15466/*
15467 * Power BI Visualizations
15468 *
15469 * Copyright (c) Microsoft Corporation
15470 * All rights reserved.
15471 * MIT License
15472 *
15473 * Permission is hereby granted, free of charge, to any person obtaining a copy
15474 * of this software and associated documentation files (the ""Software""), to deal
15475 * in the Software without restriction, including without limitation the rights
15476 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15477 * copies of the Software, and to permit persons to whom the Software is
15478 * furnished to do so, subject to the following conditions:
15479 *
15480 * The above copyright notice and this permission notice shall be included in
15481 * all copies or substantial portions of the Software.
15482 *
15483 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15484 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15485 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15486 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15487 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15488 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15489 * THE SOFTWARE.
15490 */
15491var powerbi;
15492(function (powerbi) {
15493 var DataViewScopeIdentity;
15494 (function (DataViewScopeIdentity) {
15495 /** Compares the two DataViewScopeIdentity values for equality. */
15496 function equals(x, y, ignoreCase) {
15497 // Normalize falsy to null
15498 x = x || null;
15499 y = y || null;
15500 if (x === y)
15501 return true;
15502 if (!x !== !y)
15503 return false;
15504 debug.assertValue(x, 'x');
15505 debug.assertValue(y, 'y');
15506 return data.SQExpr.equals(x.expr, y.expr, ignoreCase);
15507 }
15508 DataViewScopeIdentity.equals = equals;
15509 function filterFromIdentity(identities, isNot) {
15510 if (_.isEmpty(identities))
15511 return;
15512 var exprs = [];
15513 for (var _i = 0, identities_1 = identities; _i < identities_1.length; _i++) {
15514 var identity = identities_1[_i];
15515 exprs.push(identity.expr);
15516 }
15517 return filterFromExprs(exprs, isNot);
15518 }
15519 DataViewScopeIdentity.filterFromIdentity = filterFromIdentity;
15520 function filterFromExprs(orExprs, isNot) {
15521 if (_.isEmpty(orExprs))
15522 return;
15523 var resultExpr;
15524 for (var _i = 0, orExprs_1 = orExprs; _i < orExprs_1.length; _i++) {
15525 var orExpr = orExprs_1[_i];
15526 var inExpr = data.ScopeIdentityExtractor.getInExpr(orExpr);
15527 if (resultExpr)
15528 resultExpr = data.SQExprBuilder.or(resultExpr, inExpr);
15529 else
15530 resultExpr = inExpr || orExpr;
15531 }
15532 if (resultExpr) {
15533 if (isNot)
15534 resultExpr = powerbi.data.SQExprBuilder.not(resultExpr);
15535 }
15536 return powerbi.data.SemanticFilter.fromSQExpr(resultExpr);
15537 }
15538 DataViewScopeIdentity.filterFromExprs = filterFromExprs;
15539 })(DataViewScopeIdentity = powerbi.DataViewScopeIdentity || (powerbi.DataViewScopeIdentity = {}));
15540 var data;
15541 (function (data) {
15542 var Lazy = jsCommon.Lazy;
15543 function createDataViewScopeIdentity(expr) {
15544 return new DataViewScopeIdentityImpl(expr);
15545 }
15546 data.createDataViewScopeIdentity = createDataViewScopeIdentity;
15547 var DataViewScopeIdentityImpl = (function () {
15548 function DataViewScopeIdentityImpl(expr) {
15549 debug.assertValue(expr, 'expr');
15550 this._expr = expr;
15551 this._key = new Lazy(function () { return data.SQExprShortSerializer.serialize(expr); });
15552 }
15553 Object.defineProperty(DataViewScopeIdentityImpl.prototype, "expr", {
15554 get: function () {
15555 return this._expr;
15556 },
15557 enumerable: true,
15558 configurable: true
15559 });
15560 Object.defineProperty(DataViewScopeIdentityImpl.prototype, "key", {
15561 get: function () {
15562 return this._key.getValue();
15563 },
15564 enumerable: true,
15565 configurable: true
15566 });
15567 return DataViewScopeIdentityImpl;
15568 }());
15569 })(data = powerbi.data || (powerbi.data = {}));
15570})(powerbi || (powerbi = {}));
15571/*
15572 * Power BI Visualizations
15573 *
15574 * Copyright (c) Microsoft Corporation
15575 * All rights reserved.
15576 * MIT License
15577 *
15578 * Permission is hereby granted, free of charge, to any person obtaining a copy
15579 * of this software and associated documentation files (the ""Software""), to deal
15580 * in the Software without restriction, including without limitation the rights
15581 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15582 * copies of the Software, and to permit persons to whom the Software is
15583 * furnished to do so, subject to the following conditions:
15584 *
15585 * The above copyright notice and this permission notice shall be included in
15586 * all copies or substantial portions of the Software.
15587 *
15588 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15589 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15590 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15591 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15592 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15593 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15594 * THE SOFTWARE.
15595 */
15596var powerbi;
15597(function (powerbi) {
15598 var data;
15599 (function (data) {
15600 var Lazy = jsCommon.Lazy;
15601 var DataViewScopeWildcard;
15602 (function (DataViewScopeWildcard) {
15603 function matches(wildcard, instance) {
15604 var instanceExprs = data.ScopeIdentityExtractor.getKeys(instance.expr);
15605 if (!instanceExprs)
15606 return false;
15607 return data.SQExprUtils.sequenceEqual(wildcard.exprs, instanceExprs);
15608 }
15609 DataViewScopeWildcard.matches = matches;
15610 function equals(firstScopeWildcard, secondScopeWildcard) {
15611 return firstScopeWildcard.key === secondScopeWildcard.key &&
15612 data.SQExprUtils.sequenceEqual(firstScopeWildcard.exprs, secondScopeWildcard.exprs);
15613 }
15614 DataViewScopeWildcard.equals = equals;
15615 function fromExprs(exprs) {
15616 return new DataViewScopeWildcardImpl(exprs);
15617 }
15618 DataViewScopeWildcard.fromExprs = fromExprs;
15619 var DataViewScopeWildcardImpl = (function () {
15620 function DataViewScopeWildcardImpl(exprs) {
15621 debug.assertValue(exprs, 'exprs');
15622 this._exprs = exprs;
15623 this._key = new Lazy(function () { return data.SQExprShortSerializer.serializeArray(exprs); });
15624 }
15625 Object.defineProperty(DataViewScopeWildcardImpl.prototype, "exprs", {
15626 get: function () {
15627 return this._exprs;
15628 },
15629 enumerable: true,
15630 configurable: true
15631 });
15632 Object.defineProperty(DataViewScopeWildcardImpl.prototype, "key", {
15633 get: function () {
15634 return this._key.getValue();
15635 },
15636 enumerable: true,
15637 configurable: true
15638 });
15639 return DataViewScopeWildcardImpl;
15640 }());
15641 })(DataViewScopeWildcard = data.DataViewScopeWildcard || (data.DataViewScopeWildcard = {}));
15642 })(data = powerbi.data || (powerbi.data = {}));
15643})(powerbi || (powerbi = {}));
15644/*
15645 * Power BI Visualizations
15646 *
15647 * Copyright (c) Microsoft Corporation
15648 * All rights reserved.
15649 * MIT License
15650 *
15651 * Permission is hereby granted, free of charge, to any person obtaining a copy
15652 * of this software and associated documentation files (the ""Software""), to deal
15653 * in the Software without restriction, including without limitation the rights
15654 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15655 * copies of the Software, and to permit persons to whom the Software is
15656 * furnished to do so, subject to the following conditions:
15657 *
15658 * The above copyright notice and this permission notice shall be included in
15659 * all copies or substantial portions of the Software.
15660 *
15661 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15662 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15663 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15664 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15665 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15666 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15667 * THE SOFTWARE.
15668 */
15669var powerbi;
15670(function (powerbi) {
15671 var data;
15672 (function (data) {
15673 function createColorAllocatorCache() {
15674 return new ColorAllocatorProvider();
15675 }
15676 data.createColorAllocatorCache = createColorAllocatorCache;
15677 var ColorAllocatorProvider = (function () {
15678 function ColorAllocatorProvider() {
15679 this.cache = [];
15680 }
15681 ColorAllocatorProvider.prototype.get = function (key) {
15682 debug.assertValue(key, 'key');
15683 for (var _i = 0, _a = this.cache; _i < _a.length; _i++) {
15684 var entry = _a[_i];
15685 if (entry.key === key)
15686 return entry.allocator;
15687 }
15688 };
15689 ColorAllocatorProvider.prototype.register = function (key, colorAllocator) {
15690 debug.assertValue(key, 'key');
15691 debug.assertValue(colorAllocator, 'colorAllocator');
15692 debug.assert(this.get(key) == null, 'Trying to re-register for same key expr.');
15693 this.cache.push({
15694 key: key,
15695 allocator: colorAllocator,
15696 });
15697 return this;
15698 };
15699 return ColorAllocatorProvider;
15700 }());
15701 })(data = powerbi.data || (powerbi.data = {}));
15702})(powerbi || (powerbi = {}));
15703/*
15704 * Power BI Visualizations
15705 *
15706 * Copyright (c) Microsoft Corporation
15707 * All rights reserved.
15708 * MIT License
15709 *
15710 * Permission is hereby granted, free of charge, to any person obtaining a copy
15711 * of this software and associated documentation files (the ""Software""), to deal
15712 * in the Software without restriction, including without limitation the rights
15713 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15714 * copies of the Software, and to permit persons to whom the Software is
15715 * furnished to do so, subject to the following conditions:
15716 *
15717 * The above copyright notice and this permission notice shall be included in
15718 * all copies or substantial portions of the Software.
15719 *
15720 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15721 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15722 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15723 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15724 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15725 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15726 * THE SOFTWARE.
15727 */
15728/*
15729 * Power BI Visualizations
15730 *
15731 * Copyright (c) Microsoft Corporation
15732 * All rights reserved.
15733 * MIT License
15734 *
15735 * Permission is hereby granted, free of charge, to any person obtaining a copy
15736 * of this software and associated documentation files (the ""Software""), to deal
15737 * in the Software without restriction, including without limitation the rights
15738 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15739 * copies of the Software, and to permit persons to whom the Software is
15740 * furnished to do so, subject to the following conditions:
15741 *
15742 * The above copyright notice and this permission notice shall be included in
15743 * all copies or substantial portions of the Software.
15744 *
15745 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15746 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15747 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15748 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15749 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15750 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15751 * THE SOFTWARE.
15752 */
15753var powerbi;
15754(function (powerbi) {
15755 var data;
15756 (function (data) {
15757 var DataViewRegression;
15758 (function (DataViewRegression) {
15759 // TODO VSTS 6842046: Currently we are using a constant queryName since we don't have a way to generate
15760 // unique ones. There is a bug filed to do this by lawong, so this part will be fixed with that bug.
15761 var regressionXQueryName = 'RegressionX';
15762 var regressionSeriesQueryName = 'RegressionSeries';
15763 DataViewRegression.regressionYQueryName = 'RegressionY';
15764 function run(options) {
15765 debug.assertValue(options, 'options');
15766 var dataViewMappings = options.dataViewMappings;
15767 var visualDataViews = options.visualDataViews;
15768 var dataRoles = options.dataRoles;
15769 var objectDescriptors = options.objectDescriptors;
15770 var objectDefinitions = options.objectDefinitions;
15771 var colorAllocatorFactory = options.colorAllocatorFactory;
15772 var transformSelects = options.transformSelects;
15773 var projectionActiveItems = options.projectionActiveItems;
15774 var metadata = options.metadata;
15775 if (!_.isEmpty(visualDataViews) && transformSelects && metadata) {
15776 // compute linear regression line if applicable
15777 var roleKindByQueryRef = data.DataViewSelectTransform.createRoleKindFromMetadata(transformSelects, metadata);
15778 var projections = data.DataViewSelectTransform.projectionsFromSelects(transformSelects, projectionActiveItems);
15779 if (!roleKindByQueryRef || !projections || _.isEmpty(dataViewMappings) || !objectDescriptors || !objectDefinitions)
15780 return visualDataViews;
15781 var applicableDataViewMappings = powerbi.DataViewAnalysis.chooseDataViewMappings(projections, dataViewMappings, roleKindByQueryRef, objectDescriptors, objectDefinitions).supportedMappings;
15782 if (applicableDataViewMappings) {
15783 var regressionDataViewMapping = _.find(applicableDataViewMappings, function (dataViewMapping) {
15784 return dataViewMapping.usage && dataViewMapping.usage.regression;
15785 });
15786 if (regressionDataViewMapping) {
15787 var regressionDataViews = [];
15788 for (var _i = 0, visualDataViews_1 = visualDataViews; _i < visualDataViews_1.length; _i++) {
15789 var visualDataView = visualDataViews_1[_i];
15790 var regressionDataView = this.linearRegressionTransform(visualDataView, dataRoles, regressionDataViewMapping, objectDescriptors, objectDefinitions, colorAllocatorFactory);
15791 if (regressionDataView)
15792 regressionDataViews.push(regressionDataView);
15793 }
15794 if (!_.isEmpty(regressionDataViews))
15795 visualDataViews.push.apply(visualDataViews, regressionDataViews);
15796 }
15797 }
15798 }
15799 return visualDataViews;
15800 }
15801 DataViewRegression.run = run;
15802 /**
15803 * This function will compute the linear regression algorithm on the sourceDataView and create a new dataView.
15804 * It works on scalar axis only.
15805 * The algorithm is as follows
15806 *
15807 * 1. Find the cartesian X and Y roles and the columns that correspond to those roles
15808 * 2. Get the data points, (X, Y) pairs, for each series, combining if needed.
15809 * 3. Compute the X and Y points for regression line using Y = Slope * X + Intercept
15810 * If highlights values are present, repeat steps 2 & 3 using highlight values.
15811 * 4. Create the new dataView using the points computed above
15812 */
15813 function linearRegressionTransform(sourceDataView, dataRoles, regressionDataViewMapping, objectDescriptors, objectDefinitions, colorAllocatorFactory) {
15814 debug.assertValue(sourceDataView, 'sourceDataView');
15815 debug.assertValue(sourceDataView.categorical, 'sourceDataView.categorical');
15816 debug.assertValue(dataRoles, 'dataRoles');
15817 debug.assertValue(objectDescriptors, 'objectDescriptors');
15818 debug.assertValue(objectDefinitions, 'objectDefinitions');
15819 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
15820 if (!sourceDataView.categorical)
15821 return;
15822 // Step 1
15823 var xColumns = getColumnsForCartesianRoleKind(0 /* X */, sourceDataView.categorical, dataRoles);
15824 var yColumns = getColumnsForCartesianRoleKind(1 /* Y */, sourceDataView.categorical, dataRoles);
15825 if (_.isEmpty(xColumns) || _.isEmpty(yColumns))
15826 return;
15827 var xColumnSource = xColumns[0].source;
15828 var yColumnSource = yColumns[0].source;
15829 var combineSeries = true;
15830 if (regressionDataViewMapping.usage && regressionDataViewMapping.usage.regression && sourceDataView.metadata.objects) {
15831 var regressionUsage = regressionDataViewMapping.usage.regression;
15832 var combineSeriesPropertyId = regressionUsage['combineSeries'];
15833 if (combineSeriesPropertyId) {
15834 combineSeries = powerbi.DataViewObjects.getValue(sourceDataView.metadata.objects, combineSeriesPropertyId, true);
15835 }
15836 }
15837 // Step 2
15838 var dataPointsBySeries = getDataPointsBySeries(xColumns, yColumns, combineSeries, /* preferHighlights */ false);
15839 var lineDefSet = calculateLineDefinitions(dataPointsBySeries);
15840 var xMin = lineDefSet.xMin;
15841 var xMax = lineDefSet.xMax;
15842 var shouldComputeHightlights = hasHighlightValues(yColumns) || hasHighlightValues(xColumns);
15843 var highlightsLineDefSet;
15844 if (shouldComputeHightlights) {
15845 var highlightDataPointsBySeries = getDataPointsBySeries(xColumns, yColumns, combineSeries, /* preferHighlights */ true);
15846 highlightsLineDefSet = calculateLineDefinitions(highlightDataPointsBySeries);
15847 if (highlightsLineDefSet) {
15848 xMin = _.min([xMin, highlightsLineDefSet.xMin]);
15849 xMax = _.max([xMax, highlightsLineDefSet.xMax]);
15850 }
15851 else {
15852 shouldComputeHightlights = false;
15853 }
15854 }
15855 // Step 3
15856 var valuesByTrend = [];
15857 for (var _i = 0, _a = lineDefSet.lineDefs; _i < _a.length; _i++) {
15858 var trend = _a[_i];
15859 valuesByTrend.push(computeLineYValues(trend, +xMin, +xMax));
15860 }
15861 var highlightsByTrend;
15862 if (shouldComputeHightlights) {
15863 highlightsByTrend = [];
15864 for (var _b = 0, _c = highlightsLineDefSet.lineDefs; _b < _c.length; _b++) {
15865 var trend = _c[_b];
15866 highlightsByTrend.push(computeLineYValues(trend, +xMin, +xMax));
15867 }
15868 }
15869 // Step 4
15870 var groupValues;
15871 if (combineSeries) {
15872 groupValues = ['combinedRegressionSeries'];
15873 }
15874 else {
15875 // If we are producing a trend line per series we need to maintain the group identities so that we can map between the
15876 // trend line and the original series (to match the color for example).
15877 if (sourceDataView.categorical.values.source) {
15878 // Source data view has dynamic series.
15879 var groups = sourceDataView.categorical.values.grouped();
15880 groupValues = _.map(groups, function (group) { return group.name; });
15881 }
15882 else {
15883 // Source data view has static or no series.
15884 groupValues = _.map(yColumns, function (column) { return column.source.queryName; });
15885 }
15886 }
15887 // Step 5
15888 var regressionDataView = createRegressionDataView(xColumnSource, yColumnSource, groupValues, [xMin, xMax], valuesByTrend, highlightsByTrend, sourceDataView, regressionDataViewMapping, objectDescriptors, objectDefinitions, colorAllocatorFactory);
15889 return regressionDataView;
15890 }
15891 DataViewRegression.linearRegressionTransform = linearRegressionTransform;
15892 function calculateLineDefinitions(dataPointsBySeries) {
15893 var xMin;
15894 var xMax;
15895 var lineDefs = [];
15896 for (var _i = 0, dataPointsBySeries_1 = dataPointsBySeries; _i < dataPointsBySeries_1.length; _i++) {
15897 var dataPointSet = dataPointsBySeries_1[_i];
15898 var unsortedXValues = dataPointSet.xValues;
15899 var unsortedYValues = dataPointSet.yValues;
15900 if (_.isEmpty(unsortedXValues) || _.isEmpty(unsortedYValues))
15901 return;
15902 // get the data type for each column; we will have null type when dataPoints have different type or if a value is null
15903 var xDataType = getDataType(unsortedXValues);
15904 if (!xDataType)
15905 return;
15906 var yDataType = getDataType(unsortedYValues);
15907 if (!yDataType)
15908 return;
15909 var sortedDataPointSet = sortValues(unsortedXValues, unsortedYValues);
15910 var minCategoryValue = sortedDataPointSet.xValues[0];
15911 var maxCategoryValue = sortedDataPointSet.xValues[sortedDataPointSet.xValues.length - 1];
15912 var lineDef = computeRegressionLine(sortedDataPointSet.xValues, sortedDataPointSet.yValues);
15913 xMin = _.min([xMin, minCategoryValue]);
15914 xMax = _.max([xMax, maxCategoryValue]);
15915 lineDefs.push(lineDef);
15916 }
15917 return {
15918 lineDefs: lineDefs,
15919 xMin: xMin,
15920 xMax: xMax,
15921 };
15922 }
15923 function getColumnsForCartesianRoleKind(roleKind, categorical, roles) {
15924 debug.assertValue(roleKind, 'roleKind');
15925 debug.assertValue(categorical, 'categorical');
15926 var columns = getColumnsWithRoleKind(roleKind, categorical.values, roles);
15927 if (!_.isEmpty(columns))
15928 return columns;
15929 var categories = categorical.categories;
15930 if (_.isEmpty(categories))
15931 return;
15932 debug.assert(categories.length === 1, 'composite category columns not supported');
15933 var categoryColumn = categories[0];
15934 columns = getColumnsWithRoleKind(roleKind, [categoryColumn], roles);
15935 if (!_.isEmpty(columns))
15936 return columns;
15937 }
15938 function getColumnsWithRoleKind(roleKind, columns, roles) {
15939 if (_.isEmpty(columns))
15940 return;
15941 return _.filter(columns, function (column) {
15942 var _loop_1 = function(roleName) {
15943 if (!column.source.roles[roleName])
15944 return "continue";
15945 var role = _.find(roles, function (role) { return role.name === roleName; });
15946 if (role && role.cartesianKind === roleKind)
15947 return { value: true };
15948 };
15949 for (var roleName in column.source.roles) {
15950 var state_1 = _loop_1(roleName);
15951 if (typeof state_1 === "object") return state_1.value;
15952 if (state_1 === "continue") continue;
15953 }
15954 return false;
15955 });
15956 }
15957 function getDataType(values) {
15958 var firstNonNull = _.find(values, function (value) { return value != null; });
15959 if (firstNonNull == null)
15960 return;
15961 var dataType = typeof firstNonNull;
15962 if (_.some(values, function (value) { return value != null && typeof value !== dataType; }))
15963 return;
15964 return dataType;
15965 }
15966 function sortValues(unsortedXValues, unsortedYValues) {
15967 debug.assertValue(unsortedXValues, 'unsortedXValues');
15968 debug.assertValue(unsortedYValues, 'unsortedYValues');
15969 var zippedValues = _.zip(unsortedXValues, unsortedYValues);
15970 var _a = _.chain(zippedValues)
15971 .filter(function (valuePair) { return valuePair[0] != null && valuePair[1] != null; })
15972 .sortBy(function (valuePair) { return valuePair[0]; })
15973 .unzip()
15974 .value(), xValues = _a[0], yValues = _a[1];
15975 return {
15976 xValues: xValues,
15977 yValues: yValues
15978 };
15979 }
15980 /**
15981 * Computes a line definition using linear regression.
15982 * xBar: average of X values, yBar: average of Y values
15983 * ssXX: sum of squares of X values = Sum(xi - xBar)^2
15984 * ssXY: sum of squares of X and Y values = Sum((xi - xBar)(yi - yBar)
15985 * Slope: ssXY / ssXX
15986 * Intercept: yBar - xBar * slope
15987 */
15988 function computeRegressionLine(xValues, yValues) {
15989 debug.assertValue(xValues, 'xValues');
15990 debug.assertValue(yValues, 'yValues');
15991 var xBar = _.sum(xValues) / xValues.length;
15992 var yBar = _.sum(yValues) / yValues.length;
15993 var ssXX = _.chain(xValues)
15994 .map(function (x) {
15995 return Math.pow((x - xBar), 2);
15996 })
15997 .sum();
15998 var ssXY = _.chain(xValues)
15999 .map(function (x, i) {
16000 return (x - xBar) * (yValues[i] - yBar);
16001 })
16002 .sum();
16003 var slope = ssXY / ssXX;
16004 var intercept = yBar - (xBar * slope);
16005 return {
16006 slope: slope,
16007 intercept: intercept
16008 };
16009 }
16010 function computeLineYValues(lineDef, x1, x2) {
16011 return [x1 * lineDef.slope + lineDef.intercept, x2 * lineDef.slope + lineDef.intercept];
16012 }
16013 function getValuesFromColumn(column, preferHighlights) {
16014 if (preferHighlights) {
16015 // Attempt to use highlight values. When X is categorical, we may not have highlight values so we should fall back to the non-highlight values.
16016 var valueColumn = column;
16017 if (valueColumn.highlights) {
16018 return valueColumn.highlights;
16019 }
16020 }
16021 return column.values;
16022 }
16023 function getDataPointsBySeries(xColumns, yColumns, combineSeries, preferHighlights) {
16024 var dataPointsBySeries = [];
16025 var xValueArray = _.map(xColumns, function (column) { return getValuesFromColumn(column, preferHighlights); });
16026 var seriesYValues = _.map(yColumns, function (column) { return getValuesFromColumn(column, preferHighlights); });
16027 var multipleXValueColumns = xColumns.length > 1;
16028 for (var i = 0; i < seriesYValues.length; i++) {
16029 var xValues = multipleXValueColumns ? xValueArray[i] : xValueArray[0];
16030 var yValues = seriesYValues[i];
16031 if (combineSeries && dataPointsBySeries.length > 0) {
16032 dataPointsBySeries[0].xValues = dataPointsBySeries[0].xValues.concat(xValues);
16033 dataPointsBySeries[0].yValues = dataPointsBySeries[0].yValues.concat(yValues);
16034 }
16035 else {
16036 dataPointsBySeries.push({
16037 xValues: xValues,
16038 yValues: yValues,
16039 });
16040 }
16041 }
16042 return dataPointsBySeries;
16043 }
16044 function createRegressionDataView(xColumnSource, yColumnSource, groupValues, categories, values, highlights, sourceDataView, regressionDataViewMapping, objectDescriptors, objectDefinitions, colorAllocatorFactory) {
16045 debug.assertValue(xColumnSource, 'xColumnSource');
16046 debug.assertValue(yColumnSource, 'yColumnSource');
16047 debug.assertValue(categories, 'categories');
16048 debug.assertValue(values, 'values');
16049 debug.assertValue(sourceDataView, 'sourceDataView');
16050 debug.assertValue(objectDescriptors, 'objectDescriptors');
16051 debug.assertValue(objectDefinitions, 'objectDefinitions');
16052 debug.assertValue(colorAllocatorFactory, 'colorAllocatorFactory');
16053 debug.assertAnyValue(highlights, 'highlights');
16054 debug.assert(!highlights || highlights.length === values.length, 'highlights should have the same length as values');
16055 var xRole = regressionDataViewMapping.categorical.categories.for.in;
16056 var grouped = regressionDataViewMapping.categorical.values.group;
16057 var yRole;
16058 var seriesRole;
16059 if (grouped && !_.isEmpty(grouped.select)) {
16060 yRole = grouped.select[0].for ?
16061 grouped.select[0].for.in :
16062 grouped.select[0].bind.to;
16063 seriesRole = grouped.by;
16064 }
16065 if (!yRole || !seriesRole)
16066 return;
16067 var categoricalRoles = (_a = {}, _a[xRole] = true, _a);
16068 var valueRoles = (_b = {}, _b[yRole] = true, _b);
16069 var seriesRoles = (_c = {}, _c[seriesRole] = true, _c);
16070 var valuesBySeries = [];
16071 for (var index in values) {
16072 var seriesData = {
16073 values: values[index],
16074 };
16075 if (highlights)
16076 seriesData.highlights = highlights[index];
16077 valuesBySeries.push([seriesData]);
16078 }
16079 var regressionDataView = data.createCategoricalDataViewBuilder()
16080 .withCategory({
16081 source: {
16082 displayName: xColumnSource.displayName,
16083 queryName: regressionXQueryName,
16084 type: xColumnSource.type,
16085 isMeasure: false,
16086 roles: categoricalRoles
16087 },
16088 values: categories,
16089 identityFrom: {
16090 fields: [data.SQExprBuilder.columnRef(data.SQExprBuilder.entity('s', 'RegressionEntity'), 'RegressionCategories')],
16091 },
16092 })
16093 .withGroupedValues({
16094 groupColumn: {
16095 source: {
16096 displayName: yColumnSource.displayName + 'Regression',
16097 queryName: regressionSeriesQueryName,
16098 type: yColumnSource.type,
16099 isMeasure: yColumnSource.isMeasure,
16100 roles: seriesRoles
16101 },
16102 values: groupValues,
16103 identityFrom: {
16104 fields: [data.SQExprBuilder.columnRef(data.SQExprBuilder.entity('s', 'RegressionEntity'), 'RegressionSeries')],
16105 }
16106 },
16107 valueColumns: [{
16108 source: {
16109 displayName: yColumnSource.displayName,
16110 queryName: DataViewRegression.regressionYQueryName,
16111 type: yColumnSource.type,
16112 isMeasure: yColumnSource.isMeasure,
16113 roles: valueRoles
16114 },
16115 }],
16116 data: valuesBySeries
16117 })
16118 .build();
16119 data.DataViewTransform.transformObjects(regressionDataView, 1 /* Categorical */, objectDescriptors, objectDefinitions, [], colorAllocatorFactory);
16120 return regressionDataView;
16121 var _a, _b, _c;
16122 }
16123 function hasHighlightValues(columns) {
16124 return _.any(columns, function (column) {
16125 var valueColumn = column;
16126 return valueColumn.highlights != null;
16127 });
16128 }
16129 })(DataViewRegression = data.DataViewRegression || (data.DataViewRegression = {}));
16130 })(data = powerbi.data || (powerbi.data = {}));
16131})(powerbi || (powerbi = {}));
16132/*
16133 * Power BI Visualizations
16134 *
16135 * Copyright (c) Microsoft Corporation
16136 * All rights reserved.
16137 * MIT License
16138 *
16139 * Permission is hereby granted, free of charge, to any person obtaining a copy
16140 * of this software and associated documentation files (the ""Software""), to deal
16141 * in the Software without restriction, including without limitation the rights
16142 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16143 * copies of the Software, and to permit persons to whom the Software is
16144 * furnished to do so, subject to the following conditions:
16145 *
16146 * The above copyright notice and this permission notice shall be included in
16147 * all copies or substantial portions of the Software.
16148 *
16149 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16150 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16151 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16152 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16153 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16154 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16155 * THE SOFTWARE.
16156 */
16157var powerbi;
16158(function (powerbi) {
16159 var data;
16160 (function (data) {
16161 var DataViewSelectTransform;
16162 (function (DataViewSelectTransform) {
16163 /** Convert selection info to projections */
16164 function projectionsFromSelects(selects, projectionActiveItems) {
16165 debug.assertAnyValue(selects, "selects");
16166 debug.assertAnyValue(projectionActiveItems, "projectionActiveItems");
16167 var projections = {};
16168 for (var _i = 0, selects_1 = selects; _i < selects_1.length; _i++) {
16169 var select = selects_1[_i];
16170 var roles = select.roles;
16171 if (!roles)
16172 continue;
16173 for (var roleName in roles) {
16174 if (roles[roleName]) {
16175 var qp = projections[roleName];
16176 if (!qp)
16177 qp = projections[roleName] = new data.QueryProjectionCollection([]);
16178 qp.all().push({ queryRef: select.queryName });
16179 if (projectionActiveItems && projectionActiveItems[roleName])
16180 qp.activeProjectionRefs = _.map(projectionActiveItems[roleName], function (activeItem) { return activeItem.queryRef; });
16181 }
16182 }
16183 }
16184 return projections;
16185 }
16186 DataViewSelectTransform.projectionsFromSelects = projectionsFromSelects;
16187 /** Use selections and metadata to fashion query role kinds */
16188 function createRoleKindFromMetadata(selects, metadata) {
16189 var roleKindByQueryRef = {};
16190 for (var _i = 0, _a = metadata.columns; _i < _a.length; _i++) {
16191 var column = _a[_i];
16192 if ((!column.index && column.index !== 0) || column.index < 0 || column.index >= selects.length)
16193 continue;
16194 var select = selects[column.index];
16195 if (select) {
16196 var queryRef = select.queryName;
16197 if (queryRef && roleKindByQueryRef[queryRef] === undefined) {
16198 roleKindByQueryRef[queryRef] = column.isMeasure ? powerbi.VisualDataRoleKind.Measure : powerbi.VisualDataRoleKind.Grouping;
16199 }
16200 }
16201 }
16202 return roleKindByQueryRef;
16203 }
16204 DataViewSelectTransform.createRoleKindFromMetadata = createRoleKindFromMetadata;
16205 })(DataViewSelectTransform = data.DataViewSelectTransform || (data.DataViewSelectTransform = {}));
16206 })(data = powerbi.data || (powerbi.data = {}));
16207})(powerbi || (powerbi = {}));
16208/*
16209 * Power BI Visualizations
16210 *
16211 * Copyright (c) Microsoft Corporation
16212 * All rights reserved.
16213 * MIT License
16214 *
16215 * Permission is hereby granted, free of charge, to any person obtaining a copy
16216 * of this software and associated documentation files (the ""Software""), to deal
16217 * in the Software without restriction, including without limitation the rights
16218 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16219 * copies of the Software, and to permit persons to whom the Software is
16220 * furnished to do so, subject to the following conditions:
16221 *
16222 * The above copyright notice and this permission notice shall be included in
16223 * all copies or substantial portions of the Software.
16224 *
16225 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16226 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16227 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16228 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16229 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16230 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16231 * THE SOFTWARE.
16232 */
16233var powerbi;
16234(function (powerbi) {
16235 var data;
16236 (function (data) {
16237 function createCategoricalEvalContext(colorAllocatorProvider, dataViewCategorical) {
16238 return new CategoricalEvalContext(colorAllocatorProvider, dataViewCategorical);
16239 }
16240 data.createCategoricalEvalContext = createCategoricalEvalContext;
16241 var CategoricalEvalContext = (function () {
16242 function CategoricalEvalContext(colorAllocatorProvider, dataView) {
16243 debug.assertValue(colorAllocatorProvider, 'colorAllocatorProvider');
16244 debug.assertValue(dataView, 'dataView');
16245 this.colorAllocatorProvider = colorAllocatorProvider;
16246 this.dataView = dataView;
16247 this.columnsByRole = {};
16248 }
16249 CategoricalEvalContext.prototype.getColorAllocator = function (expr) {
16250 return this.colorAllocatorProvider.get(expr);
16251 };
16252 CategoricalEvalContext.prototype.getExprValue = function (expr) {
16253 return;
16254 };
16255 CategoricalEvalContext.prototype.getRoleValue = function (roleName) {
16256 var columnsByRole = this.columnsByRole;
16257 var column = columnsByRole[roleName];
16258 if (!column)
16259 column = columnsByRole[roleName] = findRuleInputColumn(this.dataView, roleName);
16260 if (!column)
16261 return;
16262 var index = this.index;
16263 if (index != null)
16264 return column.values[this.index];
16265 };
16266 CategoricalEvalContext.prototype.setCurrentRowIndex = function (index) {
16267 debug.assertValue(index, 'index');
16268 this.index = index;
16269 };
16270 return CategoricalEvalContext;
16271 }());
16272 function findRuleInputColumn(dataViewCategorical, inputRole) {
16273 debug.assertValue(dataViewCategorical, 'dataViewCategorical');
16274 return findRuleInputInColumns(dataViewCategorical.values, inputRole) ||
16275 findRuleInputInColumns(dataViewCategorical.categories, inputRole);
16276 }
16277 function findRuleInputInColumns(columns, inputRole) {
16278 debug.assertAnyValue(columns, 'columns');
16279 if (!columns)
16280 return;
16281 for (var _i = 0, columns_7 = columns; _i < columns_7.length; _i++) {
16282 var column = columns_7[_i];
16283 var roles = column.source.roles;
16284 if (!roles || !roles[inputRole])
16285 continue;
16286 return column;
16287 }
16288 }
16289 })(data = powerbi.data || (powerbi.data = {}));
16290})(powerbi || (powerbi = {}));
16291/*
16292 * Power BI Visualizations
16293 *
16294 * Copyright (c) Microsoft Corporation
16295 * All rights reserved.
16296 * MIT License
16297 *
16298 * Permission is hereby granted, free of charge, to any person obtaining a copy
16299 * of this software and associated documentation files (the ""Software""), to deal
16300 * in the Software without restriction, including without limitation the rights
16301 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16302 * copies of the Software, and to permit persons to whom the Software is
16303 * furnished to do so, subject to the following conditions:
16304 *
16305 * The above copyright notice and this permission notice shall be included in
16306 * all copies or substantial portions of the Software.
16307 *
16308 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16309 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16310 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16311 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16312 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16313 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16314 * THE SOFTWARE.
16315 */
16316var powerbi;
16317(function (powerbi) {
16318 var data;
16319 (function (data) {
16320 function createTableEvalContext(colorAllocatorProvider, dataViewTable, selectTransforms) {
16321 return new TableEvalContext(colorAllocatorProvider, dataViewTable, selectTransforms);
16322 }
16323 data.createTableEvalContext = createTableEvalContext;
16324 var TableEvalContext = (function () {
16325 function TableEvalContext(colorAllocatorProvider, dataView, selectTransforms) {
16326 debug.assertValue(colorAllocatorProvider, 'colorAllocatorProvider');
16327 debug.assertValue(dataView, 'dataView');
16328 debug.assertValue(selectTransforms, 'selectTransforms');
16329 this.colorAllocatorProvider = colorAllocatorProvider;
16330 this.dataView = dataView;
16331 this.selectTransforms = selectTransforms;
16332 }
16333 TableEvalContext.prototype.getColorAllocator = function (expr) {
16334 return this.colorAllocatorProvider.get(expr);
16335 };
16336 TableEvalContext.prototype.getExprValue = function (expr) {
16337 debug.assertValue(expr, 'expr');
16338 var rowIdx = this.rowIdx;
16339 if (rowIdx == null)
16340 return;
16341 return data.getExprValueFromTable(expr, this.selectTransforms, this.dataView, rowIdx);
16342 };
16343 TableEvalContext.prototype.getRoleValue = function (roleName) {
16344 return;
16345 };
16346 TableEvalContext.prototype.setCurrentRowIndex = function (index) {
16347 debug.assertValue(index, 'index');
16348 this.rowIdx = index;
16349 };
16350 return TableEvalContext;
16351 }());
16352 })(data = powerbi.data || (powerbi.data = {}));
16353})(powerbi || (powerbi = {}));
16354/*
16355 * Power BI Visualizations
16356 *
16357 * Copyright (c) Microsoft Corporation
16358 * All rights reserved.
16359 * MIT License
16360 *
16361 * Permission is hereby granted, free of charge, to any person obtaining a copy
16362 * of this software and associated documentation files (the ""Software""), to deal
16363 * in the Software without restriction, including without limitation the rights
16364 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16365 * copies of the Software, and to permit persons to whom the Software is
16366 * furnished to do so, subject to the following conditions:
16367 *
16368 * The above copyright notice and this permission notice shall be included in
16369 * all copies or substantial portions of the Software.
16370 *
16371 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16372 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16373 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16374 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16375 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16376 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16377 * THE SOFTWARE.
16378 */
16379var powerbi;
16380(function (powerbi) {
16381 var data;
16382 (function (data) {
16383 var RuleEvaluation = (function () {
16384 function RuleEvaluation() {
16385 }
16386 // NOTE: even though this class has no behaviour, we still use a class to facilitate instanceof checks.
16387 RuleEvaluation.prototype.evaluate = function (evalContext) {
16388 debug.assertFail('Abstract method RuleEvaluation.evaluate not implemented.');
16389 };
16390 return RuleEvaluation;
16391 }());
16392 data.RuleEvaluation = RuleEvaluation;
16393 })(data = powerbi.data || (powerbi.data = {}));
16394})(powerbi || (powerbi = {}));
16395/*
16396 * Power BI Visualizations
16397 *
16398 * Copyright (c) Microsoft Corporation
16399 * All rights reserved.
16400 * MIT License
16401 *
16402 * Permission is hereby granted, free of charge, to any person obtaining a copy
16403 * of this software and associated documentation files (the ""Software""), to deal
16404 * in the Software without restriction, including without limitation the rights
16405 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16406 * copies of the Software, and to permit persons to whom the Software is
16407 * furnished to do so, subject to the following conditions:
16408 *
16409 * The above copyright notice and this permission notice shall be included in
16410 * all copies or substantial portions of the Software.
16411 *
16412 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16413 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16414 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16415 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16416 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16417 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16418 * THE SOFTWARE.
16419 */
16420var powerbi;
16421(function (powerbi) {
16422 var data;
16423 (function (data) {
16424 var ColorRuleEvaluation = (function (_super) {
16425 __extends(ColorRuleEvaluation, _super);
16426 function ColorRuleEvaluation(inputRole, allocator) {
16427 debug.assertValue(inputRole, 'inputRole');
16428 debug.assertValue(allocator, 'allocator');
16429 _super.call(this);
16430 this.inputRole = inputRole;
16431 this.allocator = allocator;
16432 }
16433 ColorRuleEvaluation.prototype.evaluate = function (evalContext) {
16434 debug.assertValue(evalContext, 'evalContext');
16435 var value = evalContext.getRoleValue(this.inputRole);
16436 if (value !== undefined)
16437 return this.allocator.color(value);
16438 };
16439 return ColorRuleEvaluation;
16440 }(data.RuleEvaluation));
16441 data.ColorRuleEvaluation = ColorRuleEvaluation;
16442 })(data = powerbi.data || (powerbi.data = {}));
16443})(powerbi || (powerbi = {}));
16444/*
16445 * Power BI Visualizations
16446 *
16447 * Copyright (c) Microsoft Corporation
16448 * All rights reserved.
16449 * MIT License
16450 *
16451 * Permission is hereby granted, free of charge, to any person obtaining a copy
16452 * of this software and associated documentation files (the ""Software""), to deal
16453 * in the Software without restriction, including without limitation the rights
16454 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16455 * copies of the Software, and to permit persons to whom the Software is
16456 * furnished to do so, subject to the following conditions:
16457 *
16458 * The above copyright notice and this permission notice shall be included in
16459 * all copies or substantial portions of the Software.
16460 *
16461 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16462 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16463 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16464 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16465 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16466 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16467 * THE SOFTWARE.
16468 */
16469var powerbi;
16470(function (powerbi) {
16471 var data;
16472 (function (data) {
16473 var utils;
16474 (function (utils) {
16475 var inherit = powerbi.Prototype.inherit;
16476 var inheritSingle = powerbi.Prototype.inheritSingle;
16477 var ArrayExtensions = jsCommon.ArrayExtensions;
16478 var DataViewMatrixUtils;
16479 (function (DataViewMatrixUtils) {
16480 /**
16481 * Invokes the specified callback once per leaf nodes (including root-level leaves and descendent leaves) of the
16482 * specified rootNodes, with an optional index parameter in the callback that is the 0-based index of the
16483 * particular leaf node in the context of this forEachLeafNode(...) invocation.
16484 *
16485 * If rootNodes is null or undefined or empty, the specified callback will not get invoked.
16486 *
16487 * The treePath parameter in the callback is an ordered set of nodes that form the path from the specified
16488 * rootNodes down to the leafNode argument itself. If callback leafNode is one of the specified rootNodes,
16489 * then treePath will be an array of length 1 containing that very node.
16490 *
16491 * IMPORTANT: The treePath array passed to the callback will be modified after the callback function returns!
16492 * If your callback needs to retain a copy of the treePath, please clone the array before returning.
16493 */
16494 function forEachLeafNode(rootNodes, callback) {
16495 debug.assertAnyValue(rootNodes, 'rootNodes');
16496 debug.assertValue(callback, 'callback');
16497 // Note: Don't do "if (!_.isEmpty(rootNodes))" for checking whether rootNodes is an empty array DataViewMatrixNode[],
16498 // because rootNodes can also be an non-array DataViewMatrixNode, and an empty object can be a valid root node DataViewMatrixNode,
16499 // for the fact that all the properties on DataViewMatrixNode are optional...
16500 if (rootNodes) {
16501 if (isNodeArray(rootNodes)) {
16502 var index = 0;
16503 for (var _i = 0, rootNodes_1 = rootNodes; _i < rootNodes_1.length; _i++) {
16504 var rootNode = rootNodes_1[_i];
16505 if (rootNode) {
16506 index = forEachLeafNodeRecursive(rootNode, index, [], callback);
16507 }
16508 }
16509 }
16510 else {
16511 forEachLeafNodeRecursive(rootNodes, 0, [], callback);
16512 }
16513 }
16514 }
16515 DataViewMatrixUtils.forEachLeafNode = forEachLeafNode;
16516 function isNodeArray(nodeOrNodeArray) {
16517 return ArrayExtensions.isArrayOrInheritedArray(nodeOrNodeArray);
16518 }
16519 /**
16520 * Recursively traverses to each leaf node of the specified matrixNode and invokes callback with each of them.
16521 * Returns the index for the next node after the last node that this function invokes callback with.
16522 *
16523 * @treePath an array that contains the path from the specified rootNodes in forEachLeafNode() down to the parent of the argument matrixNode (i.e. treePath does not contain the matrixNode argument yet).
16524 */
16525 function forEachLeafNodeRecursive(matrixNode, nextIndex, treePath, callback) {
16526 debug.assertValue(matrixNode, 'matrixNode');
16527 debug.assertValue(treePath, 'treePath');
16528 debug.assertValue(callback, 'callback');
16529 // If treePath already contains matrixNode, then either one of the following errors has happened:
16530 // 1. the caller code mistakenly added matrixNode to treePath, or
16531 // 2. the callback modified treePath by adding a node to it, or
16532 // 3. the matrix hierarchy contains a cyclical node reference.');
16533 debug.assert(!_.contains(treePath, matrixNode), 'pre-condition: treePath must not already contain matrixNode');
16534 treePath.push(matrixNode);
16535 if (_.isEmpty(matrixNode.children)) {
16536 callback(matrixNode, nextIndex, treePath);
16537 nextIndex++;
16538 }
16539 else {
16540 var children = matrixNode.children;
16541 for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
16542 var nextChild = children_1[_i];
16543 if (nextChild) {
16544 nextIndex = forEachLeafNodeRecursive(nextChild, nextIndex, treePath, callback);
16545 }
16546 }
16547 }
16548 debug.assert(_.last(treePath) === matrixNode, 'pre-condition: the callback given to forEachLeafNode() is not supposed to modify the treePath argument array.');
16549 treePath.pop();
16550 return nextIndex;
16551 }
16552 /**
16553 * Returned an object tree where each node and its children property are inherited from the specified node
16554 * hierarchy, from the root down to the nodes at the specified deepestLevelToInherit, inclusively.
16555 *
16556 * The inherited nodes at level === deepestLevelToInherit will NOT get an inherited version of children array
16557 * property, i.e. its children property is the same array object referenced in the input node's object tree.
16558 *
16559 * @param node The input node with the hierarchy object tree.
16560 * @param deepestLevelToInherit The highest level for a node to get inherited. See DataViewMatrixNode.level property.
16561 * @param useInheritSingle If true, then a node will get inherited in the returned object tree only if it is
16562 * not already an inherited object. Same goes for the node's children property. This is useful for creating
16563 * "visual DataView" objects from "query DataView" objects, as object inheritance is the mechanism for
16564 * "visual DataView" to override properties in "query DataView", and that "query DataView" never contains
16565 * inherited objects.
16566 */
16567 function inheritMatrixNodeHierarchy(node, deepestLevelToInherit, useInheritSingle) {
16568 debug.assertValue(node, 'node');
16569 debug.assert(deepestLevelToInherit >= 0, 'deepestLevelToInherit >= 0');
16570 debug.assertValue(useInheritSingle, 'useInheritSingle');
16571 var returnNode = node;
16572 // Note: The level property of DataViewMatrix.rows.root and DataViewMatrix.columns.root are always undefined.
16573 // Also, in a matrix with multiple column grouping fields and multiple value fields, the DataViewMatrixNode
16574 // for the Grand Total column in the column hierarchy will have children nodes where level > (parent.level + 1):
16575 // {
16576 // "level": 0,
16577 // "isSubtotal": true,
16578 // "children": [
16579 // { "level": 2, "isSubtotal": true },
16580 // { "level": 2, "levelSourceIndex": 1, "isSubtotal": true }
16581 // ]
16582 // }
16583 var isRootNode = _.isUndefined(node.level);
16584 var shouldInheritCurrentNode = isRootNode || (node.level <= deepestLevelToInherit);
16585 if (shouldInheritCurrentNode) {
16586 var inheritFunc = useInheritSingle ? inheritSingle : inherit;
16587 var inheritedNode = inheritFunc(node);
16588 var shouldInheritChildNodes = isRootNode || (node.level < deepestLevelToInherit);
16589 if (shouldInheritChildNodes && !_.isEmpty(node.children)) {
16590 inheritedNode.children = inheritFunc(node.children); // first, make an inherited array
16591 for (var i = 0, ilen = inheritedNode.children.length; i < ilen; i++) {
16592 inheritedNode.children[i] =
16593 inheritMatrixNodeHierarchy(inheritedNode.children[i], deepestLevelToInherit, useInheritSingle);
16594 }
16595 }
16596 returnNode = inheritedNode;
16597 }
16598 return returnNode;
16599 }
16600 DataViewMatrixUtils.inheritMatrixNodeHierarchy = inheritMatrixNodeHierarchy;
16601 /**
16602 * Returns true if the specified matrixOrHierarchy contains any composite grouping, i.e. a grouping on multiple columns.
16603 * An example of composite grouping is one on [Year, Quarter, Month], where a particular group instance can have
16604 * Year === 2016, Quarter === 'Qtr 1', Month === 1.
16605 *
16606 * Returns false if the specified matrixOrHierarchy does not contain any composite group,
16607 * or if matrixOrHierarchy is null or undefined.
16608 */
16609 function containsCompositeGroup(matrixOrHierarchy) {
16610 debug.assertAnyValue(matrixOrHierarchy, 'matrixOrHierarchy');
16611 var hasCompositeGroup = false;
16612 if (matrixOrHierarchy) {
16613 if (isMatrix(matrixOrHierarchy)) {
16614 hasCompositeGroup = containsCompositeGroup(matrixOrHierarchy.rows) ||
16615 containsCompositeGroup(matrixOrHierarchy.columns);
16616 }
16617 else {
16618 var hierarchyLevels = matrixOrHierarchy.levels;
16619 if (!_.isEmpty(hierarchyLevels)) {
16620 for (var _i = 0, hierarchyLevels_1 = hierarchyLevels; _i < hierarchyLevels_1.length; _i++) {
16621 var level = hierarchyLevels_1[_i];
16622 // it takes at least 2 columns at the same hierarchy level to form a composite group...
16623 if (level.sources && (level.sources.length >= 2)) {
16624 debug.assert(_.all(level.sources, function (sourceColumn) { return sourceColumn.isMeasure === level.sources[0].isMeasure; }), 'pre-condition: in a valid DataViewMatrix, the source columns in each of its hierarchy levels must either be all non-measure columns (i.e. a grouping level) or all measure columns (i.e. a measure headers level)');
16625 // Measure headers are not group
16626 var isMeasureHeadersLevel = level.sources[0].isMeasure;
16627 if (!isMeasureHeadersLevel) {
16628 hasCompositeGroup = true;
16629 break;
16630 }
16631 }
16632 }
16633 }
16634 }
16635 }
16636 return hasCompositeGroup;
16637 }
16638 DataViewMatrixUtils.containsCompositeGroup = containsCompositeGroup;
16639 function isMatrix(matrixOrHierarchy) {
16640 return 'rows' in matrixOrHierarchy &&
16641 'columns' in matrixOrHierarchy &&
16642 'valueSources' in matrixOrHierarchy;
16643 }
16644 })(DataViewMatrixUtils = utils.DataViewMatrixUtils || (utils.DataViewMatrixUtils = {}));
16645 })(utils = data.utils || (data.utils = {}));
16646 })(data = powerbi.data || (powerbi.data = {}));
16647})(powerbi || (powerbi = {}));
16648/*
16649 * Power BI Visualizations
16650 *
16651 * Copyright (c) Microsoft Corporation
16652 * All rights reserved.
16653 * MIT License
16654 *
16655 * Permission is hereby granted, free of charge, to any person obtaining a copy
16656 * of this software and associated documentation files (the ""Software""), to deal
16657 * in the Software without restriction, including without limitation the rights
16658 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16659 * copies of the Software, and to permit persons to whom the Software is
16660 * furnished to do so, subject to the following conditions:
16661 *
16662 * The above copyright notice and this permission notice shall be included in
16663 * all copies or substantial portions of the Software.
16664 *
16665 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16666 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16667 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16668 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16669 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16670 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16671 * THE SOFTWARE.
16672 */
16673var powerbi;
16674(function (powerbi) {
16675 var data;
16676 (function (data) {
16677 var utils;
16678 (function (utils) {
16679 var DataViewMetadataColumnUtils;
16680 (function (DataViewMetadataColumnUtils) {
16681 /**
16682 * Returns true iff the specified metadataColumn is assigned to the specified targetRole.
16683 */
16684 function isForRole(metadataColumn, targetRole) {
16685 debug.assertValue(metadataColumn, 'metadataColumn');
16686 debug.assertValue(targetRole, 'targetRole');
16687 var roles = metadataColumn.roles;
16688 return roles && roles[targetRole];
16689 }
16690 DataViewMetadataColumnUtils.isForRole = isForRole;
16691 /**
16692 * Joins each column in the specified columnSources with projection ordering index into a wrapper object.
16693 *
16694 * Note: In order for this function to reliably calculate the "source index" of a particular column, the
16695 * specified columnSources must be a non-filtered array of column sources from the DataView, such as
16696 * the DataViewHierarchyLevel.sources and DataViewMatrix.valueSources array properties.
16697 *
16698 * @param columnSources E.g. DataViewHierarchyLevel.sources, DataViewMatrix.valueSources...
16699 * @param projection The projection ordering. It must contain an ordering for the specified role.
16700 * @param role The role for getting the relevant projection ordering, as well as for filtering out the irrevalent columns in columnSources.
16701 */
16702 function joinMetadataColumnsAndProjectionOrder(columnSources, projection, role) {
16703 debug.assertAnyValue(columnSources, 'columnSources');
16704 debug.assert(_.all(columnSources, function (column) { return _.isNumber(column.index); }), 'pre-condition: Every value in columnSources must already have its Select Index property initialized.');
16705 debug.assertNonEmpty(projection[role], 'projection[role]');
16706 debug.assert(_.all(columnSources, function (column) { return !isForRole(column, role) || _.contains(projection[role], column.index); }), 'pre-condition: The projection order for the specified role must contain the Select Index of every column with matching role in the specified columnSources.');
16707 var jointResult = [];
16708 if (!_.isEmpty(columnSources)) {
16709 var projectionOrderSelectIndices = projection[role];
16710 var selectIndexToProjectionIndexMap = {};
16711 for (var i = 0, ilen = projectionOrderSelectIndices.length; i < ilen; i++) {
16712 var selectIndex = projectionOrderSelectIndices[i];
16713 selectIndexToProjectionIndexMap[selectIndex] = i;
16714 }
16715 for (var j = 0, jlen = columnSources.length; j < jlen; j++) {
16716 var column = columnSources[j];
16717 if (isForRole(column, role)) {
16718 var jointColumnInfo = {
16719 metadataColumn: column,
16720 sourceIndex: j,
16721 projectionOrderIndex: selectIndexToProjectionIndexMap[column.index]
16722 };
16723 jointResult.push(jointColumnInfo);
16724 }
16725 }
16726 }
16727 return jointResult;
16728 }
16729 DataViewMetadataColumnUtils.joinMetadataColumnsAndProjectionOrder = joinMetadataColumnsAndProjectionOrder;
16730 })(DataViewMetadataColumnUtils = utils.DataViewMetadataColumnUtils || (utils.DataViewMetadataColumnUtils = {}));
16731 })(utils = data.utils || (data.utils = {}));
16732 })(data = powerbi.data || (powerbi.data = {}));
16733})(powerbi || (powerbi = {}));
16734/*
16735 * Power BI Visualizations
16736 *
16737 * Copyright (c) Microsoft Corporation
16738 * All rights reserved.
16739 * MIT License
16740 *
16741 * Permission is hereby granted, free of charge, to any person obtaining a copy
16742 * of this software and associated documentation files (the ""Software""), to deal
16743 * in the Software without restriction, including without limitation the rights
16744 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16745 * copies of the Software, and to permit persons to whom the Software is
16746 * furnished to do so, subject to the following conditions:
16747 *
16748 * The above copyright notice and this permission notice shall be included in
16749 * all copies or substantial portions of the Software.
16750 *
16751 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16752 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16753 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16754 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16755 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16756 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16757 * THE SOFTWARE.
16758 */
16759var powerbi;
16760(function (powerbi) {
16761 var data;
16762 (function (data) {
16763 var ConceptualSchema = (function () {
16764 function ConceptualSchema() {
16765 }
16766 ConceptualSchema.prototype.findProperty = function (entityName, propertyName) {
16767 var entity = this.entities.withName(entityName);
16768 if (!entity || _.isEmpty(entity.properties))
16769 return;
16770 return entity.properties.withName(propertyName);
16771 };
16772 ConceptualSchema.prototype.findHierarchy = function (entityName, name) {
16773 var entity = this.entities.withName(entityName);
16774 if (!entity || _.isEmpty(entity.hierarchies))
16775 return;
16776 return entity.hierarchies.withName(name);
16777 };
16778 ConceptualSchema.prototype.findHierarchyByVariation = function (variationEntityName, variationColumnName, variationName, hierarchyName) {
16779 var variationEntity = this.entities.withName(variationEntityName);
16780 if (!variationEntity || _.isEmpty(variationEntity.properties))
16781 return;
16782 var variationProperty = variationEntity.properties.withName(variationColumnName);
16783 if (!variationProperty)
16784 return;
16785 var variationColumn = variationProperty.column;
16786 if (!variationColumn || _.isEmpty(variationColumn.variations))
16787 return;
16788 var variation = variationColumn.variations.withName(variationName);
16789 if (variation) {
16790 var targetEntity = variation.navigationProperty ? variation.navigationProperty.targetEntity : variationEntity;
16791 if (!targetEntity || _.isEmpty(targetEntity.hierarchies))
16792 return;
16793 return targetEntity.hierarchies.withName(hierarchyName);
16794 }
16795 };
16796 /**
16797 * Returns the first property of the entity whose kpi is tied to kpiProperty
16798 */
16799 ConceptualSchema.prototype.findPropertyWithKpi = function (entityName, kpiProperty) {
16800 debug.assertValue(kpiProperty, 'kpiProperty');
16801 var entity = this.entities.withName(entityName);
16802 if (!entity || _.isEmpty(entity.properties))
16803 return;
16804 for (var _i = 0, _a = entity.properties; _i < _a.length; _i++) {
16805 var prop = _a[_i];
16806 if (prop &&
16807 prop.measure &&
16808 prop.measure.kpi &&
16809 (prop.measure.kpi.status === kpiProperty || prop.measure.kpi.goal === kpiProperty))
16810 return prop;
16811 }
16812 return;
16813 };
16814 return ConceptualSchema;
16815 }());
16816 data.ConceptualSchema = ConceptualSchema;
16817 // TODO: Remove this (replaced by ValueType)
16818 (function (ConceptualDataCategory) {
16819 ConceptualDataCategory[ConceptualDataCategory["None"] = 0] = "None";
16820 ConceptualDataCategory[ConceptualDataCategory["Address"] = 1] = "Address";
16821 ConceptualDataCategory[ConceptualDataCategory["City"] = 2] = "City";
16822 ConceptualDataCategory[ConceptualDataCategory["Company"] = 3] = "Company";
16823 ConceptualDataCategory[ConceptualDataCategory["Continent"] = 4] = "Continent";
16824 ConceptualDataCategory[ConceptualDataCategory["Country"] = 5] = "Country";
16825 ConceptualDataCategory[ConceptualDataCategory["County"] = 6] = "County";
16826 ConceptualDataCategory[ConceptualDataCategory["Date"] = 7] = "Date";
16827 ConceptualDataCategory[ConceptualDataCategory["Image"] = 8] = "Image";
16828 ConceptualDataCategory[ConceptualDataCategory["ImageUrl"] = 9] = "ImageUrl";
16829 ConceptualDataCategory[ConceptualDataCategory["Latitude"] = 10] = "Latitude";
16830 ConceptualDataCategory[ConceptualDataCategory["Longitude"] = 11] = "Longitude";
16831 ConceptualDataCategory[ConceptualDataCategory["Organization"] = 12] = "Organization";
16832 ConceptualDataCategory[ConceptualDataCategory["Place"] = 13] = "Place";
16833 ConceptualDataCategory[ConceptualDataCategory["PostalCode"] = 14] = "PostalCode";
16834 ConceptualDataCategory[ConceptualDataCategory["Product"] = 15] = "Product";
16835 ConceptualDataCategory[ConceptualDataCategory["StateOrProvince"] = 16] = "StateOrProvince";
16836 ConceptualDataCategory[ConceptualDataCategory["WebUrl"] = 17] = "WebUrl";
16837 })(data.ConceptualDataCategory || (data.ConceptualDataCategory = {}));
16838 var ConceptualDataCategory = data.ConceptualDataCategory;
16839 })(data = powerbi.data || (powerbi.data = {}));
16840})(powerbi || (powerbi = {}));
16841/*
16842 * Power BI Visualizations
16843 *
16844 * Copyright (c) Microsoft Corporation
16845 * All rights reserved.
16846 * MIT License
16847 *
16848 * Permission is hereby granted, free of charge, to any person obtaining a copy
16849 * of this software and associated documentation files (the ""Software""), to deal
16850 * in the Software without restriction, including without limitation the rights
16851 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16852 * copies of the Software, and to permit persons to whom the Software is
16853 * furnished to do so, subject to the following conditions:
16854 *
16855 * The above copyright notice and this permission notice shall be included in
16856 * all copies or substantial portions of the Software.
16857 *
16858 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16859 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16860 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16861 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16862 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16863 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16864 * THE SOFTWARE.
16865 */
16866var powerbi;
16867(function (powerbi) {
16868 var StringExtensions = jsCommon.StringExtensions;
16869 var FieldExprPattern = powerbi.data.FieldExprPattern;
16870 var ScriptResultUtil;
16871 (function (ScriptResultUtil) {
16872 function findScriptResult(dataViewMappings) {
16873 if (dataViewMappings && dataViewMappings.length === 1) {
16874 return dataViewMappings[0].scriptResult;
16875 }
16876 return undefined;
16877 }
16878 ScriptResultUtil.findScriptResult = findScriptResult;
16879 function extractScriptResult(dataViewMappings) {
16880 var scriptResult = findScriptResult(dataViewMappings);
16881 if (scriptResult) {
16882 var objects = dataViewMappings[0].metadata.objects;
16883 var source = powerbi.DataViewObjects.getValue(objects, scriptResult.script.source);
16884 var provider = powerbi.DataViewObjects.getValue(objects, scriptResult.script.provider);
16885 return {
16886 source: source,
16887 provider: provider
16888 };
16889 }
16890 return undefined;
16891 }
16892 ScriptResultUtil.extractScriptResult = extractScriptResult;
16893 function extractScriptResultFromVisualConfig(dataViewMappings, objects) {
16894 var scriptResult = findScriptResult(dataViewMappings);
16895 if (scriptResult && objects) {
16896 var scriptSource = powerbi.data.DataViewObjectDefinitions.getValue(objects, scriptResult.script.source, null);
16897 var provider = powerbi.data.DataViewObjectDefinitions.getValue(objects, scriptResult.script.provider, null);
16898 return {
16899 source: scriptSource ? scriptSource.value : null,
16900 provider: provider ? provider.value : null
16901 };
16902 }
16903 return undefined;
16904 }
16905 ScriptResultUtil.extractScriptResultFromVisualConfig = extractScriptResultFromVisualConfig;
16906 function getScriptInput(projections, selects, schema) {
16907 var scriptInput = {
16908 VariableName: "dataset",
16909 Columns: []
16910 };
16911 // Go over all the projections, and create an input column according to the order
16912 // of the projections (including duplicate expressions)
16913 if (projections && selects && !_.isEmpty(selects)) {
16914 var scriptInputColumnNames = [];
16915 var scriptInputColumns = [];
16916 for (var role in projections) {
16917 for (var _i = 0, _a = projections[role].all(); _i < _a.length; _i++) {
16918 var projection = _a[_i];
16919 var select = selects.withName(projection.queryRef);
16920 if (select) {
16921 var scriptInputColumn = {
16922 QueryName: select.name,
16923 Name: FieldExprPattern.visit(select.expr, new ScriptInputColumnNameVisitor(schema))
16924 };
16925 scriptInputColumns.push(scriptInputColumn);
16926 scriptInputColumnNames.push(scriptInputColumn.Name);
16927 }
16928 }
16929 }
16930 // Make sure the names of the columns are unique
16931 scriptInputColumnNames = StringExtensions.ensureUniqueNames(scriptInputColumnNames);
16932 // Update the names of the columns
16933 for (var i = 0; i < scriptInputColumnNames.length; i++) {
16934 var scriptInputColumn = scriptInputColumns[i];
16935 scriptInputColumn.Name = scriptInputColumnNames[i];
16936 }
16937 scriptInput.Columns = scriptInputColumns;
16938 }
16939 return scriptInput;
16940 }
16941 ScriptResultUtil.getScriptInput = getScriptInput;
16942 var ScriptInputColumnNameVisitor = (function () {
16943 function ScriptInputColumnNameVisitor(federatedSchema) {
16944 this.federatedSchema = federatedSchema;
16945 }
16946 ScriptInputColumnNameVisitor.prototype.visitColumn = function (column) {
16947 return ScriptInputColumnNameVisitor.getNameForProperty(column, this.federatedSchema);
16948 };
16949 ScriptInputColumnNameVisitor.prototype.visitColumnAggr = function (columnAggr) {
16950 return ScriptInputColumnNameVisitor.getNameForProperty(columnAggr, this.federatedSchema);
16951 };
16952 ScriptInputColumnNameVisitor.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
16953 return ScriptInputColumnNameVisitor.getVariationLevelName(columnHierarchyLevelVariation, this.federatedSchema);
16954 };
16955 ScriptInputColumnNameVisitor.prototype.visitEntity = function (entity) {
16956 return entity.entity;
16957 };
16958 ScriptInputColumnNameVisitor.prototype.visitEntityAggr = function (entityAggr) {
16959 return entityAggr.entity;
16960 };
16961 ScriptInputColumnNameVisitor.prototype.visitHierarchy = function (hierarchy) {
16962 return ScriptInputColumnNameVisitor.getNameForHierarchy(hierarchy, this.federatedSchema);
16963 };
16964 ScriptInputColumnNameVisitor.prototype.visitHierarchyLevel = function (hierarchyLevel) {
16965 /*Hierarchy levels are not supported yet*/
16966 return;
16967 };
16968 ScriptInputColumnNameVisitor.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
16969 return ScriptInputColumnNameVisitor.getNameForProperty(hierarchyLevelAggr, this.federatedSchema);
16970 };
16971 ScriptInputColumnNameVisitor.prototype.visitMeasure = function (measure) {
16972 return ScriptInputColumnNameVisitor.getNameForProperty(measure, this.federatedSchema);
16973 };
16974 ScriptInputColumnNameVisitor.prototype.visitSelectRef = function (selectRef) {
16975 return FieldExprPattern.visit(selectRef, this);
16976 };
16977 ScriptInputColumnNameVisitor.prototype.visitPercentile = function (percentile) {
16978 return FieldExprPattern.visit(percentile.arg, this);
16979 };
16980 ScriptInputColumnNameVisitor.prototype.visitPercentOfGrandTotal = function (percentOfGrandTotal) {
16981 return FieldExprPattern.visit(percentOfGrandTotal.baseExpr, this);
16982 };
16983 ScriptInputColumnNameVisitor.getNameForHierarchy = function (pattern, federatedScheam) {
16984 debug.assertValue(pattern, 'pattern');
16985 var schema = federatedScheam.schema(pattern.schema), hierarchy = schema.findHierarchy(pattern.entity, pattern.name);
16986 if (hierarchy)
16987 return hierarchy.name;
16988 };
16989 ScriptInputColumnNameVisitor.getNameForProperty = function (pattern, federatedSchema) {
16990 debug.assertValue(pattern, 'pattern');
16991 var schema = federatedSchema.schema(pattern.schema), property = schema.findProperty(pattern.entity, pattern.name);
16992 if (property)
16993 return property.name;
16994 };
16995 ScriptInputColumnNameVisitor.getVariationLevelName = function (pattern, federatedSchema) {
16996 debug.assertValue(pattern, 'pattern');
16997 var source = pattern.source;
16998 var prop = federatedSchema.schema(source.schema).findProperty(source.entity, source.name);
16999 if (!prop)
17000 return;
17001 var variations = prop.column.variations;
17002 for (var _i = 0, variations_1 = variations; _i < variations_1.length; _i++) {
17003 var variation = variations_1[_i];
17004 if (variation.name === pattern.variationName)
17005 for (var _a = 0, _b = variation.defaultHierarchy.levels; _a < _b.length; _a++) {
17006 var level = _b[_a];
17007 if (level.name === pattern.level.level)
17008 return level.column.name;
17009 }
17010 }
17011 };
17012 return ScriptInputColumnNameVisitor;
17013 }());
17014 })(ScriptResultUtil = powerbi.ScriptResultUtil || (powerbi.ScriptResultUtil = {}));
17015})(powerbi || (powerbi = {}));
17016/*
17017 * Power BI Visualizations
17018 *
17019 * Copyright (c) Microsoft Corporation
17020 * All rights reserved.
17021 * MIT License
17022 *
17023 * Permission is hereby granted, free of charge, to any person obtaining a copy
17024 * of this software and associated documentation files (the ""Software""), to deal
17025 * in the Software without restriction, including without limitation the rights
17026 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17027 * copies of the Software, and to permit persons to whom the Software is
17028 * furnished to do so, subject to the following conditions:
17029 *
17030 * The above copyright notice and this permission notice shall be included in
17031 * all copies or substantial portions of the Software.
17032 *
17033 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17034 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17035 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17036 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17037 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17038 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17039 * THE SOFTWARE.
17040 */
17041var powerbi;
17042(function (powerbi) {
17043 var data;
17044 (function (data) {
17045 var segmentation;
17046 (function (segmentation) {
17047 var DataViewMerger;
17048 (function (DataViewMerger) {
17049 function mergeDataViews(source, segment) {
17050 if (!powerbi.DataViewAnalysis.isMetadataEquivalent(source.metadata, segment.metadata)) {
17051 debug.assertFail("Cannot merge data views with different metadata columns");
17052 }
17053 // The last segment is complete. We mark the source as complete.
17054 if (!segment.metadata.segment)
17055 delete source.metadata.segment;
17056 if (source.table && segment.table)
17057 mergeTables(source.table, segment.table);
17058 if (source.categorical && segment.categorical)
17059 mergeCategorical(source.categorical, segment.categorical);
17060 // Tree cannot support subtotals hence we can get into situations
17061 // where a node has no children in one segment and more than 1 child
17062 // in another segment.
17063 if (source.tree && segment.tree)
17064 mergeTreeNodes(source.tree.root, segment.tree.root, true /*allowDifferentStructure*/);
17065 if (source.matrix && segment.matrix)
17066 mergeTreeNodes(source.matrix.rows.root, segment.matrix.rows.root, false /*allowDifferentStructure*/);
17067 }
17068 DataViewMerger.mergeDataViews = mergeDataViews;
17069 /** Note: Public for testability */
17070 function mergeTables(source, segment) {
17071 debug.assertValue(source, 'source');
17072 debug.assertValue(segment, 'segment');
17073 if (_.isEmpty(segment.rows))
17074 return;
17075 var mergeIndex = segment.lastMergeIndex + 1;
17076 merge(source.rows, segment.rows, mergeIndex);
17077 debug.assert(!source.identity === !segment.identity, 'The existence of identity in the new segment is different than the source');
17078 if (segment.identity)
17079 merge(source.identity, segment.identity, mergeIndex);
17080 }
17081 DataViewMerger.mergeTables = mergeTables;
17082 /**
17083 * Merge categories values and identities
17084 *
17085 * Note: Public for testability
17086 */
17087 function mergeCategorical(source, segment) {
17088 debug.assertValue(source, 'source');
17089 debug.assertValue(segment, 'segment');
17090 // Merge categories values and identities
17091 if (source.categories && segment.categories) {
17092 var segmentCategoriesLength = segment.categories.length;
17093 debug.assert(source.categories.length === segmentCategoriesLength, "Source and segment categories have different lengths.");
17094 for (var categoryIndex = 0; categoryIndex < segmentCategoriesLength; categoryIndex++) {
17095 var segmentCategory = segment.categories[categoryIndex];
17096 var sourceCategory = source.categories[categoryIndex];
17097 debug.assert(powerbi.DataViewAnalysis.areMetadataColumnsEquivalent(sourceCategory.source, segmentCategory.source), "Source and segment category have different sources.");
17098 debug.assert(_.isUndefined(sourceCategory.values) ? _.isUndefined(sourceCategory.identity) : true, 'Source category is missing values but has identities.');
17099 var mergeIndex = segment.lastMergeIndex + 1;
17100 if (segmentCategory.values) {
17101 merge(sourceCategory.values, segmentCategory.values, mergeIndex);
17102 }
17103 if (segmentCategory.identity) {
17104 merge(sourceCategory.identity, segmentCategory.identity, mergeIndex);
17105 }
17106 }
17107 }
17108 // Merge values for each value column
17109 if (source.values && segment.values) {
17110 var segmentValuesLength = segment.values.length;
17111 debug.assert(source.values.length === segmentValuesLength, "Source and segment values have different lengths.");
17112 for (var valueIndex = 0; valueIndex < segmentValuesLength; valueIndex++) {
17113 var segmentValue = segment.values[valueIndex];
17114 var sourceValue = source.values[valueIndex];
17115 debug.assert(powerbi.DataViewAnalysis.areMetadataColumnsEquivalent(sourceValue.source, segmentValue.source), "Source and segment value have different sources.");
17116 if (!sourceValue.values && segmentValue.values) {
17117 sourceValue.values = [];
17118 }
17119 var mergeIndex = segment.lastMergeIndex + 1;
17120 if (segmentValue.values) {
17121 merge(sourceValue.values, segmentValue.values, mergeIndex);
17122 }
17123 if (segmentValue.highlights) {
17124 merge(sourceValue.highlights, segmentValue.highlights, mergeIndex);
17125 }
17126 }
17127 }
17128 }
17129 DataViewMerger.mergeCategorical = mergeCategorical;
17130 /**
17131 * Merges the segment array starting at the specified index into the source array
17132 * and returns the segment slice that wasn't merged.
17133 * The segment array is spliced up to specified index in the process.
17134 */
17135 function merge(source, segment, index) {
17136 if (index >= segment.length)
17137 return segment;
17138 var result = [];
17139 if (index !== undefined)
17140 result = segment.splice(0, index);
17141 Array.prototype.push.apply(source, segment);
17142 return result;
17143 }
17144 /** Note: Public for testability */
17145 function mergeTreeNodes(sourceRoot, segmentRoot, allowDifferentStructure) {
17146 debug.assertValue(sourceRoot, 'sourceRoot');
17147 debug.assertValue(segmentRoot, 'segmentRoot');
17148 if (!segmentRoot.children || segmentRoot.children.length === 0)
17149 return;
17150 if (allowDifferentStructure && (!sourceRoot.children || sourceRoot.children.length === 0)) {
17151 sourceRoot.children = segmentRoot.children;
17152 return;
17153 }
17154 debug.assert(sourceRoot.children && sourceRoot.children.length >= 0, "Source tree has different structure than segment.");
17155 var firstAppendIndex = findFirstAppendIndex(segmentRoot.children);
17156 var lastSourceChild = sourceRoot.children[sourceRoot.children.length - 1];
17157 var mergedChildren = merge(sourceRoot.children, segmentRoot.children, firstAppendIndex);
17158 if (mergedChildren.length > 0)
17159 mergeTreeNodes(lastSourceChild, mergedChildren[mergedChildren.length - 1], allowDifferentStructure);
17160 }
17161 DataViewMerger.mergeTreeNodes = mergeTreeNodes;
17162 function findFirstAppendIndex(children) {
17163 if (children.length === 0)
17164 return 0;
17165 var i = 0;
17166 for (; i < children.length; i++) {
17167 var childSegment = children[i];
17168 if (!childSegment.isMerge)
17169 break;
17170 }
17171 return i;
17172 }
17173 })(DataViewMerger = segmentation.DataViewMerger || (segmentation.DataViewMerger = {}));
17174 })(segmentation = data.segmentation || (data.segmentation = {}));
17175 })(data = powerbi.data || (powerbi.data = {}));
17176})(powerbi || (powerbi = {}));
17177/*
17178 * Power BI Visualizations
17179 *
17180 * Copyright (c) Microsoft Corporation
17181 * All rights reserved.
17182 * MIT License
17183 *
17184 * Permission is hereby granted, free of charge, to any person obtaining a copy
17185 * of this software and associated documentation files (the ""Software""), to deal
17186 * in the Software without restriction, including without limitation the rights
17187 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17188 * copies of the Software, and to permit persons to whom the Software is
17189 * furnished to do so, subject to the following conditions:
17190 *
17191 * The above copyright notice and this permission notice shall be included in
17192 * all copies or substantial portions of the Software.
17193 *
17194 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17195 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17196 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17197 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17198 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17199 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17200 * THE SOFTWARE.
17201 */
17202var powerbi;
17203(function (powerbi) {
17204 var data;
17205 (function (data) {
17206 var ArrayExtensions = jsCommon.ArrayExtensions;
17207 /** Rewrites an expression tree, including all descendant nodes. */
17208 var SQExprRewriter = (function () {
17209 function SQExprRewriter() {
17210 }
17211 SQExprRewriter.prototype.visitColumnRef = function (expr) {
17212 var origArg = expr.source, rewrittenArg = origArg.accept(this);
17213 if (origArg === rewrittenArg)
17214 return expr;
17215 return new data.SQColumnRefExpr(rewrittenArg, expr.ref);
17216 };
17217 SQExprRewriter.prototype.visitMeasureRef = function (expr) {
17218 var origArg = expr.source, rewrittenArg = origArg.accept(this);
17219 if (origArg === rewrittenArg)
17220 return expr;
17221 return new data.SQMeasureRefExpr(rewrittenArg, expr.ref);
17222 };
17223 SQExprRewriter.prototype.visitAggr = function (expr) {
17224 var origArg = expr.arg, rewrittenArg = origArg.accept(this);
17225 if (origArg === rewrittenArg)
17226 return expr;
17227 return new data.SQAggregationExpr(rewrittenArg, expr.func);
17228 };
17229 SQExprRewriter.prototype.visitSelectRef = function (expr) {
17230 return expr;
17231 };
17232 SQExprRewriter.prototype.visitPercentile = function (expr) {
17233 var origArg = expr.arg, rewrittenArg = origArg.accept(this);
17234 if (origArg === rewrittenArg)
17235 return expr;
17236 return new data.SQPercentileExpr(rewrittenArg, expr.k, expr.exclusive);
17237 };
17238 SQExprRewriter.prototype.visitHierarchy = function (expr) {
17239 var origArg = expr.arg, rewrittenArg = origArg.accept(this);
17240 if (origArg === rewrittenArg)
17241 return expr;
17242 return new data.SQHierarchyExpr(rewrittenArg, expr.hierarchy);
17243 };
17244 SQExprRewriter.prototype.visitHierarchyLevel = function (expr) {
17245 var origArg = expr.arg, rewrittenArg = origArg.accept(this);
17246 if (origArg === rewrittenArg)
17247 return expr;
17248 return new data.SQHierarchyLevelExpr(rewrittenArg, expr.level);
17249 };
17250 SQExprRewriter.prototype.visitPropertyVariationSource = function (expr) {
17251 var origArg = expr.arg, rewrittenArg = origArg.accept(this);
17252 if (origArg === rewrittenArg)
17253 return expr;
17254 return new data.SQPropertyVariationSourceExpr(rewrittenArg, expr.name, expr.property);
17255 };
17256 SQExprRewriter.prototype.visitEntity = function (expr) {
17257 return expr;
17258 };
17259 SQExprRewriter.prototype.visitAnd = function (orig) {
17260 var origLeft = orig.left, rewrittenLeft = origLeft.accept(this), origRight = orig.right, rewrittenRight = origRight.accept(this);
17261 if (origLeft === rewrittenLeft && origRight === rewrittenRight)
17262 return orig;
17263 return new data.SQAndExpr(rewrittenLeft, rewrittenRight);
17264 };
17265 SQExprRewriter.prototype.visitBetween = function (orig) {
17266 var origArg = orig.arg, rewrittenArg = origArg.accept(this), origLower = orig.lower, rewrittenLower = origLower.accept(this), origUpper = orig.upper, rewrittenUpper = origUpper.accept(this);
17267 if (origArg === rewrittenArg && origLower === rewrittenLower && origUpper === rewrittenUpper)
17268 return orig;
17269 return new data.SQBetweenExpr(rewrittenArg, rewrittenLower, rewrittenUpper);
17270 };
17271 SQExprRewriter.prototype.visitIn = function (orig) {
17272 var origArgs = orig.args, rewrittenArgs = this.rewriteAll(origArgs), origValues = orig.values, rewrittenValues;
17273 for (var i = 0, len = origValues.length; i < len; i++) {
17274 var origValueTuple = origValues[i], rewrittenValueTuple = this.rewriteAll(origValueTuple);
17275 if (origValueTuple !== rewrittenValueTuple && !rewrittenValues)
17276 rewrittenValues = ArrayExtensions.take(origValues, i);
17277 if (rewrittenValues)
17278 rewrittenValues.push(rewrittenValueTuple);
17279 }
17280 if (origArgs === rewrittenArgs && !rewrittenValues)
17281 return orig;
17282 return new data.SQInExpr(rewrittenArgs, rewrittenValues || origValues);
17283 };
17284 SQExprRewriter.prototype.rewriteAll = function (origExprs) {
17285 debug.assertValue(origExprs, 'origExprs');
17286 var rewrittenResult;
17287 for (var i = 0, len = origExprs.length; i < len; i++) {
17288 var origExpr = origExprs[i], rewrittenExpr = origExpr.accept(this);
17289 if (origExpr !== rewrittenExpr && !rewrittenResult)
17290 rewrittenResult = ArrayExtensions.take(origExprs, i);
17291 if (rewrittenResult)
17292 rewrittenResult.push(rewrittenExpr);
17293 }
17294 return rewrittenResult || origExprs;
17295 };
17296 SQExprRewriter.prototype.visitOr = function (orig) {
17297 var origLeft = orig.left, rewrittenLeft = origLeft.accept(this), origRight = orig.right, rewrittenRight = origRight.accept(this);
17298 if (origLeft === rewrittenLeft && origRight === rewrittenRight)
17299 return orig;
17300 return new data.SQOrExpr(rewrittenLeft, rewrittenRight);
17301 };
17302 SQExprRewriter.prototype.visitCompare = function (orig) {
17303 var origLeft = orig.left, rewrittenLeft = origLeft.accept(this), origRight = orig.right, rewrittenRight = origRight.accept(this);
17304 if (origLeft === rewrittenLeft && origRight === rewrittenRight)
17305 return orig;
17306 return new data.SQCompareExpr(orig.comparison, rewrittenLeft, rewrittenRight);
17307 };
17308 SQExprRewriter.prototype.visitContains = function (orig) {
17309 var origLeft = orig.left, rewrittenLeft = origLeft.accept(this), origRight = orig.right, rewrittenRight = origRight.accept(this);
17310 if (origLeft === rewrittenLeft && origRight === rewrittenRight)
17311 return orig;
17312 return new data.SQContainsExpr(rewrittenLeft, rewrittenRight);
17313 };
17314 SQExprRewriter.prototype.visitExists = function (orig) {
17315 var origArg = orig.arg, rewrittenArg = origArg.accept(this);
17316 if (origArg === rewrittenArg)
17317 return orig;
17318 return new data.SQExistsExpr(rewrittenArg);
17319 };
17320 SQExprRewriter.prototype.visitNot = function (orig) {
17321 var origArg = orig.arg, rewrittenArg = origArg.accept(this);
17322 if (origArg === rewrittenArg)
17323 return orig;
17324 return new data.SQNotExpr(rewrittenArg);
17325 };
17326 SQExprRewriter.prototype.visitStartsWith = function (orig) {
17327 var origLeft = orig.left, rewrittenLeft = origLeft.accept(this), origRight = orig.right, rewrittenRight = origRight.accept(this);
17328 if (origLeft === rewrittenLeft && origRight === rewrittenRight)
17329 return orig;
17330 return new data.SQStartsWithExpr(rewrittenLeft, rewrittenRight);
17331 };
17332 SQExprRewriter.prototype.visitConstant = function (expr) {
17333 return expr;
17334 };
17335 SQExprRewriter.prototype.visitDateSpan = function (orig) {
17336 var origArg = orig.arg, rewrittenArg = origArg.accept(this);
17337 if (origArg === rewrittenArg)
17338 return orig;
17339 return new data.SQDateSpanExpr(orig.unit, rewrittenArg);
17340 };
17341 SQExprRewriter.prototype.visitDateAdd = function (orig) {
17342 var origArg = orig.arg, rewrittenArg = origArg.accept(this);
17343 if (origArg === rewrittenArg)
17344 return orig;
17345 return new data.SQDateAddExpr(orig.unit, orig.amount, rewrittenArg);
17346 };
17347 SQExprRewriter.prototype.visitNow = function (orig) {
17348 return orig;
17349 };
17350 SQExprRewriter.prototype.visitDefaultValue = function (orig) {
17351 return orig;
17352 };
17353 SQExprRewriter.prototype.visitAnyValue = function (orig) {
17354 return orig;
17355 };
17356 SQExprRewriter.prototype.visitArithmetic = function (orig) {
17357 var origLeft = orig.left, rewrittenLeft = origLeft.accept(this), origRight = orig.right, rewrittenRight = origRight.accept(this);
17358 if (origLeft === rewrittenLeft && origRight === rewrittenRight)
17359 return orig;
17360 return new data.SQArithmeticExpr(rewrittenLeft, rewrittenRight, orig.operator);
17361 };
17362 SQExprRewriter.prototype.visitScopedEval = function (orig) {
17363 var origExpression = orig.expression, rewrittenExpression = origExpression.accept(this), origScope = orig.scope, rewrittenScope = this.rewriteAll(origScope);
17364 if (origExpression === rewrittenExpression && origScope === rewrittenScope)
17365 return orig;
17366 return new data.SQScopedEvalExpr(rewrittenExpression, rewrittenScope);
17367 };
17368 SQExprRewriter.prototype.visitFillRule = function (orig) {
17369 var origInput = orig.input, rewrittenInput = origInput.accept(this);
17370 var origRule = orig.rule;
17371 var origGradient2 = origRule.linearGradient2, rewrittenGradient2 = origGradient2;
17372 if (origGradient2) {
17373 rewrittenGradient2 = this.visitLinearGradient2(origGradient2);
17374 }
17375 var origGradient3 = origRule.linearGradient3, rewrittenGradient3 = origGradient3;
17376 if (origGradient3) {
17377 rewrittenGradient3 = this.visitLinearGradient3(origGradient3);
17378 }
17379 if (origInput !== rewrittenInput ||
17380 origGradient2 !== rewrittenGradient2 ||
17381 origGradient3 !== rewrittenGradient3) {
17382 var rewrittenRule = {};
17383 if (rewrittenGradient2)
17384 rewrittenRule.linearGradient2 = rewrittenGradient2;
17385 if (rewrittenGradient3)
17386 rewrittenRule.linearGradient3 = rewrittenGradient3;
17387 return new data.SQFillRuleExpr(rewrittenInput, rewrittenRule);
17388 }
17389 return orig;
17390 };
17391 SQExprRewriter.prototype.visitLinearGradient2 = function (origGradient2) {
17392 debug.assertValue(origGradient2, 'origGradient2');
17393 var origMin = origGradient2.min, rewrittenMin = this.visitFillRuleStop(origMin), origMax = origGradient2.max, rewrittenMax = this.visitFillRuleStop(origMax);
17394 if (origMin !== rewrittenMin || origMax !== rewrittenMax) {
17395 return {
17396 min: rewrittenMin,
17397 max: rewrittenMax,
17398 };
17399 }
17400 return origGradient2;
17401 };
17402 SQExprRewriter.prototype.visitLinearGradient3 = function (origGradient3) {
17403 debug.assertValue(origGradient3, 'origGradient3');
17404 var origMin = origGradient3.min, rewrittenMin = this.visitFillRuleStop(origMin), origMid = origGradient3.mid, rewrittenMid = this.visitFillRuleStop(origMid), origMax = origGradient3.max, rewrittenMax = this.visitFillRuleStop(origMax);
17405 if (origMin !== rewrittenMin || origMid !== rewrittenMid || origMax !== rewrittenMax) {
17406 return {
17407 min: rewrittenMin,
17408 mid: rewrittenMid,
17409 max: rewrittenMax,
17410 };
17411 }
17412 return origGradient3;
17413 };
17414 SQExprRewriter.prototype.visitFillRuleStop = function (stop) {
17415 debug.assertValue(stop, 'stop');
17416 var origColor = stop.color, rewrittenColor = stop.color.accept(this);
17417 var origValue = stop.value, rewrittenValue = origValue;
17418 if (origValue)
17419 rewrittenValue = origValue.accept(this);
17420 if (origColor !== rewrittenColor || origValue !== rewrittenValue) {
17421 var rewrittenStop = {
17422 color: rewrittenColor
17423 };
17424 if (rewrittenValue)
17425 rewrittenStop.value = rewrittenValue;
17426 return rewrittenStop;
17427 }
17428 return stop;
17429 };
17430 SQExprRewriter.prototype.visitResourcePackageItem = function (orig) {
17431 return orig;
17432 };
17433 return SQExprRewriter;
17434 }());
17435 data.SQExprRewriter = SQExprRewriter;
17436 })(data = powerbi.data || (powerbi.data = {}));
17437})(powerbi || (powerbi = {}));
17438/*
17439 * Power BI Visualizations
17440 *
17441 * Copyright (c) Microsoft Corporation
17442 * All rights reserved.
17443 * MIT License
17444 *
17445 * Permission is hereby granted, free of charge, to any person obtaining a copy
17446 * of this software and associated documentation files (the ""Software""), to deal
17447 * in the Software without restriction, including without limitation the rights
17448 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17449 * copies of the Software, and to permit persons to whom the Software is
17450 * furnished to do so, subject to the following conditions:
17451 *
17452 * The above copyright notice and this permission notice shall be included in
17453 * all copies or substantial portions of the Software.
17454 *
17455 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17456 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17457 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17458 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17459 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17460 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17461 * THE SOFTWARE.
17462 */
17463var powerbi;
17464(function (powerbi) {
17465 var data;
17466 (function (data) {
17467 /** Responsible for writing equality comparisons against a field to an SQInExpr. */
17468 var EqualsToInRewriter;
17469 (function (EqualsToInRewriter) {
17470 function run(expr) {
17471 debug.assertValue(expr, 'expr');
17472 return expr.accept(new Rewriter());
17473 }
17474 EqualsToInRewriter.run = run;
17475 var Rewriter = (function (_super) {
17476 __extends(Rewriter, _super);
17477 function Rewriter() {
17478 _super.call(this);
17479 }
17480 Rewriter.prototype.visitCompare = function (expr) {
17481 if (expr.comparison !== data.QueryComparisonKind.Equal)
17482 return this.visitUnsupported(expr);
17483 if (!this.isSupported(expr.left) || !this.isSupported(expr.right))
17484 return this.visitUnsupported(expr);
17485 var leftIsComparand = this.isComparand(expr.left);
17486 var rightIsComparand = this.isComparand(expr.right);
17487 if (leftIsComparand === rightIsComparand)
17488 return this.visitUnsupported(expr);
17489 var operand = leftIsComparand
17490 ? expr.left
17491 : expr.right;
17492 var value = leftIsComparand
17493 ? expr.right
17494 : expr.left;
17495 var current = this.current;
17496 if (!current) {
17497 return data.SQExprBuilder.inExpr([operand], [[value]]);
17498 }
17499 current.add(operand, value);
17500 return expr;
17501 };
17502 Rewriter.prototype.visitOr = function (expr) {
17503 if (!this.isSupported(expr.left) || !this.isSupported(expr.right))
17504 return this.visitUnsupported(expr);
17505 var current;
17506 if (!this.current) {
17507 current = this.current = new InBuilder();
17508 }
17509 expr.left.accept(this);
17510 expr.right.accept(this);
17511 if (current) {
17512 this.current = null;
17513 return current.complete() || expr;
17514 }
17515 return expr;
17516 };
17517 Rewriter.prototype.visitAnd = function (expr) {
17518 if (!this.isSupported(expr.left) || !this.isSupported(expr.right))
17519 return this.visitUnsupported(expr);
17520 var current = this.current;
17521 if (current) {
17522 // NOTE: Composite keys are not supported by this algorithm.
17523 current.cancel();
17524 return expr;
17525 }
17526 return _super.prototype.visitAnd.call(this, expr);
17527 };
17528 Rewriter.prototype.visitUnsupported = function (expr) {
17529 var current = this.current;
17530 if (current)
17531 current.cancel();
17532 return expr;
17533 };
17534 Rewriter.prototype.isSupported = function (expr) {
17535 debug.assertValue(expr, 'expr');
17536 return expr instanceof data.SQCompareExpr
17537 || expr instanceof data.SQColumnRefExpr
17538 || expr instanceof data.SQConstantExpr
17539 || expr instanceof data.SQHierarchyLevelExpr
17540 || expr instanceof data.SQOrExpr
17541 || expr instanceof data.SQAndExpr;
17542 };
17543 Rewriter.prototype.isComparand = function (expr) {
17544 return expr instanceof data.SQColumnRefExpr
17545 || expr instanceof data.SQHierarchyLevelExpr;
17546 };
17547 return Rewriter;
17548 }(data.SQExprRewriter));
17549 var InBuilder = (function () {
17550 function InBuilder() {
17551 }
17552 InBuilder.prototype.add = function (operand, value) {
17553 debug.assertValue(operand, 'operand');
17554 debug.assertValue(value, 'value');
17555 if (this.cancelled)
17556 return;
17557 if (this.operand && !data.SQExpr.equals(operand, this.operand)) {
17558 this.cancel();
17559 return;
17560 }
17561 this.operand = operand;
17562 var values = this.values;
17563 if (!values)
17564 values = this.values = [];
17565 values.push(value);
17566 };
17567 InBuilder.prototype.cancel = function () {
17568 this.cancelled = true;
17569 };
17570 InBuilder.prototype.complete = function () {
17571 if (this.cancelled || !this.operand)
17572 return;
17573 return data.SQExprBuilder.inExpr([this.operand], _.map(this.values, function (v) { return [v]; }));
17574 };
17575 return InBuilder;
17576 }());
17577 })(EqualsToInRewriter = data.EqualsToInRewriter || (data.EqualsToInRewriter = {}));
17578 })(data = powerbi.data || (powerbi.data = {}));
17579})(powerbi || (powerbi = {}));
17580/*
17581 * Power BI Visualizations
17582 *
17583 * Copyright (c) Microsoft Corporation
17584 * All rights reserved.
17585 * MIT License
17586 *
17587 * Permission is hereby granted, free of charge, to any person obtaining a copy
17588 * of this software and associated documentation files (the ""Software""), to deal
17589 * in the Software without restriction, including without limitation the rights
17590 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17591 * copies of the Software, and to permit persons to whom the Software is
17592 * furnished to do so, subject to the following conditions:
17593 *
17594 * The above copyright notice and this permission notice shall be included in
17595 * all copies or substantial portions of the Software.
17596 *
17597 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17598 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17599 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17600 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17601 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17602 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17603 * THE SOFTWARE.
17604 */
17605var powerbi;
17606(function (powerbi) {
17607 var data;
17608 (function (data) {
17609 var SQExprConverter;
17610 (function (SQExprConverter) {
17611 function asScopeIdsContainer(filter, fieldSQExprs) {
17612 debug.assertValue(filter, 'filter');
17613 debug.assertValue(fieldSQExprs, 'fieldSQExprs');
17614 debug.assert(fieldSQExprs.length > 0, 'There should be at least 1 field expression.');
17615 var filterItems = filter.conditions();
17616 debug.assert(filterItems.length === 1, 'There should be exactly 1 filter expression.');
17617 var filterItem = filterItems[0];
17618 if (filterItem) {
17619 var visitor = new FilterScopeIdsCollectorVisitor(fieldSQExprs);
17620 if (filterItem.accept(visitor))
17621 return visitor.getResult();
17622 }
17623 }
17624 SQExprConverter.asScopeIdsContainer = asScopeIdsContainer;
17625 /** Gets a comparand value from the given DataViewScopeIdentity. */
17626 function getFirstComparandValue(identity) {
17627 debug.assertValue(identity, 'identity');
17628 var comparandExpr = identity.expr.accept(new FindComparandVisitor());
17629 if (comparandExpr)
17630 return comparandExpr.value;
17631 }
17632 SQExprConverter.getFirstComparandValue = getFirstComparandValue;
17633 })(SQExprConverter = data.SQExprConverter || (data.SQExprConverter = {}));
17634 /** Collect filter values from simple semantic filter that is similar to 'is any of' or 'is not any of', getResult() returns a collection of scopeIds.**/
17635 var FilterScopeIdsCollectorVisitor = (function (_super) {
17636 __extends(FilterScopeIdsCollectorVisitor, _super);
17637 function FilterScopeIdsCollectorVisitor(fieldSQExprs) {
17638 _super.call(this);
17639 this.isRoot = true;
17640 this.isNot = false;
17641 this.keyExprsCount = null;
17642 this.valueExprs = [];
17643 // Need to drop the entitylet before create the scopeIdentity. The ScopeIdentity created on the client is used to
17644 // compare the ScopeIdentity came from the server. But server doesn't have the entity variable concept, so we will
17645 // need to drop it in order to use JsonComparer.
17646 this.fieldExprs = [];
17647 for (var _i = 0, fieldSQExprs_1 = fieldSQExprs; _i < fieldSQExprs_1.length; _i++) {
17648 var field = fieldSQExprs_1[_i];
17649 this.fieldExprs.push(data.SQExprBuilder.removeEntityVariables(field));
17650 }
17651 }
17652 FilterScopeIdsCollectorVisitor.prototype.getResult = function () {
17653 debug.assert(this.fieldExprs.length > 0, 'fieldExprs has at least one fieldExpr');
17654 var valueExprs = this.valueExprs, scopeIds = [];
17655 var valueCount = this.keyExprsCount || 1;
17656 for (var startIndex = 0, endIndex = valueCount, len = valueExprs.length; startIndex < len && endIndex <= len;) {
17657 var values = valueExprs.slice(startIndex, endIndex);
17658 var scopeId = FilterScopeIdsCollectorVisitor.getScopeIdentity(this.fieldExprs, values);
17659 if (!jsCommon.ArrayExtensions.isInArray(scopeIds, scopeId, powerbi.DataViewScopeIdentity.equals))
17660 scopeIds.push(scopeId);
17661 startIndex += valueCount;
17662 endIndex += valueCount;
17663 }
17664 return {
17665 isNot: this.isNot,
17666 scopeIds: scopeIds,
17667 };
17668 };
17669 FilterScopeIdsCollectorVisitor.getScopeIdentity = function (fieldExprs, valueExprs) {
17670 debug.assert(valueExprs.length > 0, 'valueExprs has at least one valueExpr');
17671 debug.assert(valueExprs.length === fieldExprs.length, 'fieldExpr and valueExpr count should match');
17672 var compoundSQExpr;
17673 for (var i = 0, len = fieldExprs.length; i < len; i++) {
17674 var equalsExpr = data.SQExprBuilder.equal(fieldExprs[i], valueExprs[i]);
17675 if (!compoundSQExpr)
17676 compoundSQExpr = equalsExpr;
17677 else
17678 compoundSQExpr = data.SQExprBuilder.and(compoundSQExpr, equalsExpr);
17679 }
17680 return data.createDataViewScopeIdentity(compoundSQExpr);
17681 };
17682 FilterScopeIdsCollectorVisitor.prototype.visitOr = function (expr) {
17683 if (this.keyExprsCount !== null)
17684 return this.unsupportedSQExpr();
17685 this.isRoot = false;
17686 return expr.left.accept(this) && expr.right.accept(this);
17687 };
17688 FilterScopeIdsCollectorVisitor.prototype.visitNot = function (expr) {
17689 if (!this.isRoot)
17690 return this.unsupportedSQExpr();
17691 this.isNot = true;
17692 return expr.arg.accept(this);
17693 };
17694 FilterScopeIdsCollectorVisitor.prototype.visitConstant = function (expr) {
17695 if (this.isRoot && expr.type.primitiveType === powerbi.PrimitiveType.Null)
17696 return this.unsupportedSQExpr();
17697 this.valueExprs.push(expr);
17698 return true;
17699 };
17700 FilterScopeIdsCollectorVisitor.prototype.visitCompare = function (expr) {
17701 if (this.keyExprsCount !== null)
17702 return this.unsupportedSQExpr();
17703 this.isRoot = false;
17704 if (expr.comparison !== data.QueryComparisonKind.Equal)
17705 return this.unsupportedSQExpr();
17706 return expr.left.accept(this) && expr.right.accept(this);
17707 };
17708 FilterScopeIdsCollectorVisitor.prototype.visitIn = function (expr) {
17709 this.keyExprsCount = 0;
17710 var result;
17711 this.isRoot = false;
17712 for (var _i = 0, _a = expr.args; _i < _a.length; _i++) {
17713 var arg = _a[_i];
17714 result = arg.accept(this);
17715 if (!result)
17716 return this.unsupportedSQExpr();
17717 this.keyExprsCount++;
17718 }
17719 if (this.keyExprsCount !== this.fieldExprs.length)
17720 return this.unsupportedSQExpr();
17721 var values = expr.values;
17722 for (var _b = 0, values_1 = values; _b < values_1.length; _b++) {
17723 var valueTuple = values_1[_b];
17724 var jlen = valueTuple.length;
17725 debug.assert(jlen === this.keyExprsCount, "keys count and values count should match");
17726 for (var _c = 0, valueTuple_1 = valueTuple; _c < valueTuple_1.length; _c++) {
17727 var value = valueTuple_1[_c];
17728 result = value.accept(this);
17729 if (!result)
17730 return this.unsupportedSQExpr();
17731 }
17732 }
17733 return result;
17734 };
17735 FilterScopeIdsCollectorVisitor.prototype.visitColumnRef = function (expr) {
17736 if (this.isRoot)
17737 return this.unsupportedSQExpr();
17738 var fixedExpr = data.SQExprBuilder.removeEntityVariables(expr);
17739 if (this.keyExprsCount !== null)
17740 return data.SQExpr.equals(this.fieldExprs[this.keyExprsCount], fixedExpr);
17741 return data.SQExpr.equals(this.fieldExprs[0], fixedExpr);
17742 };
17743 FilterScopeIdsCollectorVisitor.prototype.visitDefaultValue = function (expr) {
17744 if (this.isRoot || this.keyExprsCount !== null)
17745 return this.unsupportedSQExpr();
17746 this.valueExprs.push(expr);
17747 return true;
17748 };
17749 FilterScopeIdsCollectorVisitor.prototype.visitAnyValue = function (expr) {
17750 if (this.isRoot || this.keyExprsCount !== null)
17751 return this.unsupportedSQExpr();
17752 this.valueExprs.push(expr);
17753 return true;
17754 };
17755 FilterScopeIdsCollectorVisitor.prototype.visitDefault = function (expr) {
17756 return this.unsupportedSQExpr();
17757 };
17758 FilterScopeIdsCollectorVisitor.prototype.unsupportedSQExpr = function () {
17759 return false;
17760 };
17761 return FilterScopeIdsCollectorVisitor;
17762 }(data.DefaultSQExprVisitor));
17763 var FindComparandVisitor = (function (_super) {
17764 __extends(FindComparandVisitor, _super);
17765 function FindComparandVisitor() {
17766 _super.apply(this, arguments);
17767 }
17768 FindComparandVisitor.prototype.visitAnd = function (expr) {
17769 return expr.left.accept(this) || expr.right.accept(this);
17770 };
17771 FindComparandVisitor.prototype.visitCompare = function (expr) {
17772 if (expr.comparison === data.QueryComparisonKind.Equal) {
17773 if (expr.right instanceof data.SQConstantExpr)
17774 return expr.right;
17775 if (expr.left instanceof data.SQConstantExpr)
17776 return expr.left;
17777 }
17778 };
17779 return FindComparandVisitor;
17780 }(data.DefaultSQExprVisitor));
17781 })(data = powerbi.data || (powerbi.data = {}));
17782})(powerbi || (powerbi = {}));
17783/*
17784 * Power BI Visualizations
17785 *
17786 * Copyright (c) Microsoft Corporation
17787 * All rights reserved.
17788 * MIT License
17789 *
17790 * Permission is hereby granted, free of charge, to any person obtaining a copy
17791 * of this software and associated documentation files (the ""Software""), to deal
17792 * in the Software without restriction, including without limitation the rights
17793 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17794 * copies of the Software, and to permit persons to whom the Software is
17795 * furnished to do so, subject to the following conditions:
17796 *
17797 * The above copyright notice and this permission notice shall be included in
17798 * all copies or substantial portions of the Software.
17799 *
17800 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17801 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17802 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17803 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17804 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17805 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17806 * THE SOFTWARE.
17807 */
17808var powerbi;
17809(function (powerbi) {
17810 var data;
17811 (function (data) {
17812 var ArrayExtensions = jsCommon.ArrayExtensions;
17813 /** Recognizes DataViewScopeIdentity expression trees to extract comparison keys. */
17814 var ScopeIdentityExtractor;
17815 (function (ScopeIdentityExtractor) {
17816 function getKeys(expr) {
17817 var extractor = new ScopeIdExtractorImpl();
17818 expr.accept(extractor);
17819 if (extractor.malformed)
17820 return null;
17821 return ArrayExtensions.emptyToNull(extractor.keys);
17822 }
17823 ScopeIdentityExtractor.getKeys = getKeys;
17824 function getInExpr(expr) {
17825 var extractor = new ScopeIdExtractorImpl();
17826 expr.accept(extractor);
17827 if (extractor.malformed)
17828 return;
17829 var keys = ArrayExtensions.emptyToNull(extractor.keys);
17830 var keyValues = ArrayExtensions.emptyToNull(extractor.values);
17831 if (keys && keyValues)
17832 return data.SQExprBuilder.inExpr(keys, [keyValues]);
17833 }
17834 ScopeIdentityExtractor.getInExpr = getInExpr;
17835 /**
17836 * Recognizes expressions of the form:
17837 * 1) Equals(ColRef, Constant)
17838 * 2) And(Equals(ColRef1, Constant1), Equals(ColRef2, Constant2))
17839 * or And(And(Equals(ColRef1, Constant1), Equals(ColRef2, Constant2)), Equals(ColRef3, Constant3)) etc..
17840 */
17841 var ScopeIdExtractorImpl = (function (_super) {
17842 __extends(ScopeIdExtractorImpl, _super);
17843 function ScopeIdExtractorImpl() {
17844 _super.apply(this, arguments);
17845 this.keys = [];
17846 this.values = [];
17847 }
17848 ScopeIdExtractorImpl.prototype.visitAnd = function (expr) {
17849 expr.left.accept(this);
17850 expr.right.accept(this);
17851 };
17852 ScopeIdExtractorImpl.prototype.visitCompare = function (expr) {
17853 if (expr.comparison !== data.QueryComparisonKind.Equal) {
17854 this.visitDefault(expr);
17855 return;
17856 }
17857 debug.assert(expr.left instanceof data.SQExpr && expr.right instanceof data.SQConstantExpr, 'invalid compare expr operands');
17858 expr.left.accept(this);
17859 expr.right.accept(this);
17860 };
17861 ScopeIdExtractorImpl.prototype.visitColumnRef = function (expr) {
17862 this.keys.push(expr);
17863 };
17864 ScopeIdExtractorImpl.prototype.visitHierarchyLevel = function (expr) {
17865 this.keys.push(expr);
17866 };
17867 ScopeIdExtractorImpl.prototype.visitConstant = function (expr) {
17868 this.values.push(expr);
17869 };
17870 ScopeIdExtractorImpl.prototype.visitArithmetic = function (expr) {
17871 this.keys.push(expr);
17872 };
17873 ScopeIdExtractorImpl.prototype.visitDefault = function (expr) {
17874 this.malformed = true;
17875 };
17876 return ScopeIdExtractorImpl;
17877 }(data.DefaultSQExprVisitor));
17878 })(ScopeIdentityExtractor = data.ScopeIdentityExtractor || (data.ScopeIdentityExtractor = {}));
17879 })(data = powerbi.data || (powerbi.data = {}));
17880})(powerbi || (powerbi = {}));
17881/*
17882 * Power BI Visualizations
17883 *
17884 * Copyright (c) Microsoft Corporation
17885 * All rights reserved.
17886 * MIT License
17887 *
17888 * Permission is hereby granted, free of charge, to any person obtaining a copy
17889 * of this software and associated documentation files (the ""Software""), to deal
17890 * in the Software without restriction, including without limitation the rights
17891 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17892 * copies of the Software, and to permit persons to whom the Software is
17893 * furnished to do so, subject to the following conditions:
17894 *
17895 * The above copyright notice and this permission notice shall be included in
17896 * all copies or substantial portions of the Software.
17897 *
17898 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17899 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17900 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17901 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17902 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17903 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17904 * THE SOFTWARE.
17905 */
17906var powerbi;
17907(function (powerbi) {
17908 var data;
17909 (function (data) {
17910 var PrimitiveValueEncoding;
17911 (function (PrimitiveValueEncoding) {
17912 var SingleQuoteRegex = /'/g;
17913 function decimal(value) {
17914 debug.assertValue(value, 'value');
17915 return value + 'M';
17916 }
17917 PrimitiveValueEncoding.decimal = decimal;
17918 function double(value) {
17919 debug.assertValue(value, 'value');
17920 return value + 'D';
17921 }
17922 PrimitiveValueEncoding.double = double;
17923 function integer(value) {
17924 debug.assertValue(value, 'value');
17925 return value + 'L';
17926 }
17927 PrimitiveValueEncoding.integer = integer;
17928 function dateTime(value) {
17929 debug.assertValue(value, 'value');
17930 // Currently, server doesn't support timezone. All date time data on the server don't have time zone information.
17931 // So, when we construct a dateTime object on the client, we will need to ignor user's time zone and force it to be UTC time.
17932 // When we subtract the timeZone offset, the date time object will remain the same value as you entered but dropped the local timeZone.
17933 var date = new Date(value.getTime() - (value.getTimezoneOffset() * 60000));
17934 var dateTimeString = date.toISOString();
17935 // If it ends with Z, we want to get rid of it, because with trailing Z, it will assume the dateTime is UTC, but we don't want any timeZone information, so
17936 // we will drop it.
17937 // Also, we need to add Prefix and Suffix to match the dsr value format for dateTime object.
17938 if (jsCommon.StringExtensions.endsWith(dateTimeString, 'Z'))
17939 dateTimeString = dateTimeString.substr(0, dateTimeString.length - 1);
17940 return "datetime'" + dateTimeString + "'";
17941 }
17942 PrimitiveValueEncoding.dateTime = dateTime;
17943 function text(value) {
17944 debug.assertValue(value, 'value');
17945 return "'" + value.replace(SingleQuoteRegex, "''") + "'";
17946 }
17947 PrimitiveValueEncoding.text = text;
17948 function nullEncoding() {
17949 return 'null';
17950 }
17951 PrimitiveValueEncoding.nullEncoding = nullEncoding;
17952 function boolean(value) {
17953 return value ? 'true' : 'false';
17954 }
17955 PrimitiveValueEncoding.boolean = boolean;
17956 })(PrimitiveValueEncoding = data.PrimitiveValueEncoding || (data.PrimitiveValueEncoding = {}));
17957 })(data = powerbi.data || (powerbi.data = {}));
17958})(powerbi || (powerbi = {}));
17959/*
17960 * Power BI Visualizations
17961 *
17962 * Copyright (c) Microsoft Corporation
17963 * All rights reserved.
17964 * MIT License
17965 *
17966 * Permission is hereby granted, free of charge, to any person obtaining a copy
17967 * of this software and associated documentation files (the ""Software""), to deal
17968 * in the Software without restriction, including without limitation the rights
17969 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17970 * copies of the Software, and to permit persons to whom the Software is
17971 * furnished to do so, subject to the following conditions:
17972 *
17973 * The above copyright notice and this permission notice shall be included in
17974 * all copies or substantial portions of the Software.
17975 *
17976 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17977 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17978 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17979 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17980 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17981 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17982 * THE SOFTWARE.
17983 */
17984var powerbi;
17985(function (powerbi) {
17986 var data;
17987 (function (data) {
17988 var Agg = powerbi.data.QueryAggregateFunction;
17989 function createSQAggregationOperations(datetimeMinMaxSupported) {
17990 return new SQAggregationOperations(datetimeMinMaxSupported);
17991 }
17992 data.createSQAggregationOperations = createSQAggregationOperations;
17993 var SQAggregationOperations = (function () {
17994 function SQAggregationOperations(datetimeMinMaxSupported) {
17995 this.datetimeMinMaxSupported = datetimeMinMaxSupported;
17996 }
17997 SQAggregationOperations.prototype.getSupportedAggregates = function (expr, schema, targetTypes) {
17998 debug.assertValue(expr, 'expr');
17999 debug.assertValue(schema, 'schema');
18000 debug.assertAnyValue(targetTypes, 'targetTypes');
18001 var metadata = getMetadataForUnderlyingType(expr, schema);
18002 // don't use expr.validate as validate will be using this function and we end up in a recursive loop
18003 if (!metadata)
18004 return [];
18005 var valueType = metadata.type, fieldKind = metadata.kind, isPropertyIdentity = metadata.idOnEntityKey;
18006 if (!valueType)
18007 return [];
18008 // Cannot aggregate on model measures
18009 if (fieldKind === 1 /* Measure */)
18010 return [];
18011 if (valueType.numeric || valueType.integer) {
18012 var aggregates_1 = [Agg.Sum, Agg.Avg, Agg.Min, Agg.Max, Agg.Count, Agg.CountNonNull, Agg.StandardDeviation, Agg.Variance];
18013 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
18014 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
18015 var currentSchema = schema.schema(fieldExprItem.schema);
18016 if (currentSchema.capabilities.supportsMedian)
18017 aggregates_1.push(Agg.Median);
18018 return aggregates_1;
18019 }
18020 var aggregates = [];
18021 // Min/Max of DateTime
18022 if (this.datetimeMinMaxSupported &&
18023 valueType.dateTime &&
18024 (_.isEmpty(targetTypes) || powerbi.ValueType.isCompatibleTo(valueType, targetTypes))) {
18025 aggregates.push(Agg.Min);
18026 aggregates.push(Agg.Max);
18027 }
18028 // The supported aggregation types for an identity field are restricted to 'Count Non-Null' (e.g. for the field well aggregation options)
18029 // but a valid semantic query can return a less-restricted aggregation option which we should honor. (e.g. this results from Q&A)
18030 var distinctCountAggExists = data.SQExprInfo.getAggregate(expr) === Agg.Count;
18031 if (!(isPropertyIdentity && !distinctCountAggExists))
18032 aggregates.push(Agg.Count);
18033 aggregates.push(Agg.CountNonNull);
18034 return aggregates;
18035 };
18036 SQAggregationOperations.prototype.isSupportedAggregate = function (expr, schema, aggregate, targetTypes) {
18037 debug.assertValue(expr, 'expr');
18038 debug.assertValue(schema, 'schema');
18039 var supportedAggregates = this.getSupportedAggregates(expr, schema, targetTypes);
18040 return _.contains(supportedAggregates, aggregate);
18041 };
18042 SQAggregationOperations.prototype.createExprWithAggregate = function (expr, schema, aggregateNonNumericFields, targetTypes, preferredAggregate) {
18043 debug.assertValue(expr, 'expr');
18044 debug.assertValue(schema, 'schema');
18045 var aggregate;
18046 if (preferredAggregate != null && this.isSupportedAggregate(expr, schema, preferredAggregate, targetTypes)) {
18047 aggregate = preferredAggregate;
18048 }
18049 else {
18050 aggregate = expr.getDefaultAggregate(schema, aggregateNonNumericFields);
18051 }
18052 if (aggregate !== undefined)
18053 expr = data.SQExprBuilder.aggregate(expr, aggregate);
18054 return expr;
18055 };
18056 return SQAggregationOperations;
18057 }());
18058 function getMetadataForUnderlyingType(expr, schema) {
18059 // Unwrap the aggregate (if the expr has one), and look at the underlying type.
18060 var metadata = data.SQExprBuilder.removeAggregate(expr).getMetadata(schema);
18061 if (!metadata)
18062 metadata = expr.getMetadata(schema);
18063 return metadata;
18064 }
18065 })(data = powerbi.data || (powerbi.data = {}));
18066})(powerbi || (powerbi = {}));
18067/*
18068 * Power BI Visualizations
18069 *
18070 * Copyright (c) Microsoft Corporation
18071 * All rights reserved.
18072 * MIT License
18073 *
18074 * Permission is hereby granted, free of charge, to any person obtaining a copy
18075 * of this software and associated documentation files (the ""Software""), to deal
18076 * in the Software without restriction, including without limitation the rights
18077 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18078 * copies of the Software, and to permit persons to whom the Software is
18079 * furnished to do so, subject to the following conditions:
18080 *
18081 * The above copyright notice and this permission notice shall be included in
18082 * all copies or substantial portions of the Software.
18083 *
18084 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18085 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18086 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18087 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18088 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18089 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18090 * THE SOFTWARE.
18091 */
18092var powerbi;
18093(function (powerbi) {
18094 var data;
18095 (function (data) {
18096 var SQHierarchyExprUtils;
18097 (function (SQHierarchyExprUtils) {
18098 function getConceptualHierarchyLevelFromExpr(conceptualSchema, fieldExpr) {
18099 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
18100 var hierarchyLevel = fieldExpr.hierarchyLevel || fieldExpr.hierarchyLevelAggr;
18101 if (hierarchyLevel)
18102 return SQHierarchyExprUtils.getConceptualHierarchyLevel(conceptualSchema, fieldExprItem.schema, fieldExprItem.entity, hierarchyLevel.name, hierarchyLevel.level);
18103 }
18104 SQHierarchyExprUtils.getConceptualHierarchyLevelFromExpr = getConceptualHierarchyLevelFromExpr;
18105 function getConceptualHierarchyLevel(conceptualSchema, schemaName, entity, hierarchy, hierarchyLevel) {
18106 var schema = conceptualSchema.schema(schemaName);
18107 var conceptualHierarchy = schema.findHierarchy(entity, hierarchy);
18108 if (conceptualHierarchy) {
18109 return conceptualHierarchy.levels.withName(hierarchyLevel);
18110 }
18111 }
18112 SQHierarchyExprUtils.getConceptualHierarchyLevel = getConceptualHierarchyLevel;
18113 function getConceptualHierarchy(sqExpr, federatedSchema) {
18114 if (sqExpr instanceof data.SQHierarchyExpr) {
18115 var hierarchy = sqExpr;
18116 if (sqExpr.arg instanceof data.SQEntityExpr) {
18117 var entityExpr = sqExpr.arg;
18118 return federatedSchema
18119 .schema(entityExpr.schema)
18120 .findHierarchy(entityExpr.entity, hierarchy.hierarchy);
18121 }
18122 else if (sqExpr.arg instanceof data.SQPropertyVariationSourceExpr) {
18123 var variationExpr = sqExpr.arg;
18124 var sourceEntityExpr = variationExpr.arg;
18125 return federatedSchema
18126 .schema(sourceEntityExpr.schema)
18127 .findHierarchyByVariation(sourceEntityExpr.entity, variationExpr.property, variationExpr.name, hierarchy.hierarchy);
18128 }
18129 }
18130 }
18131 SQHierarchyExprUtils.getConceptualHierarchy = getConceptualHierarchy;
18132 function expandExpr(schema, expr, suppressHierarchyLevelExpansion) {
18133 return SQExprHierarchyToHierarchyLevelConverter.convert(expr, schema) ||
18134 SQExprVariationConverter.expand(expr, schema) ||
18135 // If we are calling expandExpr from suppressHierarchyLevelExpansion, we should not expand the hierarchylevels
18136 (!suppressHierarchyLevelExpansion && SQExprHierarchyLevelConverter.expand(expr, schema)) ||
18137 expr;
18138 }
18139 SQHierarchyExprUtils.expandExpr = expandExpr;
18140 function isHierarchyOrVariation(schema, expr) {
18141 if (expr instanceof data.SQHierarchyExpr || expr instanceof data.SQHierarchyLevelExpr)
18142 return true;
18143 var conceptualProperty = expr.getConceptualProperty(schema);
18144 if (conceptualProperty) {
18145 var column = conceptualProperty.column;
18146 if (column && column.variations && column.variations.length > 0)
18147 return true;
18148 }
18149 return false;
18150 }
18151 SQHierarchyExprUtils.isHierarchyOrVariation = isHierarchyOrVariation;
18152 // Return column reference expression for hierarchy level expression.
18153 function getSourceVariationExpr(hierarchyLevelExpr) {
18154 var fieldExprPattern = data.SQExprConverter.asFieldPattern(hierarchyLevelExpr);
18155 if (fieldExprPattern.columnHierarchyLevelVariation) {
18156 var entity = data.SQExprBuilder.entity(fieldExprPattern.columnHierarchyLevelVariation.source.schema, fieldExprPattern.columnHierarchyLevelVariation.source.entity);
18157 return data.SQExprBuilder.columnRef(entity, fieldExprPattern.columnHierarchyLevelVariation.source.name);
18158 }
18159 }
18160 SQHierarchyExprUtils.getSourceVariationExpr = getSourceVariationExpr;
18161 // Return hierarchy expression for hierarchy level expression.
18162 function getSourceHierarchy(hierarchyLevelExpr) {
18163 var fieldExprPattern = data.SQExprConverter.asFieldPattern(hierarchyLevelExpr);
18164 var hierarchyLevel = fieldExprPattern.hierarchyLevel;
18165 if (hierarchyLevel) {
18166 var entity = data.SQExprBuilder.entity(hierarchyLevel.schema, hierarchyLevel.entity, hierarchyLevel.entityVar);
18167 return data.SQExprBuilder.hierarchy(entity, hierarchyLevel.name);
18168 }
18169 }
18170 SQHierarchyExprUtils.getSourceHierarchy = getSourceHierarchy;
18171 function getHierarchySourceAsVariationSource(hierarchyLevelExpr) {
18172 // Make sure the hierarchy level source is a hierarchy
18173 if (!(hierarchyLevelExpr.arg instanceof data.SQHierarchyExpr))
18174 return;
18175 // Check if the hierarchy source if a variation
18176 var hierarchyRef = hierarchyLevelExpr.arg;
18177 if (hierarchyRef.arg instanceof data.SQPropertyVariationSourceExpr)
18178 return hierarchyRef.arg;
18179 }
18180 SQHierarchyExprUtils.getHierarchySourceAsVariationSource = getHierarchySourceAsVariationSource;
18181 /**
18182 * Returns true if firstExpr and secondExpr are levels in the same hierarchy and firstExpr is before secondExpr in allLevels.
18183 */
18184 function areHierarchyLevelsOrdered(allLevels, firstExpr, secondExpr) {
18185 // Validate that both items hierarchy levels
18186 if (!(firstExpr instanceof data.SQHierarchyLevelExpr) || !(secondExpr instanceof data.SQHierarchyLevelExpr))
18187 return false;
18188 var firstLevel = firstExpr;
18189 var secondLevel = secondExpr;
18190 // Validate that both items belong to the same hierarchy
18191 if (!data.SQExpr.equals(firstLevel.arg, secondLevel.arg))
18192 return false;
18193 // Determine the order
18194 var firstIndex = data.SQExprUtils.indexOfExpr(allLevels, firstLevel);
18195 var secondIndex = data.SQExprUtils.indexOfExpr(allLevels, secondLevel);
18196 return firstIndex !== -1 && secondIndex !== -1 && firstIndex < secondIndex;
18197 }
18198 SQHierarchyExprUtils.areHierarchyLevelsOrdered = areHierarchyLevelsOrdered;
18199 /**
18200 * Given an ordered set of levels and an ordered subset of those levels, returns the index where
18201 * expr should be inserted into the subset to maintain the correct order.
18202 */
18203 function getInsertionIndex(allLevels, orderedSubsetOfLevels, expr) {
18204 var insertIndex = 0;
18205 // Loop through the supplied levels until the insertion would no longer be in the correct order
18206 while (insertIndex < orderedSubsetOfLevels.length &&
18207 areHierarchyLevelsOrdered(allLevels, orderedSubsetOfLevels[insertIndex], expr)) {
18208 insertIndex++;
18209 }
18210 return insertIndex;
18211 }
18212 SQHierarchyExprUtils.getInsertionIndex = getInsertionIndex;
18213 })(SQHierarchyExprUtils = data.SQHierarchyExprUtils || (data.SQHierarchyExprUtils = {}));
18214 var SQExprHierarchyToHierarchyLevelConverter;
18215 (function (SQExprHierarchyToHierarchyLevelConverter) {
18216 function convert(sqExpr, federatedSchema) {
18217 debug.assertValue(sqExpr, 'sqExpr');
18218 debug.assertValue(federatedSchema, 'federatedSchema');
18219 if (sqExpr instanceof data.SQHierarchyExpr) {
18220 var hierarchyExpr = sqExpr;
18221 var conceptualHierarchy = SQHierarchyExprUtils.getConceptualHierarchy(hierarchyExpr, federatedSchema);
18222 if (conceptualHierarchy)
18223 return _.map(conceptualHierarchy.levels, function (hierarchyLevel) { return data.SQExprBuilder.hierarchyLevel(sqExpr, hierarchyLevel.name); });
18224 }
18225 }
18226 SQExprHierarchyToHierarchyLevelConverter.convert = convert;
18227 })(SQExprHierarchyToHierarchyLevelConverter = data.SQExprHierarchyToHierarchyLevelConverter || (data.SQExprHierarchyToHierarchyLevelConverter = {}));
18228 var SQExprHierarchyLevelConverter;
18229 (function (SQExprHierarchyLevelConverter) {
18230 function expand(expr, schema) {
18231 debug.assertValue(expr, 'sqExpr');
18232 debug.assertValue(schema, 'federatedSchema');
18233 var exprs = [];
18234 if (expr instanceof data.SQHierarchyLevelExpr) {
18235 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
18236 if (fieldExpr.hierarchyLevel) {
18237 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
18238 var hierarchy = schema
18239 .schema(fieldExprItem.schema)
18240 .findHierarchy(fieldExprItem.entity, fieldExpr.hierarchyLevel.name);
18241 if (hierarchy) {
18242 var hierarchyLevels = hierarchy.levels;
18243 for (var _i = 0, hierarchyLevels_2 = hierarchyLevels; _i < hierarchyLevels_2.length; _i++) {
18244 var hierarchyLevel = hierarchyLevels_2[_i];
18245 if (hierarchyLevel.name === fieldExpr.hierarchyLevel.level) {
18246 exprs.push(expr);
18247 break;
18248 }
18249 else
18250 exprs.push(data.SQExprBuilder.hierarchyLevel(data.SQExprBuilder.hierarchy(data.SQExprBuilder.entity(fieldExprItem.schema, fieldExprItem.entity, fieldExprItem.entityVar), hierarchy.name), hierarchyLevel.name));
18251 }
18252 }
18253 }
18254 }
18255 if (!_.isEmpty(exprs))
18256 return exprs;
18257 }
18258 SQExprHierarchyLevelConverter.expand = expand;
18259 })(SQExprHierarchyLevelConverter || (SQExprHierarchyLevelConverter = {}));
18260 var SQExprVariationConverter;
18261 (function (SQExprVariationConverter) {
18262 function expand(expr, schema) {
18263 debug.assertValue(expr, 'sqExpr');
18264 debug.assertValue(schema, 'federatedSchema');
18265 var exprs;
18266 var conceptualProperty = expr.getConceptualProperty(schema);
18267 if (conceptualProperty) {
18268 var column = conceptualProperty.column;
18269 if (column && column.variations && column.variations.length > 0) {
18270 var variations = column.variations;
18271 // for SU11, we support only one variation
18272 debug.assert(variations.length === 1, "variations.length");
18273 var variation = variations[0];
18274 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
18275 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
18276 exprs = [];
18277 if (variation.defaultHierarchy) {
18278 var hierarchyExpr = data.SQExprBuilder.hierarchy(data.SQExprBuilder.propertyVariationSource(data.SQExprBuilder.entity(fieldExprItem.schema, fieldExprItem.entity, fieldExprItem.entityVar), variation.name, conceptualProperty.name), variation.defaultHierarchy.name);
18279 for (var _i = 0, _a = variation.defaultHierarchy.levels; _i < _a.length; _i++) {
18280 var level = _a[_i];
18281 exprs.push(data.SQExprBuilder.hierarchyLevel(hierarchyExpr, level.name));
18282 }
18283 }
18284 }
18285 }
18286 return exprs;
18287 }
18288 SQExprVariationConverter.expand = expand;
18289 })(SQExprVariationConverter || (SQExprVariationConverter = {}));
18290 })(data = powerbi.data || (powerbi.data = {}));
18291})(powerbi || (powerbi = {}));
18292/*
18293 * Power BI Visualizations
18294 *
18295 * Copyright (c) Microsoft Corporation
18296 * All rights reserved.
18297 * MIT License
18298 *
18299 * Permission is hereby granted, free of charge, to any person obtaining a copy
18300 * of this software and associated documentation files (the ""Software""), to deal
18301 * in the Software without restriction, including without limitation the rights
18302 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18303 * copies of the Software, and to permit persons to whom the Software is
18304 * furnished to do so, subject to the following conditions:
18305 *
18306 * The above copyright notice and this permission notice shall be included in
18307 * all copies or substantial portions of the Software.
18308 *
18309 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18310 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18311 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18312 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18313 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18314 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18315 * THE SOFTWARE.
18316 */
18317var powerbi;
18318(function (powerbi) {
18319 var data;
18320 (function (data) {
18321 ;
18322 var SQExprGroupUtils;
18323 (function (SQExprGroupUtils) {
18324 /** Group all projections. Eacch group can consist of either a single property, or a collection of hierarchy items. */
18325 function groupExprs(schema, exprs) {
18326 var groups = [];
18327 for (var i = 0, len = exprs.length; i < len; i++) {
18328 var expr = exprs[i];
18329 debug.assertValue(expr, "Expression not found");
18330 if (!(expr instanceof data.SQHierarchyLevelExpr)) {
18331 groups.push({ expr: expr, children: null, selectQueryIndex: i });
18332 }
18333 else {
18334 addChildToGroup(schema, groups, expr, i);
18335 }
18336 }
18337 return groups;
18338 }
18339 SQExprGroupUtils.groupExprs = groupExprs;
18340 function addChildToGroup(schema, groups, expr, selectQueryIndex) {
18341 // shouldAddExpressionToNewGroup is used to control whether we should add the passed expr to
18342 // a new Group or to the last Group
18343 var shouldAddExpressionToNewGroup = true;
18344 var exprSource = data.SQHierarchyExprUtils.getSourceVariationExpr(expr) || data.SQHierarchyExprUtils.getSourceHierarchy(expr);
18345 var lastGroup = _.last(groups);
18346 // The relevant group is always the last added. If it has the same source hierarchy,
18347 // and is properly ordered within that hierarchy, we will need to add to this group.
18348 if (lastGroup && lastGroup.children && data.SQExpr.equals(lastGroup.expr, exprSource)) {
18349 var expandedExpr = data.SQHierarchyExprUtils.expandExpr(schema, expr.arg);
18350 if (expandedExpr instanceof Array) {
18351 var allHierarchyLevels = expandedExpr;
18352 shouldAddExpressionToNewGroup = !data.SQHierarchyExprUtils.areHierarchyLevelsOrdered(allHierarchyLevels, _.last(lastGroup.children), expr);
18353 }
18354 }
18355 if (shouldAddExpressionToNewGroup)
18356 // Use the Sourcevariation as the expression for the group.
18357 groups.push({ expr: exprSource, children: [expr], selectQueryIndex: selectQueryIndex });
18358 else {
18359 debug.assertValue(lastGroup, 'There should be a group to add the variation to');
18360 debug.assertValue(lastGroup.children, 'The group should have children to add the variation to');
18361 lastGroup.children.push(expr);
18362 }
18363 }
18364 })(SQExprGroupUtils = data.SQExprGroupUtils || (data.SQExprGroupUtils = {}));
18365 })(data = powerbi.data || (powerbi.data = {}));
18366})(powerbi || (powerbi = {}));
18367/*
18368 * Power BI Visualizations
18369 *
18370 * Copyright (c) Microsoft Corporation
18371 * All rights reserved.
18372 * MIT License
18373 *
18374 * Permission is hereby granted, free of charge, to any person obtaining a copy
18375 * of this software and associated documentation files (the ""Software""), to deal
18376 * in the Software without restriction, including without limitation the rights
18377 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18378 * copies of the Software, and to permit persons to whom the Software is
18379 * furnished to do so, subject to the following conditions:
18380 *
18381 * The above copyright notice and this permission notice shall be included in
18382 * all copies or substantial portions of the Software.
18383 *
18384 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18385 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18386 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18387 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18388 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18389 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18390 * THE SOFTWARE.
18391 */
18392var powerbi;
18393(function (powerbi) {
18394 var data;
18395 (function (data) {
18396 var StringExtensions = jsCommon.StringExtensions;
18397 /** Represents an immutable expression within a SemanticQuery. */
18398 var SQExpr = (function () {
18399 function SQExpr(kind) {
18400 debug.assertValue(kind, 'kind');
18401 this._kind = kind;
18402 }
18403 SQExpr.equals = function (x, y, ignoreCase) {
18404 return SQExprEqualityVisitor.run(x, y, ignoreCase);
18405 };
18406 SQExpr.prototype.validate = function (schema, aggrUtils, errors) {
18407 var validator = new SQExprValidationVisitor(schema, aggrUtils, errors);
18408 this.accept(validator);
18409 return validator.errors;
18410 };
18411 SQExpr.prototype.accept = function (visitor, arg) {
18412 debug.assertFail('abstract method');
18413 return;
18414 };
18415 Object.defineProperty(SQExpr.prototype, "kind", {
18416 get: function () {
18417 return this._kind;
18418 },
18419 enumerable: true,
18420 configurable: true
18421 });
18422 SQExpr.isColumn = function (expr) {
18423 debug.assertValue(expr, 'expr');
18424 return expr.kind === 1 /* ColumnRef */;
18425 };
18426 SQExpr.isConstant = function (expr) {
18427 debug.assertValue(expr, 'expr');
18428 return expr.kind === 16 /* Constant */;
18429 };
18430 SQExpr.isEntity = function (expr) {
18431 debug.assertValue(expr, 'expr');
18432 return expr.kind === 0 /* Entity */;
18433 };
18434 SQExpr.isHierarchy = function (expr) {
18435 debug.assertValue(expr, 'expr');
18436 return expr.kind === 5 /* Hierarchy */;
18437 };
18438 SQExpr.isHierarchyLevel = function (expr) {
18439 debug.assertValue(expr, 'expr');
18440 return expr.kind === 6 /* HierarchyLevel */;
18441 };
18442 SQExpr.isAggregation = function (expr) {
18443 debug.assertValue(expr, 'expr');
18444 return expr.kind === 3 /* Aggregation */;
18445 };
18446 SQExpr.isMeasure = function (expr) {
18447 debug.assertValue(expr, 'expr');
18448 return expr.kind === 2 /* MeasureRef */;
18449 };
18450 SQExpr.isSelectRef = function (expr) {
18451 debug.assertValue(expr, 'expr');
18452 return expr.kind === 28 /* SelectRef */;
18453 };
18454 SQExpr.isResourcePackageItem = function (expr) {
18455 debug.assertValue(expr, 'expr');
18456 return expr.kind === 24 /* ResourcePackageItem */;
18457 };
18458 SQExpr.prototype.getMetadata = function (federatedSchema) {
18459 debug.assertValue(federatedSchema, 'federatedSchema');
18460 var field = data.SQExprConverter.asFieldPattern(this);
18461 if (!field)
18462 return;
18463 if (field.column || field.columnAggr || field.measure)
18464 return this.getMetadataForProperty(field, federatedSchema);
18465 if (field.hierarchyLevel || field.hierarchyLevelAggr)
18466 return this.getMetadataForHierarchyLevel(field, federatedSchema);
18467 if (field.columnHierarchyLevelVariation)
18468 return this.getMetadataForVariation(field, federatedSchema);
18469 if (field.percentOfGrandTotal)
18470 return this.getMetadataForPercentOfGrandTotal();
18471 return SQExpr.getMetadataForEntity(field, federatedSchema);
18472 };
18473 SQExpr.prototype.getDefaultAggregate = function (federatedSchema, forceAggregation) {
18474 if (forceAggregation === void 0) { forceAggregation = false; }
18475 debug.assertValue(federatedSchema, 'federatedSchema');
18476 var property = this.getConceptualProperty(federatedSchema) || this.getHierarchyLevelConceptualProperty(federatedSchema);
18477 if (!property)
18478 return;
18479 var aggregate;
18480 if (property && property.kind === 0 /* Column */) {
18481 var propertyDefaultAggregate = property.column ? property.column.defaultAggregate : null;
18482 if ((property.type.integer || property.type.numeric) &&
18483 propertyDefaultAggregate !== 1 /* None */) {
18484 aggregate = defaultAggregateToQueryAggregateFunction(propertyDefaultAggregate);
18485 if (aggregate === undefined)
18486 aggregate = defaultAggregateForDataType(property.type);
18487 }
18488 // If we haven't found an appropriate aggregate, and want to force aggregation anyway,
18489 // aggregate on CountNonNull.
18490 if (aggregate === undefined && forceAggregation) {
18491 aggregate = data.QueryAggregateFunction.CountNonNull;
18492 }
18493 }
18494 return aggregate;
18495 };
18496 /** Return the SQExpr[] of group on columns if it has group on keys otherwise return the SQExpr of the column.*/
18497 SQExpr.prototype.getKeyColumns = function (schema) {
18498 var columnRefExpr = SQExprColumnRefInfoVisitor.getColumnRefSQExpr(schema, this);
18499 if (!columnRefExpr)
18500 return;
18501 var keySQExprs = [];
18502 var keys = this.getPropertyKeys(schema);
18503 if (keys && keys.length > 0) {
18504 for (var i = 0, len = keys.length; i < len; i++) {
18505 keySQExprs.push(SQExprBuilder.columnRef(columnRefExpr.source, keys[i].name));
18506 }
18507 }
18508 else
18509 keySQExprs.push(columnRefExpr);
18510 return keySQExprs;
18511 };
18512 /** Returns a value indicating whether the expression would group on keys other than itself.*/
18513 SQExpr.prototype.hasGroupOnKeys = function (schema) {
18514 var columnRefExpr = SQExprColumnRefInfoVisitor.getColumnRefSQExpr(schema, this);
18515 if (!columnRefExpr)
18516 return;
18517 var keys = this.getPropertyKeys(schema);
18518 if (!keys || keys.length < 1)
18519 return false;
18520 if (keys.length > 1)
18521 return true;
18522 var keySqExpr = SQExprBuilder.columnRef(columnRefExpr.source, keys[0].name);
18523 return !SQExpr.equals(keySqExpr, this);
18524 };
18525 SQExpr.prototype.getPropertyKeys = function (schema) {
18526 var property = this.getConceptualProperty(schema) || this.getHierarchyLevelConceptualProperty(schema);
18527 if (!property)
18528 return;
18529 return property.column ? property.column.keys : undefined;
18530 };
18531 SQExpr.prototype.getConceptualProperty = function (federatedSchema) {
18532 var field = data.SQExprConverter.asFieldPattern(this);
18533 if (!field)
18534 return;
18535 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(field);
18536 var propertyName = data.FieldExprPattern.getPropertyName(field);
18537 if (propertyName)
18538 return federatedSchema
18539 .schema(fieldExprItem.schema)
18540 .findProperty(fieldExprItem.entity, propertyName);
18541 };
18542 SQExpr.prototype.getTargetEntityForVariation = function (federatedSchema, variationName) {
18543 var property = this.getConceptualProperty(federatedSchema);
18544 if (property && property.column && !_.isEmpty(property.column.variations)) {
18545 var variations = property.column.variations;
18546 for (var _i = 0, variations_2 = variations; _i < variations_2.length; _i++) {
18547 var variation = variations_2[_i];
18548 if (variation.name === variationName)
18549 return variation.navigationProperty.targetEntity.name;
18550 }
18551 }
18552 };
18553 SQExpr.prototype.getTargetEntity = function (federatedSchema) {
18554 return SQEntityExprInfoVisitor.getEntityExpr(federatedSchema, this);
18555 };
18556 SQExpr.prototype.getHierarchyLevelConceptualProperty = function (federatedSchema) {
18557 var field = data.SQExprConverter.asFieldPattern(this);
18558 if (!field)
18559 return;
18560 var fieldExprHierachyLevel = field.hierarchyLevel || field.hierarchyLevelAggr;
18561 if (fieldExprHierachyLevel) {
18562 var fieldExprEntity = data.FieldExprPattern.toFieldExprEntityItemPattern(field);
18563 var hierarchy = federatedSchema
18564 .schema(fieldExprEntity.schema)
18565 .findHierarchy(fieldExprEntity.entity, fieldExprHierachyLevel.name);
18566 if (hierarchy) {
18567 var hierarchyLevel = hierarchy.levels.withName(fieldExprHierachyLevel.level);
18568 if (hierarchyLevel)
18569 return hierarchyLevel.column;
18570 }
18571 }
18572 };
18573 SQExpr.prototype.getMetadataForVariation = function (field, federatedSchema) {
18574 debug.assertValue(field, 'field');
18575 debug.assertValue(federatedSchema, 'federatedSchema');
18576 var columnHierarchyLevelVariation = field.columnHierarchyLevelVariation;
18577 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(field);
18578 var sourceProperty = federatedSchema
18579 .schema(fieldExprItem.schema)
18580 .findProperty(fieldExprItem.entity, columnHierarchyLevelVariation.source.name);
18581 if (sourceProperty && sourceProperty.column && sourceProperty.column.variations) {
18582 for (var _i = 0, _a = sourceProperty.column.variations; _i < _a.length; _i++) {
18583 var variation = _a[_i];
18584 if (variation.defaultHierarchy && variation.defaultHierarchy.levels) {
18585 for (var _b = 0, _c = variation.defaultHierarchy.levels; _b < _c.length; _b++) {
18586 var level = _c[_b];
18587 if (level.name === columnHierarchyLevelVariation.level.level) {
18588 var property = level.column;
18589 return {
18590 kind: (property.kind === 1 /* Measure */) ? 1 /* Measure */ : 0 /* Column */,
18591 type: property.type,
18592 format: property.format,
18593 idOnEntityKey: property.column ? property.column.idOnEntityKey : false,
18594 defaultAggregate: property.column ? property.column.defaultAggregate : null
18595 };
18596 }
18597 }
18598 }
18599 }
18600 }
18601 };
18602 SQExpr.prototype.getMetadataForHierarchyLevel = function (field, federatedSchema) {
18603 debug.assertValue(field, 'field');
18604 debug.assertValue(federatedSchema, 'federatedSchema');
18605 var property = this.getHierarchyLevelConceptualProperty(federatedSchema);
18606 if (!property)
18607 return;
18608 return this.getPropertyMetadata(field, property);
18609 };
18610 SQExpr.prototype.getMetadataForPercentOfGrandTotal = function () {
18611 return {
18612 kind: 1 /* Measure */,
18613 format: '#,##0.##%',
18614 type: powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Double)
18615 };
18616 };
18617 SQExpr.prototype.getPropertyMetadata = function (field, property) {
18618 var format = property.format;
18619 var type = property.type;
18620 var columnAggregate = field.columnAggr || field.hierarchyLevelAggr;
18621 if (columnAggregate) {
18622 switch (columnAggregate.aggregate) {
18623 case data.QueryAggregateFunction.Count:
18624 case data.QueryAggregateFunction.CountNonNull:
18625 type = powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Integer);
18626 format = undefined;
18627 break;
18628 case data.QueryAggregateFunction.Avg:
18629 if (type.integer)
18630 type = powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Double);
18631 break;
18632 }
18633 }
18634 return {
18635 kind: (property.kind === 1 /* Measure */ || (columnAggregate && columnAggregate.aggregate !== undefined)) ? 1 /* Measure */ : 0 /* Column */,
18636 type: type,
18637 format: format,
18638 idOnEntityKey: property.column ? property.column.idOnEntityKey : false,
18639 aggregate: columnAggregate ? columnAggregate.aggregate : undefined,
18640 defaultAggregate: property.column ? property.column.defaultAggregate : null
18641 };
18642 };
18643 SQExpr.prototype.getMetadataForProperty = function (field, federatedSchema) {
18644 debug.assertValue(field, 'field');
18645 debug.assertValue(federatedSchema, 'federatedSchema');
18646 var property = this.getConceptualProperty(federatedSchema);
18647 if (!property)
18648 return;
18649 return this.getPropertyMetadata(field, property);
18650 };
18651 SQExpr.getMetadataForEntity = function (field, federatedSchema) {
18652 debug.assertValue(field, 'field');
18653 debug.assertValue(federatedSchema, 'federatedSchema');
18654 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(field);
18655 var entity = federatedSchema
18656 .schema(fieldExprItem.schema)
18657 .entities
18658 .withName(fieldExprItem.entity);
18659 if (!entity)
18660 return;
18661 // We only support count and countnonnull for entity.
18662 if (field.entityAggr) {
18663 switch (field.entityAggr.aggregate) {
18664 case data.QueryAggregateFunction.Count:
18665 case data.QueryAggregateFunction.CountNonNull:
18666 return {
18667 kind: 1 /* Measure */,
18668 type: powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Integer),
18669 format: undefined,
18670 idOnEntityKey: false,
18671 aggregate: field.entityAggr.aggregate
18672 };
18673 }
18674 }
18675 };
18676 return SQExpr;
18677 }());
18678 data.SQExpr = SQExpr;
18679 /** Note: Exported for testability */
18680 function defaultAggregateForDataType(type) {
18681 if (type.integer || type.numeric)
18682 return data.QueryAggregateFunction.Sum;
18683 return data.QueryAggregateFunction.Count;
18684 }
18685 data.defaultAggregateForDataType = defaultAggregateForDataType;
18686 /** Note: Exported for testability */
18687 function defaultAggregateToQueryAggregateFunction(aggregate) {
18688 switch (aggregate) {
18689 case 6 /* Average */:
18690 return data.QueryAggregateFunction.Avg;
18691 case 3 /* Count */:
18692 return data.QueryAggregateFunction.CountNonNull;
18693 case 7 /* DistinctCount */:
18694 return data.QueryAggregateFunction.Count;
18695 case 5 /* Max */:
18696 return data.QueryAggregateFunction.Max;
18697 case 4 /* Min */:
18698 return data.QueryAggregateFunction.Min;
18699 case 2 /* Sum */:
18700 return data.QueryAggregateFunction.Sum;
18701 default:
18702 return;
18703 }
18704 }
18705 data.defaultAggregateToQueryAggregateFunction = defaultAggregateToQueryAggregateFunction;
18706 var SQEntityExpr = (function (_super) {
18707 __extends(SQEntityExpr, _super);
18708 function SQEntityExpr(schema, entity, variable) {
18709 debug.assertValue(entity, 'entity');
18710 _super.call(this, 0 /* Entity */);
18711 this.schema = schema;
18712 this.entity = entity;
18713 if (variable)
18714 this.variable = variable;
18715 }
18716 SQEntityExpr.prototype.accept = function (visitor, arg) {
18717 return visitor.visitEntity(this, arg);
18718 };
18719 return SQEntityExpr;
18720 }(SQExpr));
18721 data.SQEntityExpr = SQEntityExpr;
18722 var SQArithmeticExpr = (function (_super) {
18723 __extends(SQArithmeticExpr, _super);
18724 function SQArithmeticExpr(left, right, operator) {
18725 debug.assertValue(left, 'left');
18726 debug.assertValue(right, 'right');
18727 debug.assertValue(operator, 'operator');
18728 _super.call(this, 22 /* Arithmetic */);
18729 this.left = left;
18730 this.right = right;
18731 this.operator = operator;
18732 }
18733 SQArithmeticExpr.prototype.accept = function (visitor, arg) {
18734 return visitor.visitArithmetic(this, arg);
18735 };
18736 return SQArithmeticExpr;
18737 }(SQExpr));
18738 data.SQArithmeticExpr = SQArithmeticExpr;
18739 var SQScopedEvalExpr = (function (_super) {
18740 __extends(SQScopedEvalExpr, _super);
18741 function SQScopedEvalExpr(expression, scope) {
18742 debug.assertValue(expression, 'expression');
18743 debug.assertValue(scope, 'scope');
18744 _super.call(this, 25 /* ScopedEval */);
18745 this.expression = expression;
18746 this.scope = scope;
18747 }
18748 SQScopedEvalExpr.prototype.accept = function (visitor, arg) {
18749 return visitor.visitScopedEval(this, arg);
18750 };
18751 SQScopedEvalExpr.prototype.getMetadata = function (federatedSchema) {
18752 return this.expression.getMetadata(federatedSchema);
18753 };
18754 return SQScopedEvalExpr;
18755 }(SQExpr));
18756 data.SQScopedEvalExpr = SQScopedEvalExpr;
18757 var SQPropRefExpr = (function (_super) {
18758 __extends(SQPropRefExpr, _super);
18759 function SQPropRefExpr(kind, source, ref) {
18760 debug.assertValue(kind, 'kind');
18761 debug.assertValue(source, 'source');
18762 debug.assertValue(ref, 'ref');
18763 _super.call(this, kind);
18764 this.source = source;
18765 this.ref = ref;
18766 }
18767 return SQPropRefExpr;
18768 }(SQExpr));
18769 data.SQPropRefExpr = SQPropRefExpr;
18770 var SQColumnRefExpr = (function (_super) {
18771 __extends(SQColumnRefExpr, _super);
18772 function SQColumnRefExpr(source, ref) {
18773 _super.call(this, 1 /* ColumnRef */, source, ref);
18774 }
18775 SQColumnRefExpr.prototype.accept = function (visitor, arg) {
18776 return visitor.visitColumnRef(this, arg);
18777 };
18778 return SQColumnRefExpr;
18779 }(SQPropRefExpr));
18780 data.SQColumnRefExpr = SQColumnRefExpr;
18781 var SQMeasureRefExpr = (function (_super) {
18782 __extends(SQMeasureRefExpr, _super);
18783 function SQMeasureRefExpr(source, ref) {
18784 _super.call(this, 2 /* MeasureRef */, source, ref);
18785 }
18786 SQMeasureRefExpr.prototype.accept = function (visitor, arg) {
18787 return visitor.visitMeasureRef(this, arg);
18788 };
18789 return SQMeasureRefExpr;
18790 }(SQPropRefExpr));
18791 data.SQMeasureRefExpr = SQMeasureRefExpr;
18792 var SQAggregationExpr = (function (_super) {
18793 __extends(SQAggregationExpr, _super);
18794 function SQAggregationExpr(arg, func) {
18795 debug.assertValue(arg, 'arg');
18796 debug.assertValue(func, 'func');
18797 _super.call(this, 3 /* Aggregation */);
18798 this.arg = arg;
18799 this.func = func;
18800 }
18801 SQAggregationExpr.prototype.accept = function (visitor, arg) {
18802 return visitor.visitAggr(this, arg);
18803 };
18804 return SQAggregationExpr;
18805 }(SQExpr));
18806 data.SQAggregationExpr = SQAggregationExpr;
18807 var SQPercentileExpr = (function (_super) {
18808 __extends(SQPercentileExpr, _super);
18809 function SQPercentileExpr(arg, k, exclusive) {
18810 debug.assertValue(arg, 'arg');
18811 debug.assertValue(k, 'k');
18812 debug.assert(0 <= k && k <= 1, '0 <= k && k <= 1');
18813 debug.assertValue(exclusive, 'exclusive');
18814 _super.call(this, 27 /* Percentile */);
18815 this.arg = arg;
18816 this.k = k;
18817 this.exclusive = exclusive;
18818 }
18819 SQPercentileExpr.prototype.getMetadata = function (federatedSchema) {
18820 debug.assertValue(federatedSchema, 'federatedSchema');
18821 var argMetadata = this.arg.getMetadata(federatedSchema);
18822 if (argMetadata) {
18823 return {
18824 kind: 1 /* Measure */,
18825 type: argMetadata.type,
18826 };
18827 }
18828 };
18829 SQPercentileExpr.prototype.accept = function (visitor, arg) {
18830 return visitor.visitPercentile(this, arg);
18831 };
18832 return SQPercentileExpr;
18833 }(SQExpr));
18834 data.SQPercentileExpr = SQPercentileExpr;
18835 var SQPropertyVariationSourceExpr = (function (_super) {
18836 __extends(SQPropertyVariationSourceExpr, _super);
18837 function SQPropertyVariationSourceExpr(arg, name, property) {
18838 debug.assertValue(arg, 'arg');
18839 debug.assertValue(name, 'name');
18840 debug.assertValue(property, 'property');
18841 _super.call(this, 4 /* PropertyVariationSource */);
18842 this.arg = arg;
18843 this.name = name;
18844 this.property = property;
18845 }
18846 SQPropertyVariationSourceExpr.prototype.accept = function (visitor, arg) {
18847 return visitor.visitPropertyVariationSource(this, arg);
18848 };
18849 return SQPropertyVariationSourceExpr;
18850 }(SQExpr));
18851 data.SQPropertyVariationSourceExpr = SQPropertyVariationSourceExpr;
18852 var SQHierarchyExpr = (function (_super) {
18853 __extends(SQHierarchyExpr, _super);
18854 function SQHierarchyExpr(arg, hierarchy) {
18855 debug.assertValue(arg, 'arg');
18856 debug.assertValue(hierarchy, 'hierarchy');
18857 _super.call(this, 5 /* Hierarchy */);
18858 this.arg = arg;
18859 this.hierarchy = hierarchy;
18860 }
18861 SQHierarchyExpr.prototype.accept = function (visitor, arg) {
18862 return visitor.visitHierarchy(this, arg);
18863 };
18864 return SQHierarchyExpr;
18865 }(SQExpr));
18866 data.SQHierarchyExpr = SQHierarchyExpr;
18867 var SQHierarchyLevelExpr = (function (_super) {
18868 __extends(SQHierarchyLevelExpr, _super);
18869 function SQHierarchyLevelExpr(arg, level) {
18870 debug.assertValue(arg, 'arg');
18871 debug.assertValue(level, 'level');
18872 _super.call(this, 6 /* HierarchyLevel */);
18873 this.arg = arg;
18874 this.level = level;
18875 }
18876 SQHierarchyLevelExpr.prototype.accept = function (visitor, arg) {
18877 return visitor.visitHierarchyLevel(this, arg);
18878 };
18879 return SQHierarchyLevelExpr;
18880 }(SQExpr));
18881 data.SQHierarchyLevelExpr = SQHierarchyLevelExpr;
18882 var SQSelectRefExpr = (function (_super) {
18883 __extends(SQSelectRefExpr, _super);
18884 function SQSelectRefExpr(expressionName) {
18885 debug.assertValue(expressionName, 'arg');
18886 _super.call(this, 28 /* SelectRef */);
18887 this.expressionName = expressionName;
18888 }
18889 SQSelectRefExpr.prototype.accept = function (visitor, arg) {
18890 return visitor.visitSelectRef(this, arg);
18891 };
18892 return SQSelectRefExpr;
18893 }(SQExpr));
18894 data.SQSelectRefExpr = SQSelectRefExpr;
18895 var SQAndExpr = (function (_super) {
18896 __extends(SQAndExpr, _super);
18897 function SQAndExpr(left, right) {
18898 debug.assertValue(left, 'left');
18899 debug.assertValue(right, 'right');
18900 _super.call(this, 7 /* And */);
18901 this.left = left;
18902 this.right = right;
18903 }
18904 SQAndExpr.prototype.accept = function (visitor, arg) {
18905 return visitor.visitAnd(this, arg);
18906 };
18907 return SQAndExpr;
18908 }(SQExpr));
18909 data.SQAndExpr = SQAndExpr;
18910 var SQBetweenExpr = (function (_super) {
18911 __extends(SQBetweenExpr, _super);
18912 function SQBetweenExpr(arg, lower, upper) {
18913 debug.assertValue(arg, 'arg');
18914 debug.assertValue(lower, 'lower');
18915 debug.assertValue(upper, 'upper');
18916 _super.call(this, 8 /* Between */);
18917 this.arg = arg;
18918 this.lower = lower;
18919 this.upper = upper;
18920 }
18921 SQBetweenExpr.prototype.accept = function (visitor, arg) {
18922 return visitor.visitBetween(this, arg);
18923 };
18924 return SQBetweenExpr;
18925 }(SQExpr));
18926 data.SQBetweenExpr = SQBetweenExpr;
18927 var SQInExpr = (function (_super) {
18928 __extends(SQInExpr, _super);
18929 function SQInExpr(args, values) {
18930 debug.assertValue(args, 'args');
18931 debug.assertValue(values, 'values');
18932 _super.call(this, 9 /* In */);
18933 this.args = args;
18934 this.values = values;
18935 }
18936 SQInExpr.prototype.accept = function (visitor, arg) {
18937 return visitor.visitIn(this, arg);
18938 };
18939 return SQInExpr;
18940 }(SQExpr));
18941 data.SQInExpr = SQInExpr;
18942 var SQOrExpr = (function (_super) {
18943 __extends(SQOrExpr, _super);
18944 function SQOrExpr(left, right) {
18945 debug.assertValue(left, 'left');
18946 debug.assertValue(right, 'right');
18947 _super.call(this, 10 /* Or */);
18948 this.left = left;
18949 this.right = right;
18950 }
18951 SQOrExpr.prototype.accept = function (visitor, arg) {
18952 return visitor.visitOr(this, arg);
18953 };
18954 return SQOrExpr;
18955 }(SQExpr));
18956 data.SQOrExpr = SQOrExpr;
18957 var SQCompareExpr = (function (_super) {
18958 __extends(SQCompareExpr, _super);
18959 function SQCompareExpr(comparison, left, right) {
18960 debug.assertValue(comparison, 'kind');
18961 debug.assertValue(left, 'left');
18962 debug.assertValue(right, 'right');
18963 _super.call(this, 12 /* Compare */);
18964 this.comparison = comparison;
18965 this.left = left;
18966 this.right = right;
18967 }
18968 SQCompareExpr.prototype.accept = function (visitor, arg) {
18969 return visitor.visitCompare(this, arg);
18970 };
18971 return SQCompareExpr;
18972 }(SQExpr));
18973 data.SQCompareExpr = SQCompareExpr;
18974 var SQContainsExpr = (function (_super) {
18975 __extends(SQContainsExpr, _super);
18976 function SQContainsExpr(left, right) {
18977 debug.assertValue(left, 'left');
18978 debug.assertValue(right, 'right');
18979 _super.call(this, 11 /* Contains */);
18980 this.left = left;
18981 this.right = right;
18982 }
18983 SQContainsExpr.prototype.accept = function (visitor, arg) {
18984 return visitor.visitContains(this, arg);
18985 };
18986 return SQContainsExpr;
18987 }(SQExpr));
18988 data.SQContainsExpr = SQContainsExpr;
18989 var SQStartsWithExpr = (function (_super) {
18990 __extends(SQStartsWithExpr, _super);
18991 function SQStartsWithExpr(left, right) {
18992 debug.assertValue(left, 'left');
18993 debug.assertValue(right, 'right');
18994 _super.call(this, 13 /* StartsWith */);
18995 this.left = left;
18996 this.right = right;
18997 }
18998 SQStartsWithExpr.prototype.accept = function (visitor, arg) {
18999 return visitor.visitStartsWith(this, arg);
19000 };
19001 return SQStartsWithExpr;
19002 }(SQExpr));
19003 data.SQStartsWithExpr = SQStartsWithExpr;
19004 var SQExistsExpr = (function (_super) {
19005 __extends(SQExistsExpr, _super);
19006 function SQExistsExpr(arg) {
19007 debug.assertValue(arg, 'arg');
19008 _super.call(this, 14 /* Exists */);
19009 this.arg = arg;
19010 }
19011 SQExistsExpr.prototype.accept = function (visitor, arg) {
19012 return visitor.visitExists(this, arg);
19013 };
19014 return SQExistsExpr;
19015 }(SQExpr));
19016 data.SQExistsExpr = SQExistsExpr;
19017 var SQNotExpr = (function (_super) {
19018 __extends(SQNotExpr, _super);
19019 function SQNotExpr(arg) {
19020 debug.assertValue(arg, 'arg');
19021 _super.call(this, 15 /* Not */);
19022 this.arg = arg;
19023 }
19024 SQNotExpr.prototype.accept = function (visitor, arg) {
19025 return visitor.visitNot(this, arg);
19026 };
19027 return SQNotExpr;
19028 }(SQExpr));
19029 data.SQNotExpr = SQNotExpr;
19030 var SQConstantExpr = (function (_super) {
19031 __extends(SQConstantExpr, _super);
19032 function SQConstantExpr(type, value, valueEncoded) {
19033 debug.assertValue(type, 'type');
19034 _super.call(this, 16 /* Constant */);
19035 this.type = type;
19036 this.value = value;
19037 this.valueEncoded = valueEncoded;
19038 }
19039 SQConstantExpr.prototype.accept = function (visitor, arg) {
19040 return visitor.visitConstant(this, arg);
19041 };
19042 SQConstantExpr.prototype.getMetadata = function (federatedSchema) {
19043 debug.assertValue(federatedSchema, 'federatedSchema');
19044 return {
19045 // Returning Measure as the kind for a SQConstantExpr is slightly ambiguous allowing the return object to conform to SQEXprMetadata.
19046 // A getType or similiar function in the future would be more appropriate.
19047 kind: 1 /* Measure */,
19048 type: this.type,
19049 };
19050 };
19051 return SQConstantExpr;
19052 }(SQExpr));
19053 data.SQConstantExpr = SQConstantExpr;
19054 var SQDateSpanExpr = (function (_super) {
19055 __extends(SQDateSpanExpr, _super);
19056 function SQDateSpanExpr(unit, arg) {
19057 debug.assertValue(unit, 'unit');
19058 debug.assertValue(arg, 'arg');
19059 _super.call(this, 17 /* DateSpan */);
19060 this.unit = unit;
19061 this.arg = arg;
19062 }
19063 SQDateSpanExpr.prototype.accept = function (visitor, arg) {
19064 return visitor.visitDateSpan(this, arg);
19065 };
19066 return SQDateSpanExpr;
19067 }(SQExpr));
19068 data.SQDateSpanExpr = SQDateSpanExpr;
19069 var SQDateAddExpr = (function (_super) {
19070 __extends(SQDateAddExpr, _super);
19071 function SQDateAddExpr(unit, amount, arg) {
19072 debug.assertValue(unit, 'unit');
19073 debug.assertValue(amount, 'amount');
19074 debug.assertValue(arg, 'arg');
19075 _super.call(this, 18 /* DateAdd */);
19076 this.unit = unit;
19077 this.arg = arg;
19078 this.amount = amount;
19079 }
19080 SQDateAddExpr.prototype.accept = function (visitor, arg) {
19081 return visitor.visitDateAdd(this, arg);
19082 };
19083 return SQDateAddExpr;
19084 }(SQExpr));
19085 data.SQDateAddExpr = SQDateAddExpr;
19086 var SQNowExpr = (function (_super) {
19087 __extends(SQNowExpr, _super);
19088 function SQNowExpr() {
19089 _super.call(this, 19 /* Now */);
19090 }
19091 SQNowExpr.prototype.accept = function (visitor, arg) {
19092 return visitor.visitNow(this, arg);
19093 };
19094 return SQNowExpr;
19095 }(SQExpr));
19096 data.SQNowExpr = SQNowExpr;
19097 var SQDefaultValueExpr = (function (_super) {
19098 __extends(SQDefaultValueExpr, _super);
19099 function SQDefaultValueExpr() {
19100 _super.call(this, 21 /* DefaultValue */);
19101 }
19102 SQDefaultValueExpr.prototype.accept = function (visitor, arg) {
19103 return visitor.visitDefaultValue(this, arg);
19104 };
19105 return SQDefaultValueExpr;
19106 }(SQExpr));
19107 data.SQDefaultValueExpr = SQDefaultValueExpr;
19108 var SQAnyValueExpr = (function (_super) {
19109 __extends(SQAnyValueExpr, _super);
19110 function SQAnyValueExpr() {
19111 _super.call(this, 20 /* AnyValue */);
19112 }
19113 SQAnyValueExpr.prototype.accept = function (visitor, arg) {
19114 return visitor.visitAnyValue(this, arg);
19115 };
19116 return SQAnyValueExpr;
19117 }(SQExpr));
19118 data.SQAnyValueExpr = SQAnyValueExpr;
19119 var SQFillRuleExpr = (function (_super) {
19120 __extends(SQFillRuleExpr, _super);
19121 function SQFillRuleExpr(input, fillRule) {
19122 debug.assertValue(input, 'input');
19123 debug.assertValue(fillRule, 'fillRule');
19124 _super.call(this, 23 /* FillRule */);
19125 this.input = input;
19126 this.rule = fillRule;
19127 }
19128 SQFillRuleExpr.prototype.accept = function (visitor, arg) {
19129 return visitor.visitFillRule(this, arg);
19130 };
19131 return SQFillRuleExpr;
19132 }(SQExpr));
19133 data.SQFillRuleExpr = SQFillRuleExpr;
19134 var SQResourcePackageItemExpr = (function (_super) {
19135 __extends(SQResourcePackageItemExpr, _super);
19136 function SQResourcePackageItemExpr(packageName, packageType, itemName) {
19137 debug.assertValue(packageName, 'packageName');
19138 debug.assertValue(itemName, 'itemName');
19139 _super.call(this, 24 /* ResourcePackageItem */);
19140 this.packageName = packageName;
19141 this.packageType = packageType;
19142 this.itemName = itemName;
19143 }
19144 SQResourcePackageItemExpr.prototype.accept = function (visitor, arg) {
19145 return visitor.visitResourcePackageItem(this, arg);
19146 };
19147 return SQResourcePackageItemExpr;
19148 }(SQExpr));
19149 data.SQResourcePackageItemExpr = SQResourcePackageItemExpr;
19150 /** Provides utilities for creating & manipulating expressions. */
19151 var SQExprBuilder;
19152 (function (SQExprBuilder) {
19153 function entity(schema, entity, variable) {
19154 return new SQEntityExpr(schema, entity, variable);
19155 }
19156 SQExprBuilder.entity = entity;
19157 function columnRef(source, prop) {
19158 return new SQColumnRefExpr(source, prop);
19159 }
19160 SQExprBuilder.columnRef = columnRef;
19161 function measureRef(source, prop) {
19162 return new SQMeasureRefExpr(source, prop);
19163 }
19164 SQExprBuilder.measureRef = measureRef;
19165 function aggregate(source, aggregate) {
19166 return new SQAggregationExpr(source, aggregate);
19167 }
19168 SQExprBuilder.aggregate = aggregate;
19169 function selectRef(expressionName) {
19170 return new SQSelectRefExpr(expressionName);
19171 }
19172 SQExprBuilder.selectRef = selectRef;
19173 function percentile(source, k, exclusive) {
19174 return new SQPercentileExpr(source, k, exclusive);
19175 }
19176 SQExprBuilder.percentile = percentile;
19177 function arithmetic(left, right, operator) {
19178 return new SQArithmeticExpr(left, right, operator);
19179 }
19180 SQExprBuilder.arithmetic = arithmetic;
19181 function scopedEval(expression, scope) {
19182 return new SQScopedEvalExpr(expression, scope);
19183 }
19184 SQExprBuilder.scopedEval = scopedEval;
19185 function hierarchy(source, hierarchy) {
19186 return new SQHierarchyExpr(source, hierarchy);
19187 }
19188 SQExprBuilder.hierarchy = hierarchy;
19189 function propertyVariationSource(source, name, property) {
19190 return new SQPropertyVariationSourceExpr(source, name, property);
19191 }
19192 SQExprBuilder.propertyVariationSource = propertyVariationSource;
19193 function hierarchyLevel(source, level) {
19194 return new SQHierarchyLevelExpr(source, level);
19195 }
19196 SQExprBuilder.hierarchyLevel = hierarchyLevel;
19197 function and(left, right) {
19198 if (!left)
19199 return right;
19200 if (!right)
19201 return left;
19202 return new SQAndExpr(left, right);
19203 }
19204 SQExprBuilder.and = and;
19205 function between(arg, lower, upper) {
19206 return new SQBetweenExpr(arg, lower, upper);
19207 }
19208 SQExprBuilder.between = between;
19209 function inExpr(args, values) {
19210 return new SQInExpr(args, values);
19211 }
19212 SQExprBuilder.inExpr = inExpr;
19213 function or(left, right) {
19214 if (!left)
19215 return right;
19216 if (!right)
19217 return left;
19218 if (left instanceof SQInExpr && right instanceof SQInExpr) {
19219 var inExpr_1 = tryUseInExprs(left, right);
19220 if (inExpr_1)
19221 return inExpr_1;
19222 }
19223 return new SQOrExpr(left, right);
19224 }
19225 SQExprBuilder.or = or;
19226 function tryUseInExprs(left, right) {
19227 if (!left.args || !right.args)
19228 return;
19229 var leftArgLen = left.args.length;
19230 var rightArgLen = right.args.length;
19231 if (leftArgLen !== rightArgLen)
19232 return;
19233 for (var i = 0; i < leftArgLen; ++i) {
19234 if (!SQExpr.equals(left.args[i], right.args[i]))
19235 return;
19236 }
19237 var combinedValues = left.values.concat(right.values);
19238 return SQExprBuilder.inExpr(left.args, combinedValues);
19239 }
19240 function compare(kind, left, right) {
19241 return new SQCompareExpr(kind, left, right);
19242 }
19243 SQExprBuilder.compare = compare;
19244 function contains(left, right) {
19245 return new SQContainsExpr(left, right);
19246 }
19247 SQExprBuilder.contains = contains;
19248 function exists(arg) {
19249 return new SQExistsExpr(arg);
19250 }
19251 SQExprBuilder.exists = exists;
19252 function equal(left, right) {
19253 return compare(data.QueryComparisonKind.Equal, left, right);
19254 }
19255 SQExprBuilder.equal = equal;
19256 function not(arg) {
19257 return new SQNotExpr(arg);
19258 }
19259 SQExprBuilder.not = not;
19260 function startsWith(left, right) {
19261 return new SQStartsWithExpr(left, right);
19262 }
19263 SQExprBuilder.startsWith = startsWith;
19264 function nullConstant() {
19265 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Null), null, data.PrimitiveValueEncoding.nullEncoding());
19266 }
19267 SQExprBuilder.nullConstant = nullConstant;
19268 function now() {
19269 return new SQNowExpr();
19270 }
19271 SQExprBuilder.now = now;
19272 function defaultValue() {
19273 return new SQDefaultValueExpr();
19274 }
19275 SQExprBuilder.defaultValue = defaultValue;
19276 function anyValue() {
19277 return new SQAnyValueExpr();
19278 }
19279 SQExprBuilder.anyValue = anyValue;
19280 function boolean(value) {
19281 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Boolean), value, data.PrimitiveValueEncoding.boolean(value));
19282 }
19283 SQExprBuilder.boolean = boolean;
19284 function dateAdd(unit, amount, arg) {
19285 return new SQDateAddExpr(unit, amount, arg);
19286 }
19287 SQExprBuilder.dateAdd = dateAdd;
19288 function dateTime(value, valueEncoded) {
19289 if (valueEncoded === undefined)
19290 valueEncoded = data.PrimitiveValueEncoding.dateTime(value);
19291 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.DateTime), value, valueEncoded);
19292 }
19293 SQExprBuilder.dateTime = dateTime;
19294 function dateSpan(unit, arg) {
19295 return new SQDateSpanExpr(unit, arg);
19296 }
19297 SQExprBuilder.dateSpan = dateSpan;
19298 function decimal(value, valueEncoded) {
19299 if (valueEncoded === undefined)
19300 valueEncoded = data.PrimitiveValueEncoding.decimal(value);
19301 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Decimal), value, valueEncoded);
19302 }
19303 SQExprBuilder.decimal = decimal;
19304 function double(value, valueEncoded) {
19305 if (valueEncoded === undefined)
19306 valueEncoded = data.PrimitiveValueEncoding.double(value);
19307 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Double), value, valueEncoded);
19308 }
19309 SQExprBuilder.double = double;
19310 function integer(value, valueEncoded) {
19311 if (valueEncoded === undefined)
19312 valueEncoded = data.PrimitiveValueEncoding.integer(value);
19313 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Integer), value, valueEncoded);
19314 }
19315 SQExprBuilder.integer = integer;
19316 function text(value, valueEncoded) {
19317 debug.assert(!valueEncoded || valueEncoded === data.PrimitiveValueEncoding.text(value), 'Incorrect encoded value specified.');
19318 return new SQConstantExpr(powerbi.ValueType.fromExtendedType(powerbi.ExtendedType.Text), value, valueEncoded || data.PrimitiveValueEncoding.text(value));
19319 }
19320 SQExprBuilder.text = text;
19321 /** Returns an SQExpr that evaluates to the constant value. */
19322 function typedConstant(value, type) {
19323 if (value == null)
19324 return nullConstant();
19325 if (_.isBoolean(value)) {
19326 return boolean(value);
19327 }
19328 if (_.isString(value)) {
19329 return text(value);
19330 }
19331 if (_.isNumber(value)) {
19332 if (type.integer && powerbi.Double.isInteger(value))
19333 return integer(value);
19334 return double(value);
19335 }
19336 if (value instanceof Date) {
19337 return dateTime(value);
19338 }
19339 }
19340 SQExprBuilder.typedConstant = typedConstant;
19341 function setAggregate(expr, aggregate) {
19342 return FieldExprChangeAggregateRewriter.rewrite(expr, aggregate);
19343 }
19344 SQExprBuilder.setAggregate = setAggregate;
19345 function removeAggregate(expr) {
19346 return FieldExprRemoveAggregateRewriter.rewrite(expr);
19347 }
19348 SQExprBuilder.removeAggregate = removeAggregate;
19349 function setPercentOfGrandTotal(expr) {
19350 return SQExprSetPercentOfGrandTotalRewriter.rewrite(expr);
19351 }
19352 SQExprBuilder.setPercentOfGrandTotal = setPercentOfGrandTotal;
19353 function removePercentOfGrandTotal(expr) {
19354 return SQExprRemovePercentOfGrandTotalRewriter.rewrite(expr);
19355 }
19356 SQExprBuilder.removePercentOfGrandTotal = removePercentOfGrandTotal;
19357 function removeEntityVariables(expr) {
19358 return SQExprRemoveEntityVariablesRewriter.rewrite(expr);
19359 }
19360 SQExprBuilder.removeEntityVariables = removeEntityVariables;
19361 function fillRule(expr, rule) {
19362 debug.assertValue(expr, 'expr');
19363 debug.assertValue(rule, 'rule');
19364 return new SQFillRuleExpr(expr, rule);
19365 }
19366 SQExprBuilder.fillRule = fillRule;
19367 function resourcePackageItem(packageName, packageType, itemName) {
19368 return new SQResourcePackageItemExpr(packageName, packageType, itemName);
19369 }
19370 SQExprBuilder.resourcePackageItem = resourcePackageItem;
19371 })(SQExprBuilder = data.SQExprBuilder || (data.SQExprBuilder = {}));
19372 /** Provides utilities for obtaining information about expressions. */
19373 var SQExprInfo;
19374 (function (SQExprInfo) {
19375 function getAggregate(expr) {
19376 return SQExprAggregateInfoVisitor.getAggregate(expr);
19377 }
19378 SQExprInfo.getAggregate = getAggregate;
19379 })(SQExprInfo = data.SQExprInfo || (data.SQExprInfo = {}));
19380 var SQExprEqualityVisitor = (function () {
19381 function SQExprEqualityVisitor(ignoreCase) {
19382 this.ignoreCase = ignoreCase;
19383 }
19384 SQExprEqualityVisitor.run = function (x, y, ignoreCase) {
19385 // Normalize falsy to null
19386 x = x || null;
19387 y = y || null;
19388 if (x === y)
19389 return true;
19390 if (!x !== !y)
19391 return false;
19392 debug.assertValue(x, 'x');
19393 debug.assertValue(y, 'y');
19394 if (ignoreCase)
19395 return x.accept(SQExprEqualityVisitor.ignoreCaseInstance, y);
19396 return x.accept(SQExprEqualityVisitor.instance, y);
19397 };
19398 SQExprEqualityVisitor.prototype.visitColumnRef = function (expr, comparand) {
19399 return comparand instanceof SQColumnRefExpr &&
19400 expr.ref === comparand.ref &&
19401 this.equals(expr.source, comparand.source);
19402 };
19403 SQExprEqualityVisitor.prototype.visitMeasureRef = function (expr, comparand) {
19404 return comparand instanceof SQMeasureRefExpr &&
19405 expr.ref === comparand.ref &&
19406 this.equals(expr.source, comparand.source);
19407 };
19408 SQExprEqualityVisitor.prototype.visitAggr = function (expr, comparand) {
19409 return comparand instanceof SQAggregationExpr &&
19410 expr.func === comparand.func &&
19411 this.equals(expr.arg, comparand.arg);
19412 };
19413 SQExprEqualityVisitor.prototype.visitPercentile = function (expr, comparand) {
19414 return comparand instanceof SQPercentileExpr &&
19415 expr.exclusive === comparand.exclusive &&
19416 expr.k === comparand.k &&
19417 this.equals(expr.arg, comparand.arg);
19418 };
19419 SQExprEqualityVisitor.prototype.visitHierarchy = function (expr, comparand) {
19420 return comparand instanceof SQHierarchyExpr &&
19421 expr.hierarchy === comparand.hierarchy &&
19422 this.equals(expr.arg, comparand.arg);
19423 };
19424 SQExprEqualityVisitor.prototype.visitHierarchyLevel = function (expr, comparand) {
19425 return comparand instanceof SQHierarchyLevelExpr &&
19426 expr.level === comparand.level &&
19427 this.equals(expr.arg, comparand.arg);
19428 };
19429 SQExprEqualityVisitor.prototype.visitPropertyVariationSource = function (expr, comparand) {
19430 return comparand instanceof SQPropertyVariationSourceExpr &&
19431 expr.name === comparand.name &&
19432 expr.property === comparand.property &&
19433 this.equals(expr.arg, comparand.arg);
19434 };
19435 SQExprEqualityVisitor.prototype.visitSelectRef = function (expr, comparand) {
19436 return comparand instanceof SQSelectRefExpr &&
19437 expr.expressionName === comparand.expressionName;
19438 };
19439 SQExprEqualityVisitor.prototype.visitBetween = function (expr, comparand) {
19440 return comparand instanceof SQBetweenExpr &&
19441 this.equals(expr.arg, comparand.arg) &&
19442 this.equals(expr.lower, comparand.lower) &&
19443 this.equals(expr.upper, comparand.upper);
19444 };
19445 SQExprEqualityVisitor.prototype.visitIn = function (expr, comparand) {
19446 if (!(comparand instanceof SQInExpr) || !this.equalsAll(expr.args, comparand.args))
19447 return false;
19448 var values = expr.values, compareValues = comparand.values;
19449 if (values.length !== compareValues.length)
19450 return false;
19451 for (var i = 0, len = values.length; i < len; i++) {
19452 if (!this.equalsAll(values[i], compareValues[i]))
19453 return false;
19454 }
19455 return true;
19456 };
19457 SQExprEqualityVisitor.prototype.visitEntity = function (expr, comparand) {
19458 return comparand instanceof SQEntityExpr &&
19459 expr.schema === comparand.schema &&
19460 expr.entity === comparand.entity &&
19461 this.optionalEqual(expr.variable, comparand.variable);
19462 };
19463 SQExprEqualityVisitor.prototype.visitAnd = function (expr, comparand) {
19464 return comparand instanceof SQAndExpr &&
19465 this.equals(expr.left, comparand.left) &&
19466 this.equals(expr.right, comparand.right);
19467 };
19468 SQExprEqualityVisitor.prototype.visitOr = function (expr, comparand) {
19469 return comparand instanceof SQOrExpr &&
19470 this.equals(expr.left, comparand.left) &&
19471 this.equals(expr.right, comparand.right);
19472 };
19473 SQExprEqualityVisitor.prototype.visitCompare = function (expr, comparand) {
19474 return comparand instanceof SQCompareExpr &&
19475 expr.comparison === comparand.comparison &&
19476 this.equals(expr.left, comparand.left) &&
19477 this.equals(expr.right, comparand.right);
19478 };
19479 SQExprEqualityVisitor.prototype.visitContains = function (expr, comparand) {
19480 return comparand instanceof SQContainsExpr &&
19481 this.equals(expr.left, comparand.left) &&
19482 this.equals(expr.right, comparand.right);
19483 };
19484 SQExprEqualityVisitor.prototype.visitDateSpan = function (expr, comparand) {
19485 return comparand instanceof SQDateSpanExpr &&
19486 expr.unit === comparand.unit &&
19487 this.equals(expr.arg, comparand.arg);
19488 };
19489 SQExprEqualityVisitor.prototype.visitDateAdd = function (expr, comparand) {
19490 return comparand instanceof SQDateAddExpr &&
19491 expr.unit === comparand.unit &&
19492 expr.amount === comparand.amount &&
19493 this.equals(expr.arg, comparand.arg);
19494 };
19495 SQExprEqualityVisitor.prototype.visitExists = function (expr, comparand) {
19496 return comparand instanceof SQExistsExpr &&
19497 this.equals(expr.arg, comparand.arg);
19498 };
19499 SQExprEqualityVisitor.prototype.visitNot = function (expr, comparand) {
19500 return comparand instanceof SQNotExpr &&
19501 this.equals(expr.arg, comparand.arg);
19502 };
19503 SQExprEqualityVisitor.prototype.visitNow = function (expr, comparand) {
19504 return comparand instanceof SQNowExpr;
19505 };
19506 SQExprEqualityVisitor.prototype.visitDefaultValue = function (expr, comparand) {
19507 return comparand instanceof SQDefaultValueExpr;
19508 };
19509 SQExprEqualityVisitor.prototype.visitAnyValue = function (expr, comparand) {
19510 return comparand instanceof SQAnyValueExpr;
19511 };
19512 SQExprEqualityVisitor.prototype.visitResourcePackageItem = function (expr, comparand) {
19513 return comparand instanceof SQResourcePackageItemExpr &&
19514 expr.packageName === comparand.packageName &&
19515 expr.packageType === comparand.packageType &&
19516 expr.itemName === comparand.itemName;
19517 };
19518 SQExprEqualityVisitor.prototype.visitStartsWith = function (expr, comparand) {
19519 return comparand instanceof SQStartsWithExpr &&
19520 this.equals(expr.left, comparand.left) &&
19521 this.equals(expr.right, comparand.right);
19522 };
19523 SQExprEqualityVisitor.prototype.visitConstant = function (expr, comparand) {
19524 if (comparand instanceof SQConstantExpr && expr.type === comparand.type)
19525 return expr.type.text && this.ignoreCase ?
19526 StringExtensions.equalIgnoreCase(expr.valueEncoded, comparand.valueEncoded) :
19527 expr.valueEncoded === comparand.valueEncoded;
19528 return false;
19529 };
19530 SQExprEqualityVisitor.prototype.visitFillRule = function (expr, comparand) {
19531 if (comparand instanceof SQFillRuleExpr && this.equals(expr.input, comparand.input)) {
19532 var leftRule = expr.rule, rightRule = comparand.rule;
19533 if (leftRule === rightRule)
19534 return true;
19535 var leftLinearGradient2 = leftRule.linearGradient2, rightLinearGradient2 = rightRule.linearGradient2;
19536 if (leftLinearGradient2 && rightLinearGradient2) {
19537 return this.visitLinearGradient2(leftLinearGradient2, rightLinearGradient2);
19538 }
19539 var leftLinearGradient3 = leftRule.linearGradient3, rightLinearGradient3 = rightRule.linearGradient3;
19540 if (leftLinearGradient3 && rightLinearGradient3) {
19541 return this.visitLinearGradient3(leftLinearGradient3, rightLinearGradient3);
19542 }
19543 }
19544 return false;
19545 };
19546 SQExprEqualityVisitor.prototype.visitLinearGradient2 = function (left2, right2) {
19547 debug.assertValue(left2, 'left2');
19548 debug.assertValue(right2, 'right2');
19549 return this.equalsFillRuleStop(left2.min, right2.min) &&
19550 this.equalsFillRuleStop(left2.max, right2.max);
19551 };
19552 SQExprEqualityVisitor.prototype.visitLinearGradient3 = function (left3, right3) {
19553 debug.assertValue(left3, 'left3');
19554 debug.assertValue(right3, 'right3');
19555 return this.equalsFillRuleStop(left3.min, right3.min) &&
19556 this.equalsFillRuleStop(left3.mid, right3.mid) &&
19557 this.equalsFillRuleStop(left3.max, right3.max);
19558 };
19559 SQExprEqualityVisitor.prototype.equalsFillRuleStop = function (stop1, stop2) {
19560 debug.assertValue(stop1, 'stop1');
19561 debug.assertValue(stop2, 'stop2');
19562 if (!this.equals(stop1.color, stop2.color))
19563 return false;
19564 if (!stop1.value)
19565 return stop1.value === stop2.value;
19566 return this.equals(stop1.value, stop2.value);
19567 };
19568 SQExprEqualityVisitor.prototype.visitArithmetic = function (expr, comparand) {
19569 return comparand instanceof SQArithmeticExpr &&
19570 expr.operator === comparand.operator &&
19571 this.equals(expr.left, comparand.left) &&
19572 this.equals(expr.right, comparand.right);
19573 };
19574 SQExprEqualityVisitor.prototype.visitScopedEval = function (expr, comparand) {
19575 return comparand instanceof SQScopedEvalExpr &&
19576 this.equals(expr.expression, comparand.expression) &&
19577 this.equalsAll(expr.scope, comparand.scope);
19578 };
19579 SQExprEqualityVisitor.prototype.optionalEqual = function (x, y) {
19580 // Only check equality if both values are specified.
19581 if (x && y)
19582 return x === y;
19583 return true;
19584 };
19585 SQExprEqualityVisitor.prototype.equals = function (x, y) {
19586 return x.accept(this, y);
19587 };
19588 SQExprEqualityVisitor.prototype.equalsAll = function (x, y) {
19589 var len = x.length;
19590 if (len !== y.length)
19591 return false;
19592 for (var i = 0; i < len; i++) {
19593 if (!this.equals(x[i], y[i]))
19594 return false;
19595 }
19596 return true;
19597 };
19598 SQExprEqualityVisitor.instance = new SQExprEqualityVisitor(/* ignoreCase */ false);
19599 SQExprEqualityVisitor.ignoreCaseInstance = new SQExprEqualityVisitor(true);
19600 return SQExprEqualityVisitor;
19601 }());
19602 /** Rewrites a root-level expression. */
19603 var SQExprRootRewriter = (function (_super) {
19604 __extends(SQExprRootRewriter, _super);
19605 function SQExprRootRewriter() {
19606 _super.apply(this, arguments);
19607 }
19608 SQExprRootRewriter.prototype.visitDefault = function (expr) {
19609 return expr;
19610 };
19611 return SQExprRootRewriter;
19612 }(data.DefaultSQExprVisitor));
19613 var SQExprValidationVisitor = (function (_super) {
19614 __extends(SQExprValidationVisitor, _super);
19615 function SQExprValidationVisitor(schema, aggrUtils, errors) {
19616 debug.assertValue(schema, 'schema');
19617 debug.assertValue(aggrUtils, 'aggrUtils');
19618 _super.call(this);
19619 this.schema = schema;
19620 this.aggrUtils = aggrUtils;
19621 if (errors)
19622 this.errors = errors;
19623 }
19624 SQExprValidationVisitor.prototype.visitIn = function (expr) {
19625 var inExpr = _super.prototype.visitIn.call(this, expr);
19626 var args = inExpr.args;
19627 var values = inExpr.values;
19628 for (var _i = 0, values_2 = values; _i < values_2.length; _i++) {
19629 var valueTuple = values_2[_i];
19630 debug.assert(valueTuple.length === args.length, 'args and value tuple are not the same length');
19631 for (var i = 0, len = valueTuple.length; i < len; ++i)
19632 this.validateCompatibleType(args[i], valueTuple[i]);
19633 }
19634 return inExpr;
19635 };
19636 SQExprValidationVisitor.prototype.visitCompare = function (expr) {
19637 var compareExpr = _super.prototype.visitCompare.call(this, expr);
19638 this.validateCompatibleType(compareExpr.left, compareExpr.right);
19639 return compareExpr;
19640 };
19641 SQExprValidationVisitor.prototype.visitColumnRef = function (expr) {
19642 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
19643 if (fieldExpr) {
19644 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
19645 var entity = this.validateEntity(fieldExprItem.schema, fieldExprItem.entity);
19646 if (entity) {
19647 var prop = entity.properties.withName(fieldExpr.column.name);
19648 if (!prop ||
19649 prop.kind !== 0 /* Column */ ||
19650 !this.isQueryable(fieldExpr))
19651 this.register(3 /* invalidColumnReference */);
19652 }
19653 }
19654 return expr;
19655 };
19656 SQExprValidationVisitor.prototype.visitMeasureRef = function (expr) {
19657 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
19658 if (fieldExpr) {
19659 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
19660 var entity = this.validateEntity(fieldExprItem.schema, fieldExprItem.entity);
19661 if (entity) {
19662 var prop = entity.properties.withName(fieldExpr.measure.name);
19663 if (!prop ||
19664 prop.kind !== 1 /* Measure */ ||
19665 !this.isQueryable(fieldExpr))
19666 this.register(4 /* invalidMeasureReference */);
19667 }
19668 }
19669 return expr;
19670 };
19671 SQExprValidationVisitor.prototype.visitAggr = function (expr) {
19672 var aggregateExpr = _super.prototype.visitAggr.call(this, expr);
19673 var columnRefExpr = SQExprColumnRefInfoVisitor.getColumnRefSQExpr(this.schema, aggregateExpr.arg);
19674 if (columnRefExpr) {
19675 if (!this.aggrUtils.isSupportedAggregate(expr, this.schema, expr.func, /*targetTypes*/ null))
19676 this.register(0 /* invalidAggregateFunction */);
19677 }
19678 return aggregateExpr;
19679 };
19680 SQExprValidationVisitor.prototype.visitHierarchy = function (expr) {
19681 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
19682 if (fieldExpr) {
19683 var fieldExprItem = fieldExpr.hierarchy;
19684 if (fieldExprItem) {
19685 this.validateHierarchy(fieldExprItem.schema, fieldExprItem.entity, fieldExprItem.name);
19686 }
19687 else {
19688 this.register(5 /* invalidHierarchyReference */);
19689 }
19690 }
19691 return expr;
19692 };
19693 SQExprValidationVisitor.prototype.visitHierarchyLevel = function (expr) {
19694 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
19695 if (fieldExpr) {
19696 var hierarchyLevelFieldExprItem = fieldExpr.hierarchyLevel;
19697 if (hierarchyLevelFieldExprItem) {
19698 this.validateHierarchyLevel(hierarchyLevelFieldExprItem.schema, hierarchyLevelFieldExprItem.entity, hierarchyLevelFieldExprItem.name, hierarchyLevelFieldExprItem.level);
19699 }
19700 else if (!fieldExpr.columnHierarchyLevelVariation) {
19701 this.register(6 /* invalidHierarchyLevelReference */);
19702 }
19703 }
19704 return expr;
19705 };
19706 SQExprValidationVisitor.prototype.visitPercentile = function (expr) {
19707 expr.arg.accept(this);
19708 if (_.isEmpty(this.errors)) {
19709 var argMetadata = expr.arg.getMetadata(this.schema);
19710 if (!argMetadata ||
19711 argMetadata.kind !== 0 /* Column */ ||
19712 !(argMetadata.type && (argMetadata.type.integer || argMetadata.type.numeric))) {
19713 this.register(10 /* invalidPercentileArgument */);
19714 }
19715 }
19716 return expr;
19717 };
19718 SQExprValidationVisitor.prototype.visitEntity = function (expr) {
19719 this.validateEntity(expr.schema, expr.entity);
19720 return expr;
19721 };
19722 SQExprValidationVisitor.prototype.visitContains = function (expr) {
19723 this.validateOperandsAndTypeForStartOrContains(expr.left, expr.right);
19724 return expr;
19725 };
19726 SQExprValidationVisitor.prototype.visitStartsWith = function (expr) {
19727 this.validateOperandsAndTypeForStartOrContains(expr.left, expr.right);
19728 return expr;
19729 };
19730 SQExprValidationVisitor.prototype.visitArithmetic = function (expr) {
19731 this.validateArithmeticTypes(expr.left, expr.right);
19732 return expr;
19733 };
19734 SQExprValidationVisitor.prototype.visitScopedEval = function (expr) {
19735 // No validation necessary
19736 return expr;
19737 };
19738 SQExprValidationVisitor.prototype.validateOperandsAndTypeForStartOrContains = function (left, right) {
19739 if (left instanceof SQColumnRefExpr) {
19740 this.visitColumnRef(left);
19741 }
19742 else if (left instanceof SQHierarchyLevelExpr) {
19743 this.visitHierarchyLevel(left);
19744 }
19745 else {
19746 this.register(7 /* invalidLeftOperandType */);
19747 }
19748 if (!(right instanceof SQConstantExpr) || !right.type.text)
19749 this.register(8 /* invalidRightOperandType */);
19750 else
19751 this.validateCompatibleType(left, right);
19752 };
19753 SQExprValidationVisitor.prototype.validateArithmeticTypes = function (left, right) {
19754 if (!data.SQExprUtils.supportsArithmetic(left, this.schema))
19755 this.register(7 /* invalidLeftOperandType */);
19756 if (!data.SQExprUtils.supportsArithmetic(right, this.schema))
19757 this.register(8 /* invalidRightOperandType */);
19758 };
19759 SQExprValidationVisitor.prototype.validateCompatibleType = function (left, right) {
19760 var leftMetadata = left.getMetadata(this.schema), leftType = leftMetadata && leftMetadata.type, rightMetadata = right.getMetadata(this.schema), rightType = rightMetadata && rightMetadata.type;
19761 if (leftType && rightType && !leftType.isCompatibleFrom(rightType))
19762 this.register(9 /* invalidValueType */);
19763 };
19764 SQExprValidationVisitor.prototype.validateEntity = function (schemaName, entityName) {
19765 var schema = this.schema.schema(schemaName);
19766 if (schema) {
19767 var entity = schema.entities.withName(entityName);
19768 if (entity)
19769 return entity;
19770 this.register(2 /* invalidEntityReference */);
19771 }
19772 else {
19773 this.register(1 /* invalidSchemaReference */);
19774 }
19775 };
19776 SQExprValidationVisitor.prototype.validateHierarchy = function (schemaName, entityName, hierarchyName) {
19777 var entity = this.validateEntity(schemaName, entityName);
19778 if (entity) {
19779 var hierarchy = entity.hierarchies.withName(hierarchyName);
19780 if (hierarchy)
19781 return hierarchy;
19782 this.register(5 /* invalidHierarchyReference */);
19783 }
19784 };
19785 SQExprValidationVisitor.prototype.validateHierarchyLevel = function (schemaName, entityName, hierarchyName, levelName) {
19786 var hierarchy = this.validateHierarchy(schemaName, entityName, hierarchyName);
19787 if (hierarchy) {
19788 var hierarchyLevel = hierarchy.levels.withName(levelName);
19789 if (hierarchyLevel)
19790 return hierarchyLevel;
19791 this.register(6 /* invalidHierarchyLevelReference */);
19792 }
19793 };
19794 SQExprValidationVisitor.prototype.register = function (error) {
19795 if (!this.errors)
19796 this.errors = [];
19797 this.errors.push(error);
19798 };
19799 SQExprValidationVisitor.prototype.isQueryable = function (fieldExpr) {
19800 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(fieldExpr);
19801 if (fieldExpr.hierarchyLevel || fieldExpr.hierarchyLevelAggr) {
19802 var hierarchyLevelConceptualProperty = data.SQHierarchyExprUtils.getConceptualHierarchyLevelFromExpr(this.schema, fieldExpr);
19803 return hierarchyLevelConceptualProperty && hierarchyLevelConceptualProperty.column.queryable !== 1 /* Error */;
19804 }
19805 return this.schema.schema(fieldExprItem.schema).findProperty(fieldExprItem.entity, data.FieldExprPattern.getPropertyName(fieldExpr)).queryable !== 1 /* Error */;
19806 };
19807 return SQExprValidationVisitor;
19808 }(data.SQExprRewriter));
19809 data.SQExprValidationVisitor = SQExprValidationVisitor;
19810 /** Returns an expression's aggregate function, or undefined if it doesn't have one. */
19811 var SQExprAggregateInfoVisitor = (function (_super) {
19812 __extends(SQExprAggregateInfoVisitor, _super);
19813 function SQExprAggregateInfoVisitor() {
19814 _super.apply(this, arguments);
19815 }
19816 SQExprAggregateInfoVisitor.prototype.visitAggr = function (expr) {
19817 return expr.func;
19818 };
19819 SQExprAggregateInfoVisitor.prototype.visitDefault = function (expr) {
19820 return;
19821 };
19822 SQExprAggregateInfoVisitor.getAggregate = function (expr) {
19823 var visitor = new SQExprAggregateInfoVisitor();
19824 return expr.accept(visitor);
19825 };
19826 return SQExprAggregateInfoVisitor;
19827 }(data.DefaultSQExprVisitor));
19828 /** Returns a SQExprColumnRef expression or undefined.*/
19829 var SQExprColumnRefInfoVisitor = (function (_super) {
19830 __extends(SQExprColumnRefInfoVisitor, _super);
19831 function SQExprColumnRefInfoVisitor(schema) {
19832 _super.call(this);
19833 this.schema = schema;
19834 }
19835 SQExprColumnRefInfoVisitor.prototype.visitColumnRef = function (expr) {
19836 return expr;
19837 };
19838 SQExprColumnRefInfoVisitor.prototype.visitHierarchyLevel = function (expr) {
19839 var ref = expr.level;
19840 var hierarchy = (expr.arg);
19841 var sourceExpr = hierarchy.accept(this);
19842 if (hierarchy && hierarchy.arg instanceof SQPropertyVariationSourceExpr) {
19843 var propertyVariationSource = hierarchy.arg;
19844 var targetEntity = sourceExpr.getTargetEntityForVariation(this.schema, propertyVariationSource.name);
19845 if (sourceExpr && targetEntity) {
19846 var schemaName = (sourceExpr.source).schema;
19847 var targetEntityExpr = SQExprBuilder.entity(schemaName, targetEntity);
19848 var schemaHierarchy = this.schema.schema(schemaName).findHierarchy(targetEntity, hierarchy.hierarchy);
19849 if (schemaHierarchy) {
19850 for (var _i = 0, _a = schemaHierarchy.levels; _i < _a.length; _i++) {
19851 var level = _a[_i];
19852 if (level.name === ref)
19853 return new SQColumnRefExpr(targetEntityExpr, level.column.name);
19854 }
19855 }
19856 }
19857 }
19858 else {
19859 var entityExpr = (hierarchy.arg);
19860 var hierarchyLevelRef = data.SQHierarchyExprUtils.getConceptualHierarchyLevel(this.schema, entityExpr.schema, entityExpr.entity, hierarchy.hierarchy, expr.level);
19861 if (hierarchyLevelRef)
19862 return new SQColumnRefExpr(hierarchy.arg, hierarchyLevelRef.column.name);
19863 }
19864 };
19865 SQExprColumnRefInfoVisitor.prototype.visitHierarchy = function (expr) {
19866 return expr.arg.accept(this);
19867 };
19868 SQExprColumnRefInfoVisitor.prototype.visitPropertyVariationSource = function (expr) {
19869 var propertyName = expr.property;
19870 return new SQColumnRefExpr(expr.arg, propertyName);
19871 };
19872 SQExprColumnRefInfoVisitor.prototype.visitAggr = function (expr) {
19873 return expr.arg.accept(this);
19874 };
19875 SQExprColumnRefInfoVisitor.prototype.visitDefault = function (expr) {
19876 return;
19877 };
19878 SQExprColumnRefInfoVisitor.getColumnRefSQExpr = function (schema, expr) {
19879 var visitor = new SQExprColumnRefInfoVisitor(schema);
19880 return expr.accept(visitor);
19881 };
19882 return SQExprColumnRefInfoVisitor;
19883 }(data.DefaultSQExprVisitor));
19884 /** Returns a SQEntityExpr expression or undefined.*/
19885 var SQEntityExprInfoVisitor = (function (_super) {
19886 __extends(SQEntityExprInfoVisitor, _super);
19887 function SQEntityExprInfoVisitor(schema) {
19888 _super.call(this);
19889 this.schema = schema;
19890 }
19891 SQEntityExprInfoVisitor.prototype.visitEntity = function (expr) {
19892 return expr;
19893 };
19894 SQEntityExprInfoVisitor.prototype.visitColumnRef = function (expr) {
19895 return SQEntityExprInfoVisitor.getEntity(expr);
19896 };
19897 SQEntityExprInfoVisitor.prototype.visitHierarchyLevel = function (expr) {
19898 var columnRef = SQEntityExprInfoVisitor.getColumnRefSQExpr(this.schema, expr);
19899 return SQEntityExprInfoVisitor.getEntity(columnRef);
19900 };
19901 SQEntityExprInfoVisitor.prototype.visitHierarchy = function (expr) {
19902 return expr.arg.accept(this);
19903 };
19904 SQEntityExprInfoVisitor.prototype.visitPropertyVariationSource = function (expr) {
19905 var columnRef = SQEntityExprInfoVisitor.getColumnRefSQExpr(this.schema, expr);
19906 return SQEntityExprInfoVisitor.getEntity(columnRef);
19907 };
19908 SQEntityExprInfoVisitor.prototype.visitAggr = function (expr) {
19909 var columnRef = SQEntityExprInfoVisitor.getColumnRefSQExpr(this.schema, expr);
19910 return SQEntityExprInfoVisitor.getEntity(columnRef);
19911 };
19912 SQEntityExprInfoVisitor.prototype.visitMeasureRef = function (expr) {
19913 return expr.source.accept(this);
19914 };
19915 SQEntityExprInfoVisitor.getColumnRefSQExpr = function (schema, expr) {
19916 var visitor = new SQExprColumnRefInfoVisitor(schema);
19917 return expr.accept(visitor);
19918 };
19919 SQEntityExprInfoVisitor.getEntity = function (columnRef) {
19920 var field = data.SQExprConverter.asFieldPattern(columnRef);
19921 var column = field.column;
19922 return SQExprBuilder.entity(column.schema, column.entity, column.entityVar);
19923 };
19924 SQEntityExprInfoVisitor.getEntityExpr = function (schema, expr) {
19925 var visitor = new SQEntityExprInfoVisitor(schema);
19926 return expr.accept(visitor);
19927 };
19928 return SQEntityExprInfoVisitor;
19929 }(data.DefaultSQExprVisitor));
19930 var SQExprChangeAggregateRewriter = (function (_super) {
19931 __extends(SQExprChangeAggregateRewriter, _super);
19932 function SQExprChangeAggregateRewriter(func) {
19933 debug.assertValue(func, 'func');
19934 _super.call(this);
19935 this.func = func;
19936 }
19937 SQExprChangeAggregateRewriter.prototype.visitAggr = function (expr) {
19938 if (expr.func === this.func)
19939 return expr;
19940 return new SQAggregationExpr(expr.arg, this.func);
19941 };
19942 SQExprChangeAggregateRewriter.prototype.visitColumnRef = function (expr) {
19943 return new SQAggregationExpr(expr, this.func);
19944 };
19945 SQExprChangeAggregateRewriter.rewrite = function (expr, func) {
19946 debug.assertValue(expr, 'expr');
19947 debug.assertValue(func, 'func');
19948 var rewriter = new SQExprChangeAggregateRewriter(func);
19949 return expr.accept(rewriter);
19950 };
19951 return SQExprChangeAggregateRewriter;
19952 }(SQExprRootRewriter));
19953 var FieldExprChangeAggregateRewriter = (function () {
19954 function FieldExprChangeAggregateRewriter(sqExpr, aggregate) {
19955 this.sqExpr = sqExpr;
19956 this.aggregate = aggregate;
19957 }
19958 FieldExprChangeAggregateRewriter.rewrite = function (sqExpr, aggregate) {
19959 return data.FieldExprPattern.visit(sqExpr, new FieldExprChangeAggregateRewriter(sqExpr, aggregate));
19960 };
19961 FieldExprChangeAggregateRewriter.prototype.visitPercentOfGrandTotal = function (pattern) {
19962 pattern.baseExpr = data.SQExprConverter.asFieldPattern(SQExprChangeAggregateRewriter.rewrite(SQExprBuilder.fieldExpr(pattern.baseExpr), this.aggregate));
19963 return SQExprBuilder.fieldExpr({ percentOfGrandTotal: pattern });
19964 };
19965 FieldExprChangeAggregateRewriter.prototype.visitColumn = function (column) {
19966 return this.defaultRewrite();
19967 };
19968 FieldExprChangeAggregateRewriter.prototype.visitColumnAggr = function (columnAggr) {
19969 return this.defaultRewrite();
19970 };
19971 FieldExprChangeAggregateRewriter.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
19972 return this.defaultRewrite();
19973 };
19974 FieldExprChangeAggregateRewriter.prototype.visitSelectRef = function (selectRef) {
19975 return this.defaultRewrite();
19976 };
19977 FieldExprChangeAggregateRewriter.prototype.visitEntity = function (entity) {
19978 return this.defaultRewrite();
19979 };
19980 FieldExprChangeAggregateRewriter.prototype.visitEntityAggr = function (entityAggr) {
19981 return this.defaultRewrite();
19982 };
19983 FieldExprChangeAggregateRewriter.prototype.visitHierarchy = function (hierarchy) {
19984 return this.defaultRewrite();
19985 };
19986 FieldExprChangeAggregateRewriter.prototype.visitHierarchyLevel = function (hierarchyLevel) {
19987 return this.defaultRewrite();
19988 };
19989 FieldExprChangeAggregateRewriter.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
19990 return this.defaultRewrite();
19991 };
19992 FieldExprChangeAggregateRewriter.prototype.visitMeasure = function (measure) {
19993 return this.defaultRewrite();
19994 };
19995 FieldExprChangeAggregateRewriter.prototype.visitPercentile = function (percentile) {
19996 return this.defaultRewrite();
19997 };
19998 FieldExprChangeAggregateRewriter.prototype.defaultRewrite = function () {
19999 return SQExprChangeAggregateRewriter.rewrite(this.sqExpr, this.aggregate);
20000 };
20001 return FieldExprChangeAggregateRewriter;
20002 }());
20003 var FieldExprRemoveAggregateRewriter = (function () {
20004 function FieldExprRemoveAggregateRewriter(sqExpr) {
20005 this.sqExpr = sqExpr;
20006 }
20007 FieldExprRemoveAggregateRewriter.rewrite = function (sqExpr) {
20008 return data.FieldExprPattern.visit(sqExpr, new FieldExprRemoveAggregateRewriter(sqExpr));
20009 };
20010 FieldExprRemoveAggregateRewriter.prototype.visitPercentOfGrandTotal = function (pattern) {
20011 return FieldExprRemoveAggregateRewriter.rewrite(SQExprBuilder.fieldExpr(pattern.baseExpr));
20012 };
20013 FieldExprRemoveAggregateRewriter.prototype.visitColumn = function (column) {
20014 return this.defaultRewrite();
20015 };
20016 FieldExprRemoveAggregateRewriter.prototype.visitColumnAggr = function (columnAggr) {
20017 return this.defaultRewrite();
20018 };
20019 FieldExprRemoveAggregateRewriter.prototype.visitColumnHierarchyLevelVariation = function (columnHierarchyLevelVariation) {
20020 return this.defaultRewrite();
20021 };
20022 FieldExprRemoveAggregateRewriter.prototype.visitSelectRef = function (selectRef) {
20023 return this.defaultRewrite();
20024 };
20025 FieldExprRemoveAggregateRewriter.prototype.visitEntity = function (entity) {
20026 return this.defaultRewrite();
20027 };
20028 FieldExprRemoveAggregateRewriter.prototype.visitEntityAggr = function (entityAggr) {
20029 return this.defaultRewrite();
20030 };
20031 FieldExprRemoveAggregateRewriter.prototype.visitHierarchy = function (hierarchy) {
20032 return this.defaultRewrite();
20033 };
20034 FieldExprRemoveAggregateRewriter.prototype.visitHierarchyLevel = function (hierarchyLevel) {
20035 return this.defaultRewrite();
20036 };
20037 FieldExprRemoveAggregateRewriter.prototype.visitHierarchyLevelAggr = function (hierarchyLevelAggr) {
20038 return this.defaultRewrite();
20039 };
20040 FieldExprRemoveAggregateRewriter.prototype.visitMeasure = function (measure) {
20041 return this.defaultRewrite();
20042 };
20043 FieldExprRemoveAggregateRewriter.prototype.visitPercentile = function (percentile) {
20044 return this.defaultRewrite();
20045 };
20046 FieldExprRemoveAggregateRewriter.prototype.defaultRewrite = function () {
20047 return SQExprRemoveAggregateRewriter.rewrite(this.sqExpr);
20048 };
20049 return FieldExprRemoveAggregateRewriter;
20050 }());
20051 var SQExprRemoveAggregateRewriter = (function (_super) {
20052 __extends(SQExprRemoveAggregateRewriter, _super);
20053 function SQExprRemoveAggregateRewriter() {
20054 _super.apply(this, arguments);
20055 }
20056 SQExprRemoveAggregateRewriter.prototype.visitAggr = function (expr) {
20057 return expr.arg;
20058 };
20059 SQExprRemoveAggregateRewriter.rewrite = function (expr) {
20060 debug.assertValue(expr, 'expr');
20061 return expr.accept(SQExprRemoveAggregateRewriter.instance);
20062 };
20063 SQExprRemoveAggregateRewriter.instance = new SQExprRemoveAggregateRewriter();
20064 return SQExprRemoveAggregateRewriter;
20065 }(SQExprRootRewriter));
20066 var SQExprRemoveEntityVariablesRewriter = (function (_super) {
20067 __extends(SQExprRemoveEntityVariablesRewriter, _super);
20068 function SQExprRemoveEntityVariablesRewriter() {
20069 _super.apply(this, arguments);
20070 }
20071 SQExprRemoveEntityVariablesRewriter.prototype.visitEntity = function (expr) {
20072 if (expr.variable)
20073 return SQExprBuilder.entity(expr.schema, expr.entity);
20074 return expr;
20075 };
20076 SQExprRemoveEntityVariablesRewriter.rewrite = function (expr) {
20077 debug.assertValue(expr, 'expr');
20078 return expr.accept(SQExprRemoveEntityVariablesRewriter.instance);
20079 };
20080 SQExprRemoveEntityVariablesRewriter.instance = new SQExprRemoveEntityVariablesRewriter();
20081 return SQExprRemoveEntityVariablesRewriter;
20082 }(data.SQExprRewriter));
20083 var SQExprRemovePercentOfGrandTotalRewriter = (function (_super) {
20084 __extends(SQExprRemovePercentOfGrandTotalRewriter, _super);
20085 function SQExprRemovePercentOfGrandTotalRewriter() {
20086 _super.apply(this, arguments);
20087 }
20088 SQExprRemovePercentOfGrandTotalRewriter.rewrite = function (expr) {
20089 debug.assertValue(expr, 'expr');
20090 return expr.accept(SQExprRemovePercentOfGrandTotalRewriter.instance);
20091 };
20092 SQExprRemovePercentOfGrandTotalRewriter.prototype.visitDefault = function (expr) {
20093 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
20094 if (fieldExpr && fieldExpr.percentOfGrandTotal)
20095 expr = SQExprBuilder.fieldExpr(fieldExpr.percentOfGrandTotal.baseExpr);
20096 return expr;
20097 };
20098 SQExprRemovePercentOfGrandTotalRewriter.instance = new SQExprRemovePercentOfGrandTotalRewriter();
20099 return SQExprRemovePercentOfGrandTotalRewriter;
20100 }(SQExprRootRewriter));
20101 var SQExprSetPercentOfGrandTotalRewriter = (function (_super) {
20102 __extends(SQExprSetPercentOfGrandTotalRewriter, _super);
20103 function SQExprSetPercentOfGrandTotalRewriter() {
20104 _super.apply(this, arguments);
20105 }
20106 SQExprSetPercentOfGrandTotalRewriter.rewrite = function (expr) {
20107 debug.assertValue(expr, 'expr');
20108 return expr.accept(SQExprSetPercentOfGrandTotalRewriter.instance);
20109 };
20110 SQExprSetPercentOfGrandTotalRewriter.prototype.visitDefault = function (expr) {
20111 var fieldExpr = data.SQExprConverter.asFieldPattern(expr);
20112 if (fieldExpr && !fieldExpr.percentOfGrandTotal)
20113 expr = SQExprBuilder.fieldExpr({ percentOfGrandTotal: { baseExpr: data.SQExprConverter.asFieldPattern(expr) } });
20114 return expr;
20115 };
20116 SQExprSetPercentOfGrandTotalRewriter.instance = new SQExprSetPercentOfGrandTotalRewriter();
20117 return SQExprSetPercentOfGrandTotalRewriter;
20118 }(SQExprRootRewriter));
20119 })(data = powerbi.data || (powerbi.data = {}));
20120})(powerbi || (powerbi = {}));
20121/*
20122 * Power BI Visualizations
20123 *
20124 * Copyright (c) Microsoft Corporation
20125 * All rights reserved.
20126 * MIT License
20127 *
20128 * Permission is hereby granted, free of charge, to any person obtaining a copy
20129 * of this software and associated documentation files (the ""Software""), to deal
20130 * in the Software without restriction, including without limitation the rights
20131 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20132 * copies of the Software, and to permit persons to whom the Software is
20133 * furnished to do so, subject to the following conditions:
20134 *
20135 * The above copyright notice and this permission notice shall be included in
20136 * all copies or substantial portions of the Software.
20137 *
20138 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20139 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20140 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20141 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20142 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20143 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20144 * THE SOFTWARE.
20145 */
20146var powerbi;
20147(function (powerbi) {
20148 var data;
20149 (function (data) {
20150 var ArrayExtensions = jsCommon.ArrayExtensions;
20151 var StringExtensions = jsCommon.StringExtensions;
20152 var SQExprUtils;
20153 (function (SQExprUtils) {
20154 function supportsArithmetic(expr, schema) {
20155 var metadata = expr.getMetadata(schema), type = metadata && metadata.type;
20156 if (!metadata || !type) {
20157 return false;
20158 }
20159 return type.numeric || type.dateTime || type.duration;
20160 }
20161 SQExprUtils.supportsArithmetic = supportsArithmetic;
20162 function indexOfExpr(items, searchElement) {
20163 debug.assertValue(items, 'items');
20164 debug.assertValue(searchElement, 'searchElement');
20165 for (var i = 0, len = items.length; i < len; i++) {
20166 if (data.SQExpr.equals(items[i], searchElement))
20167 return i;
20168 }
20169 return -1;
20170 }
20171 SQExprUtils.indexOfExpr = indexOfExpr;
20172 function sequenceEqual(x, y) {
20173 debug.assertValue(x, 'x');
20174 debug.assertValue(y, 'y');
20175 var len = x.length;
20176 if (len !== y.length)
20177 return false;
20178 for (var i = 0; i < len; i++) {
20179 if (!data.SQExpr.equals(x[i], y[i]))
20180 return false;
20181 }
20182 return true;
20183 }
20184 SQExprUtils.sequenceEqual = sequenceEqual;
20185 function uniqueName(namedItems, expr, exprDefaultName) {
20186 debug.assertValue(namedItems, 'namedItems');
20187 // Determine all names
20188 var names = {};
20189 for (var i = 0, len = namedItems.length; i < len; i++)
20190 names[namedItems[i].name] = true;
20191 return StringExtensions.findUniqueName(names, exprDefaultName || defaultName(expr));
20192 }
20193 SQExprUtils.uniqueName = uniqueName;
20194 /** Generates a default expression name */
20195 function defaultName(expr, fallback) {
20196 if (fallback === void 0) { fallback = 'select'; }
20197 if (!expr)
20198 return fallback;
20199 return expr.accept(SQExprDefaultNameGenerator.instance, fallback);
20200 }
20201 SQExprUtils.defaultName = defaultName;
20202 /** Gets a value indicating whether the expr is a model measure or an aggregate. */
20203 function isMeasure(expr) {
20204 debug.assertValue(expr, 'expr');
20205 return expr.accept(IsMeasureVisitor.instance);
20206 }
20207 SQExprUtils.isMeasure = isMeasure;
20208 /** Gets a value indicating whether the expr is an AnyValue or equals comparison to AnyValue*/
20209 function isAnyValue(expr) {
20210 debug.assertValue(expr, 'expr');
20211 return expr.accept(IsAnyValueVisitor.instance);
20212 }
20213 SQExprUtils.isAnyValue = isAnyValue;
20214 /** Gets a value indicating whether the expr is a DefaultValue or equals comparison to DefaultValue*/
20215 function isDefaultValue(expr) {
20216 debug.assertValue(expr, 'expr');
20217 return expr.accept(IsDefaultValueVisitor.instance);
20218 }
20219 SQExprUtils.isDefaultValue = isDefaultValue;
20220 function discourageAggregation(expr, schema) {
20221 var capabilities = getSchemaCapabilities(expr, schema);
20222 return capabilities && capabilities.discourageQueryAggregateUsage;
20223 }
20224 SQExprUtils.discourageAggregation = discourageAggregation;
20225 function getAggregateBehavior(expr, schema) {
20226 debug.assertValue(expr, 'expr');
20227 debug.assertValue(schema, 'schema');
20228 var column = getConceptualColumn(expr, schema);
20229 if (column)
20230 return column.aggregateBehavior;
20231 }
20232 SQExprUtils.getAggregateBehavior = getAggregateBehavior;
20233 function getSchemaCapabilities(expr, schema) {
20234 debug.assertValue(expr, 'expr');
20235 debug.assertValue(schema, 'schema');
20236 var field = data.SQExprConverter.asFieldPattern(expr);
20237 if (!field)
20238 return;
20239 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(field);
20240 var conceptualSchema = schema.schema(fieldExprItem.schema);
20241 if (conceptualSchema)
20242 return conceptualSchema.capabilities;
20243 }
20244 SQExprUtils.getSchemaCapabilities = getSchemaCapabilities;
20245 function getKpiMetadata(expr, schema) {
20246 var kpiStatusProperty = getKpiStatusProperty(expr, schema);
20247 if (kpiStatusProperty)
20248 return kpiStatusProperty.kpiValue.measure.kpi.statusMetadata;
20249 var kpiTrendProperty = getKpiTrendProperty(expr, schema);
20250 if (kpiTrendProperty)
20251 return kpiTrendProperty.kpiValue.measure.kpi.trendMetadata;
20252 }
20253 SQExprUtils.getKpiMetadata = getKpiMetadata;
20254 function getConceptualEntity(entityExpr, schema) {
20255 debug.assertValue(entityExpr, 'entityExpr');
20256 var conceptualEntity = schema
20257 .schema(entityExpr.schema)
20258 .entities
20259 .withName(entityExpr.entity);
20260 return conceptualEntity;
20261 }
20262 SQExprUtils.getConceptualEntity = getConceptualEntity;
20263 function getKpiStatusProperty(expr, schema) {
20264 var property = expr.getConceptualProperty(schema);
20265 if (!property)
20266 return;
20267 var kpiValue = property.kpiValue;
20268 if (kpiValue && kpiValue.measure.kpi.status === property)
20269 return property;
20270 }
20271 function getKpiTrendProperty(expr, schema) {
20272 var property = expr.getConceptualProperty(schema);
20273 if (!property)
20274 return;
20275 var kpiValue = property.kpiValue;
20276 if (kpiValue && kpiValue.measure.kpi.trend === property)
20277 return property;
20278 }
20279 function getDefaultValue(fieldSQExpr, schema) {
20280 var column = getConceptualColumn(fieldSQExpr, schema);
20281 if (column)
20282 return column.defaultValue;
20283 }
20284 SQExprUtils.getDefaultValue = getDefaultValue;
20285 function getConceptualColumn(fieldSQExpr, schema) {
20286 if (!fieldSQExpr || !schema)
20287 return;
20288 var sqField = data.SQExprConverter.asFieldPattern(fieldSQExpr);
20289 if (!sqField)
20290 return;
20291 var column = sqField.column;
20292 if (column) {
20293 if (schema.schema(column.schema) && sqField.column.name) {
20294 var property = schema.schema(column.schema).findProperty(column.entity, sqField.column.name);
20295 if (property)
20296 return property.column;
20297 }
20298 }
20299 else {
20300 var hierarchyLevelField = sqField.hierarchyLevel;
20301 if (hierarchyLevelField) {
20302 var fieldExprItem = data.FieldExprPattern.toFieldExprEntityItemPattern(sqField);
20303 var schemaName = fieldExprItem.schema;
20304 if (schema.schema(schemaName)) {
20305 var hierarchy = schema.schema(schemaName)
20306 .findHierarchy(fieldExprItem.entity, hierarchyLevelField.name);
20307 if (hierarchy) {
20308 var hierarchyLevel = hierarchy.levels.withName(hierarchyLevelField.level);
20309 if (hierarchyLevel && hierarchyLevel.column)
20310 return hierarchyLevel.column.column;
20311 }
20312 }
20313 }
20314 }
20315 }
20316 function getDefaultValues(fieldSQExprs, schema) {
20317 if (_.isEmpty(fieldSQExprs) || !schema)
20318 return;
20319 var result = [];
20320 for (var _i = 0, fieldSQExprs_2 = fieldSQExprs; _i < fieldSQExprs_2.length; _i++) {
20321 var sqExpr = fieldSQExprs_2[_i];
20322 var defaultValue = getDefaultValue(sqExpr, schema);
20323 if (defaultValue)
20324 result.push(defaultValue);
20325 }
20326 return result;
20327 }
20328 SQExprUtils.getDefaultValues = getDefaultValues;
20329 /** Return compare or and expression for key value pairs. */
20330 function getDataViewScopeIdentityComparisonExpr(fieldsExpr, values) {
20331 debug.assert(fieldsExpr.length === values.length, "fileds and values need to be the same size");
20332 var compareExprs = [];
20333 for (var i = 0; i < fieldsExpr.length; i++) {
20334 compareExprs.push(data.SQExprBuilder.compare(data.QueryComparisonKind.Equal, fieldsExpr[i], values[i]));
20335 }
20336 if (_.isEmpty(compareExprs))
20337 return;
20338 var resultExpr;
20339 for (var _i = 0, compareExprs_1 = compareExprs; _i < compareExprs_1.length; _i++) {
20340 var compareExpr = compareExprs_1[_i];
20341 resultExpr = data.SQExprBuilder.and(resultExpr, compareExpr);
20342 }
20343 return resultExpr;
20344 }
20345 SQExprUtils.getDataViewScopeIdentityComparisonExpr = getDataViewScopeIdentityComparisonExpr;
20346 function getActiveTablesNames(queryDefn) {
20347 var tables = [];
20348 if (queryDefn) {
20349 var selectedItems = queryDefn.from();
20350 if (selectedItems !== undefined) {
20351 for (var _i = 0, _a = selectedItems.keys(); _i < _a.length; _i++) {
20352 var key = _a[_i];
20353 var entityObj = selectedItems.entity(key);
20354 if (tables.indexOf(entityObj.entity) < 0)
20355 tables.push(entityObj.entity);
20356 }
20357 }
20358 }
20359 return tables;
20360 }
20361 SQExprUtils.getActiveTablesNames = getActiveTablesNames;
20362 function isRelatedToMany(schema, sourceExpr, targetExpr) {
20363 return isRelated(schema, sourceExpr, targetExpr, 0 /* ZeroOrOne */, 2 /* Many */) ||
20364 isRelated(schema, targetExpr, sourceExpr, 2 /* Many */, 0 /* ZeroOrOne */);
20365 }
20366 SQExprUtils.isRelatedToMany = isRelatedToMany;
20367 function isRelatedToOne(schema, sourceExpr, targetExpr) {
20368 return isRelated(schema, sourceExpr, targetExpr, 2 /* Many */, 0 /* ZeroOrOne */) ||
20369 isRelated(schema, targetExpr, sourceExpr, 0 /* ZeroOrOne */, 2 /* Many */);
20370 }
20371 SQExprUtils.isRelatedToOne = isRelatedToOne;
20372 function isRelated(schema, sourceExpr, targetExpr, sourceMultiplicity, targetMultiplicity) {
20373 var source = SQExprUtils.getConceptualEntity(sourceExpr, schema);
20374 debug.assertValue(source, "could not resolve conceptual entity form sourceExpr.");
20375 if (_.isEmpty(source.navigationProperties))
20376 return false;
20377 var target = SQExprUtils.getConceptualEntity(targetExpr, schema);
20378 debug.assertValue(target, "could not resolve conceptual entity form targetExpr.");
20379 var queue = [];
20380 queue.push(source);
20381 // walk the relationship path from source.
20382 while (!_.isEmpty(queue)) {
20383 var current = queue.shift();
20384 var navProperties = current.navigationProperties;
20385 if (_.isEmpty(navProperties))
20386 continue;
20387 for (var _i = 0, navProperties_1 = navProperties; _i < navProperties_1.length; _i++) {
20388 var navProperty = navProperties_1[_i];
20389 if (!navProperty.isActive)
20390 continue;
20391 if (navProperty.targetMultiplicity === targetMultiplicity && navProperty.sourceMultiplicity === sourceMultiplicity) {
20392 if (navProperty.targetEntity === target)
20393 return true;
20394 queue.push(navProperty.targetEntity);
20395 }
20396 }
20397 }
20398 return false;
20399 }
20400 function isRelatedOneToOne(schema, sourceExpr, targetExpr) {
20401 var source = SQExprUtils.getConceptualEntity(sourceExpr, schema);
20402 debug.assertValue(source, "could not resolve conceptual entity form sourceExpr.");
20403 var target = SQExprUtils.getConceptualEntity(targetExpr, schema);
20404 debug.assertValue(target, "could not resolve conceptual entity form targetExpr.");
20405 var sourceNavigations = source.navigationProperties;
20406 var targetNavigations = target.navigationProperties;
20407 if (_.isEmpty(sourceNavigations) && _.isEmpty(targetNavigations))
20408 return false;
20409 return hasOneToOneNavigation(sourceNavigations, target) || hasOneToOneNavigation(targetNavigations, source);
20410 }
20411 SQExprUtils.isRelatedOneToOne = isRelatedOneToOne;
20412 function hasOneToOneNavigation(navigationProperties, targetEntity) {
20413 if (_.isEmpty(navigationProperties))
20414 return false;
20415 for (var _i = 0, navigationProperties_1 = navigationProperties; _i < navigationProperties_1.length; _i++) {
20416 var navigationProperty = navigationProperties_1[_i];
20417 if (!navigationProperty.isActive)
20418 continue;
20419 if (navigationProperty.targetEntity !== targetEntity)
20420 continue;
20421 if (navigationProperty.sourceMultiplicity === 0 /* ZeroOrOne */ &&
20422 navigationProperty.targetMultiplicity === 0 /* ZeroOrOne */) {
20423 return true;
20424 }
20425 }
20426 return false;
20427 }
20428 /** Performs a union of the 2 arrays with SQExpr.equals as comparator to skip duplicate items,
20429 and returns a new array. When available, we should use _.unionWith from lodash. */
20430 function concatUnique(leftExprs, rightExprs) {
20431 debug.assertValue(leftExprs, 'leftExprs');
20432 debug.assertValue(rightExprs, 'rightExprs');
20433 var concatExprs = ArrayExtensions.copy(leftExprs);
20434 for (var _i = 0, rightExprs_1 = rightExprs; _i < rightExprs_1.length; _i++) {
20435 var expr = rightExprs_1[_i];
20436 if (indexOfExpr(concatExprs, expr) === -1) {
20437 concatExprs.push(expr);
20438 }
20439 }
20440 return concatExprs;
20441 }
20442 SQExprUtils.concatUnique = concatUnique;
20443 var SQExprDefaultNameGenerator = (function (_super) {
20444 __extends(SQExprDefaultNameGenerator, _super);
20445 function SQExprDefaultNameGenerator() {
20446 _super.apply(this, arguments);
20447 }
20448 SQExprDefaultNameGenerator.prototype.visitEntity = function (expr) {
20449 return expr.entity;
20450 };
20451 SQExprDefaultNameGenerator.prototype.visitColumnRef = function (expr) {
20452 return expr.source.accept(this) + '.' + expr.ref;
20453 };
20454 SQExprDefaultNameGenerator.prototype.visitMeasureRef = function (expr, fallback) {
20455 return expr.source.accept(this) + '.' + expr.ref;
20456 };
20457 SQExprDefaultNameGenerator.prototype.visitAggr = function (expr, fallback) {
20458 return data.QueryAggregateFunction[expr.func] + '(' + expr.arg.accept(this) + ')';
20459 };
20460 SQExprDefaultNameGenerator.prototype.visitPercentile = function (expr, fallback) {
20461 var func = expr.exclusive
20462 ? 'Percentile.Exc('
20463 : 'Percentile.Inc(';
20464 return func + expr.arg.accept(this) + ', ' + expr.k + ')';
20465 };
20466 SQExprDefaultNameGenerator.prototype.visitArithmetic = function (expr, fallback) {
20467 return powerbi.data.getArithmeticOperatorName(expr.operator) + '(' + expr.left.accept(this) + ', ' + expr.right.accept(this) + ')';
20468 };
20469 SQExprDefaultNameGenerator.prototype.visitConstant = function (expr) {
20470 return 'const';
20471 };
20472 SQExprDefaultNameGenerator.prototype.visitDefault = function (expr, fallback) {
20473 return fallback || 'expr';
20474 };
20475 SQExprDefaultNameGenerator.instance = new SQExprDefaultNameGenerator();
20476 return SQExprDefaultNameGenerator;
20477 }(data.DefaultSQExprVisitorWithArg));
20478 var IsMeasureVisitor = (function (_super) {
20479 __extends(IsMeasureVisitor, _super);
20480 function IsMeasureVisitor() {
20481 _super.apply(this, arguments);
20482 }
20483 IsMeasureVisitor.prototype.visitMeasureRef = function (expr) {
20484 return true;
20485 };
20486 IsMeasureVisitor.prototype.visitAggr = function (expr) {
20487 return true;
20488 };
20489 IsMeasureVisitor.prototype.visitArithmetic = function (expr) {
20490 return true;
20491 };
20492 IsMeasureVisitor.prototype.visitDefault = function (expr) {
20493 return false;
20494 };
20495 IsMeasureVisitor.instance = new IsMeasureVisitor();
20496 return IsMeasureVisitor;
20497 }(data.DefaultSQExprVisitor));
20498 var IsDefaultValueVisitor = (function (_super) {
20499 __extends(IsDefaultValueVisitor, _super);
20500 function IsDefaultValueVisitor() {
20501 _super.apply(this, arguments);
20502 }
20503 IsDefaultValueVisitor.prototype.visitCompare = function (expr) {
20504 if (expr.comparison !== data.QueryComparisonKind.Equal)
20505 return false;
20506 return expr.right.accept(this);
20507 };
20508 IsDefaultValueVisitor.prototype.visitAnd = function (expr) {
20509 return expr.left.accept(this) && expr.right.accept(this);
20510 };
20511 IsDefaultValueVisitor.prototype.visitDefaultValue = function (expr) {
20512 return true;
20513 };
20514 IsDefaultValueVisitor.prototype.visitDefault = function (expr) {
20515 return false;
20516 };
20517 IsDefaultValueVisitor.instance = new IsDefaultValueVisitor();
20518 return IsDefaultValueVisitor;
20519 }(data.DefaultSQExprVisitor));
20520 var IsAnyValueVisitor = (function (_super) {
20521 __extends(IsAnyValueVisitor, _super);
20522 function IsAnyValueVisitor() {
20523 _super.apply(this, arguments);
20524 }
20525 IsAnyValueVisitor.prototype.visitCompare = function (expr) {
20526 if (expr.comparison !== data.QueryComparisonKind.Equal)
20527 return false;
20528 return expr.right.accept(this);
20529 };
20530 IsAnyValueVisitor.prototype.visitAnd = function (expr) {
20531 return expr.left.accept(this) && expr.right.accept(this);
20532 };
20533 IsAnyValueVisitor.prototype.visitAnyValue = function (expr) {
20534 return true;
20535 };
20536 IsAnyValueVisitor.prototype.visitDefault = function (expr) {
20537 return false;
20538 };
20539 IsAnyValueVisitor.instance = new IsAnyValueVisitor();
20540 return IsAnyValueVisitor;
20541 }(data.DefaultSQExprVisitor));
20542 })(SQExprUtils = data.SQExprUtils || (data.SQExprUtils = {}));
20543 })(data = powerbi.data || (powerbi.data = {}));
20544})(powerbi || (powerbi = {}));
20545/*
20546 * Power BI Visualizations
20547 *
20548 * Copyright (c) Microsoft Corporation
20549 * All rights reserved.
20550 * MIT License
20551 *
20552 * Permission is hereby granted, free of charge, to any person obtaining a copy
20553 * of this software and associated documentation files (the ""Software""), to deal
20554 * in the Software without restriction, including without limitation the rights
20555 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20556 * copies of the Software, and to permit persons to whom the Software is
20557 * furnished to do so, subject to the following conditions:
20558 *
20559 * The above copyright notice and this permission notice shall be included in
20560 * all copies or substantial portions of the Software.
20561 *
20562 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20563 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20564 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20565 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20566 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20567 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20568 * THE SOFTWARE.
20569 */
20570var powerbi;
20571(function (powerbi) {
20572 var data;
20573 (function (data) {
20574 var SemanticQueryRewriter = (function () {
20575 function SemanticQueryRewriter(exprRewriter) {
20576 this.exprRewriter = exprRewriter;
20577 }
20578 SemanticQueryRewriter.prototype.rewriteFrom = function (fromValue) {
20579 var fromContents = {};
20580 var originalFrom = fromValue, originalFromKeys = originalFrom.keys();
20581 for (var i = 0, len = originalFromKeys.length; i < len; i++) {
20582 var keyName = originalFromKeys[i], originalEntityRef = originalFrom.entity(keyName), originalEntityExpr = data.SQExprBuilder.entity(originalEntityRef.schema, originalEntityRef.entity, keyName), updatedEntityExpr = originalEntityExpr.accept(this.exprRewriter);
20583 fromContents[keyName] = {
20584 schema: updatedEntityExpr.schema,
20585 entity: updatedEntityExpr.entity,
20586 };
20587 }
20588 return new data.SQFrom(fromContents);
20589 };
20590 SemanticQueryRewriter.prototype.rewriteSelect = function (selectItems, from) {
20591 debug.assertValue(selectItems, 'selectItems');
20592 debug.assertValue(from, 'from');
20593 return this.rewriteNamedSQExpressions(selectItems, from);
20594 };
20595 SemanticQueryRewriter.prototype.rewriteGroupBy = function (groupByitems, from) {
20596 debug.assertAnyValue(groupByitems, 'groupByitems');
20597 debug.assertValue(from, 'from');
20598 if (_.isEmpty(groupByitems))
20599 return;
20600 return this.rewriteNamedSQExpressions(groupByitems, from);
20601 };
20602 SemanticQueryRewriter.prototype.rewriteNamedSQExpressions = function (expressions, from) {
20603 var _this = this;
20604 debug.assertValue(expressions, 'expressions');
20605 return _.map(expressions, function (item) {
20606 return {
20607 name: item.name,
20608 expr: data.SQExprRewriterWithSourceRenames.rewrite(item.expr.accept(_this.exprRewriter), from)
20609 };
20610 });
20611 };
20612 SemanticQueryRewriter.prototype.rewriteOrderBy = function (orderByItems, from) {
20613 debug.assertAnyValue(orderByItems, 'orderByItems');
20614 debug.assertValue(from, 'from');
20615 if (_.isEmpty(orderByItems))
20616 return;
20617 var orderBy = [];
20618 for (var i = 0, len = orderByItems.length; i < len; i++) {
20619 var item = orderByItems[i], updatedExpr = data.SQExprRewriterWithSourceRenames.rewrite(item.expr.accept(this.exprRewriter), from);
20620 orderBy.push({
20621 direction: item.direction,
20622 expr: updatedExpr,
20623 });
20624 }
20625 return orderBy;
20626 };
20627 SemanticQueryRewriter.prototype.rewriteWhere = function (whereItems, from) {
20628 var _this = this;
20629 debug.assertAnyValue(whereItems, 'whereItems');
20630 debug.assertValue(from, 'from');
20631 if (_.isEmpty(whereItems))
20632 return;
20633 var where = [];
20634 for (var i = 0, len = whereItems.length; i < len; i++) {
20635 var originalWhere = whereItems[i];
20636 var updatedWhere = {
20637 condition: data.SQExprRewriterWithSourceRenames.rewrite(originalWhere.condition.accept(this.exprRewriter), from),
20638 };
20639 if (originalWhere.target)
20640 updatedWhere.target = _.map(originalWhere.target, function (e) { return data.SQExprRewriterWithSourceRenames.rewrite(e.accept(_this.exprRewriter), from); });
20641 where.push(updatedWhere);
20642 }
20643 return where;
20644 };
20645 return SemanticQueryRewriter;
20646 }());
20647 data.SemanticQueryRewriter = SemanticQueryRewriter;
20648 })(data = powerbi.data || (powerbi.data = {}));
20649})(powerbi || (powerbi = {}));
20650/*
20651 * Power BI Visualizations
20652 *
20653 * Copyright (c) Microsoft Corporation
20654 * All rights reserved.
20655 * MIT License
20656 *
20657 * Permission is hereby granted, free of charge, to any person obtaining a copy
20658 * of this software and associated documentation files (the ""Software""), to deal
20659 * in the Software without restriction, including without limitation the rights
20660 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20661 * copies of the Software, and to permit persons to whom the Software is
20662 * furnished to do so, subject to the following conditions:
20663 *
20664 * The above copyright notice and this permission notice shall be included in
20665 * all copies or substantial portions of the Software.
20666 *
20667 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20668 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20669 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20670 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20671 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20672 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20673 * THE SOFTWARE.
20674 */
20675var powerbi;
20676(function (powerbi) {
20677 var data;
20678 (function (data) {
20679 var ArrayExtensions = jsCommon.ArrayExtensions;
20680 /**
20681 * Represents a semantic query that is:
20682 * 1) Round-trippable with a JSON QueryDefinition.
20683 * 2) Immutable
20684 * 3) Long-lived and does not have strong references to a conceptual model (only names).
20685 */
20686 var SemanticQuery = (function () {
20687 function SemanticQuery(from, where, orderBy, select, groupBy) {
20688 debug.assertValue(from, 'from');
20689 debug.assertValue(select, 'select');
20690 this.fromValue = from;
20691 this.whereItems = where;
20692 this.orderByItems = orderBy;
20693 this.selectItems = select;
20694 this.groupByItems = groupBy;
20695 }
20696 SemanticQuery.create = function () {
20697 if (!SemanticQuery.empty)
20698 SemanticQuery.empty = new SemanticQuery(new SQFrom(), null, null, [], null);
20699 return SemanticQuery.empty;
20700 };
20701 SemanticQuery.createWithTrimmedFrom = function (from, where, orderBy, select, groupBy) {
20702 var unreferencedKeyFinder = new UnreferencedKeyFinder(from.keys());
20703 // Where
20704 if (where) {
20705 for (var i = 0, len = where.length; i < len; i++) {
20706 var filter = where[i];
20707 filter.condition.accept(unreferencedKeyFinder);
20708 var filterTarget = filter.target;
20709 if (filterTarget) {
20710 for (var j = 0, jlen = filterTarget.length; j < jlen; j++)
20711 if (filterTarget[j])
20712 filterTarget[j].accept(unreferencedKeyFinder);
20713 }
20714 }
20715 }
20716 // OrderBy
20717 if (orderBy) {
20718 for (var i = 0, len = orderBy.length; i < len; i++)
20719 orderBy[i].expr.accept(unreferencedKeyFinder);
20720 }
20721 // Select
20722 for (var i = 0, len = select.length; i < len; i++)
20723 select[i].expr.accept(unreferencedKeyFinder);
20724 // GroupBy
20725 if (groupBy) {
20726 for (var i = 0, len = groupBy.length; i < len; i++)
20727 groupBy[i].expr.accept(unreferencedKeyFinder);
20728 }
20729 var unreferencedKeys = unreferencedKeyFinder.result();
20730 for (var i = 0, len = unreferencedKeys.length; i < len; i++)
20731 from.remove(unreferencedKeys[i]);
20732 return new SemanticQuery(from, where, orderBy, select, groupBy);
20733 };
20734 SemanticQuery.prototype.from = function () {
20735 return this.fromValue.clone();
20736 };
20737 SemanticQuery.prototype.select = function (values) {
20738 if (_.isEmpty(arguments))
20739 return this.getSelect();
20740 return this.setSelect(values);
20741 };
20742 SemanticQuery.prototype.getSelect = function () {
20743 return SemanticQuery.createNamedExpressionArray(this.selectItems);
20744 };
20745 SemanticQuery.createNamedExpressionArray = function (items) {
20746 return ArrayExtensions.extendWithName(_.map(items, function (s) {
20747 return {
20748 name: s.name,
20749 expr: s.expr,
20750 };
20751 }));
20752 };
20753 SemanticQuery.prototype.setSelect = function (values) {
20754 var from = this.fromValue.clone();
20755 var selectItems = SemanticQuery.rewriteExpressionsWithSourceRenames(values, from);
20756 return SemanticQuery.createWithTrimmedFrom(from, this.whereItems, this.orderByItems, selectItems, this.groupByItems);
20757 };
20758 SemanticQuery.rewriteExpressionsWithSourceRenames = function (values, from) {
20759 var items = [];
20760 for (var i = 0, len = values.length; i < len; i++) {
20761 var value = values[i];
20762 items.push({
20763 name: value.name,
20764 expr: SQExprRewriterWithSourceRenames.rewrite(value.expr, from)
20765 });
20766 }
20767 return items;
20768 };
20769 /** Removes the given expression from the select. */
20770 SemanticQuery.prototype.removeSelect = function (expr) {
20771 debug.assertValue(expr, 'expr');
20772 var originalItems = this.selectItems, selectItems = [];
20773 for (var i = 0, len = originalItems.length; i < len; i++) {
20774 var originalExpr = originalItems[i];
20775 if (data.SQExpr.equals(originalExpr.expr, expr))
20776 continue;
20777 selectItems.push(originalExpr);
20778 }
20779 return SemanticQuery.createWithTrimmedFrom(this.fromValue.clone(), this.whereItems, this.orderByItems, selectItems, this.groupByItems);
20780 };
20781 /** Removes the given expression from order by. */
20782 SemanticQuery.prototype.removeOrderBy = function (expr) {
20783 var sorts = this.orderBy();
20784 for (var i = sorts.length - 1; i >= 0; i--) {
20785 if (data.SQExpr.equals(sorts[i].expr, expr))
20786 sorts.splice(i, 1);
20787 }
20788 return SemanticQuery.createWithTrimmedFrom(this.fromValue.clone(), this.whereItems, sorts, this.selectItems, this.groupByItems);
20789 };
20790 SemanticQuery.prototype.selectNameOf = function (expr) {
20791 var index = data.SQExprUtils.indexOfExpr(_.map(this.selectItems, function (s) { return s.expr; }), expr);
20792 if (index >= 0)
20793 return this.selectItems[index].name;
20794 };
20795 SemanticQuery.prototype.setSelectAt = function (index, expr) {
20796 debug.assertValue(expr, 'expr');
20797 if (index >= this.selectItems.length)
20798 return;
20799 var select = this.select(), from = this.fromValue.clone(), originalName = select[index].name;
20800 select[index] = {
20801 name: originalName,
20802 expr: SQExprRewriterWithSourceRenames.rewrite(expr, from)
20803 };
20804 return SemanticQuery.createWithTrimmedFrom(from, this.whereItems, this.orderByItems, select, this.groupByItems);
20805 };
20806 /** Adds a the expression to the select clause. */
20807 SemanticQuery.prototype.addSelect = function (expr, exprName) {
20808 debug.assertValue(expr, 'expr');
20809 var selectItems = this.select(), from = this.fromValue.clone();
20810 selectItems.push(this.createNamedExpr(selectItems, from, expr, exprName));
20811 return SemanticQuery.createWithTrimmedFrom(from, this.whereItems, this.orderByItems, selectItems, this.groupByItems);
20812 };
20813 SemanticQuery.prototype.createNamedExpr = function (currentNames, from, expr, exprName) {
20814 return {
20815 name: data.SQExprUtils.uniqueName(currentNames, expr, exprName),
20816 expr: SQExprRewriterWithSourceRenames.rewrite(expr, from)
20817 };
20818 };
20819 SemanticQuery.prototype.groupBy = function (values) {
20820 if (_.isEmpty(arguments))
20821 return this.getGroupBy();
20822 return this.setGroupBy(values);
20823 };
20824 SemanticQuery.prototype.getGroupBy = function () {
20825 return SemanticQuery.createNamedExpressionArray(this.groupByItems);
20826 };
20827 SemanticQuery.prototype.setGroupBy = function (values) {
20828 var from = this.fromValue.clone();
20829 var groupByItems = SemanticQuery.rewriteExpressionsWithSourceRenames(values, from);
20830 return SemanticQuery.createWithTrimmedFrom(from, this.whereItems, this.orderByItems, this.selectItems, groupByItems);
20831 };
20832 SemanticQuery.prototype.addGroupBy = function (expr) {
20833 debug.assertValue(expr, 'expr');
20834 var groupByItems = this.groupBy(), from = this.fromValue.clone();
20835 groupByItems.push(this.createNamedExpr(groupByItems, from, expr));
20836 return SemanticQuery.createWithTrimmedFrom(from, this.whereItems, this.orderByItems, this.selectItems, groupByItems);
20837 };
20838 SemanticQuery.prototype.orderBy = function (values) {
20839 if (_.isEmpty(arguments))
20840 return this.getOrderBy();
20841 return this.setOrderBy(values);
20842 };
20843 SemanticQuery.prototype.getOrderBy = function () {
20844 var result = [];
20845 var orderBy = this.orderByItems;
20846 if (orderBy) {
20847 for (var i = 0, len = orderBy.length; i < len; i++) {
20848 var clause = orderBy[i];
20849 result.push({
20850 expr: clause.expr,
20851 direction: clause.direction,
20852 });
20853 }
20854 }
20855 return result;
20856 };
20857 SemanticQuery.prototype.setOrderBy = function (values) {
20858 debug.assertValue(values, 'values');
20859 var updatedOrderBy = [], from = this.fromValue.clone();
20860 for (var i = 0, len = values.length; i < len; i++) {
20861 var clause = values[i];
20862 updatedOrderBy.push({
20863 expr: SQExprRewriterWithSourceRenames.rewrite(clause.expr, from),
20864 direction: clause.direction,
20865 });
20866 }
20867 return SemanticQuery.createWithTrimmedFrom(from, this.whereItems, updatedOrderBy, this.selectItems, this.groupByItems);
20868 };
20869 SemanticQuery.prototype.where = function (values) {
20870 if (_.isEmpty(arguments))
20871 return this.getWhere();
20872 return this.setWhere(values);
20873 };
20874 SemanticQuery.prototype.getWhere = function () {
20875 var result = [];
20876 var whereItems = this.whereItems;
20877 if (whereItems) {
20878 for (var i = 0, len = whereItems.length; i < len; i++)
20879 result.push(whereItems[i]);
20880 }
20881 return result;
20882 };
20883 SemanticQuery.prototype.setWhere = function (values) {
20884 debug.assertValue(values, 'values');
20885 var updatedWhere = [], from = this.fromValue.clone();
20886 for (var i = 0, len = values.length; i < len; i++) {
20887 var filter = values[i];
20888 var updatedFilter = {
20889 condition: SQExprRewriterWithSourceRenames.rewrite(filter.condition, from),
20890 };
20891 var filterTarget = filter.target;
20892 if (filterTarget) {
20893 updatedFilter.target = [];
20894 for (var j = 0, jlen = filterTarget.length; j < jlen; j++)
20895 if (filterTarget[j]) {
20896 var updatedTarget = SQExprRewriterWithSourceRenames.rewrite(filterTarget[j], from);
20897 updatedFilter.target.push(updatedTarget);
20898 }
20899 }
20900 updatedWhere.push(updatedFilter);
20901 }
20902 return SemanticQuery.createWithTrimmedFrom(from, updatedWhere, this.orderByItems, this.selectItems, this.groupByItems);
20903 };
20904 SemanticQuery.prototype.addWhere = function (filter) {
20905 debug.assertValue(filter, 'filter');
20906 var updatedWhere = this.where(), incomingWhere = filter.where(), from = this.fromValue.clone();
20907 for (var i = 0, len = incomingWhere.length; i < len; i++) {
20908 var clause = incomingWhere[i];
20909 var updatedClause = {
20910 condition: SQExprRewriterWithSourceRenames.rewrite(clause.condition, from),
20911 };
20912 if (clause.target)
20913 updatedClause.target = _.map(clause.target, function (t) { return SQExprRewriterWithSourceRenames.rewrite(t, from); });
20914 updatedWhere.push(updatedClause);
20915 }
20916 return SemanticQuery.createWithTrimmedFrom(from, updatedWhere, this.orderByItems, this.selectItems, this.groupByItems);
20917 };
20918 SemanticQuery.prototype.rewrite = function (exprRewriter) {
20919 var rewriter = new data.SemanticQueryRewriter(exprRewriter);
20920 var from = rewriter.rewriteFrom(this.fromValue);
20921 var where = rewriter.rewriteWhere(this.whereItems, from);
20922 var orderBy = rewriter.rewriteOrderBy(this.orderByItems, from);
20923 var select = rewriter.rewriteSelect(this.selectItems, from);
20924 var groupBy = rewriter.rewriteGroupBy(this.groupByItems, from);
20925 return SemanticQuery.createWithTrimmedFrom(from, where, orderBy, select, groupBy);
20926 };
20927 return SemanticQuery;
20928 }());
20929 data.SemanticQuery = SemanticQuery;
20930 /** Represents a semantic filter condition. Round-trippable with a JSON FilterDefinition. Instances of this class are immutable. */
20931 var SemanticFilter = (function () {
20932 function SemanticFilter(from, where) {
20933 debug.assertValue(from, 'from');
20934 debug.assertValue(where, 'where');
20935 this.fromValue = from;
20936 this.whereItems = where;
20937 }
20938 SemanticFilter.fromSQExpr = function (contract) {
20939 debug.assertValue(contract, 'contract');
20940 var from = new SQFrom();
20941 var rewrittenContract = SQExprRewriterWithSourceRenames.rewrite(contract, from);
20942 // DEVNOTE targets of some filters are visual specific and will get resolved only during query generation.
20943 // Thus not setting a target here.
20944 var where = [{
20945 condition: rewrittenContract
20946 }];
20947 return new SemanticFilter(from, where);
20948 };
20949 SemanticFilter.getDefaultValueFilter = function (fieldSQExprs) {
20950 return SemanticFilter.getDataViewScopeIdentityComparisonFilters(fieldSQExprs, data.SQExprBuilder.defaultValue());
20951 };
20952 SemanticFilter.getAnyValueFilter = function (fieldSQExprs) {
20953 return SemanticFilter.getDataViewScopeIdentityComparisonFilters(fieldSQExprs, data.SQExprBuilder.anyValue());
20954 };
20955 SemanticFilter.getDataViewScopeIdentityComparisonFilters = function (fieldSQExprs, value) {
20956 debug.assertValue(fieldSQExprs, 'fieldSQExprs');
20957 debug.assertValue(value, 'value');
20958 if (fieldSQExprs instanceof Array) {
20959 var values = Array.apply(null, Array(fieldSQExprs.length)).map(function () { return value; });
20960 return SemanticFilter.fromSQExpr(data.SQExprUtils.getDataViewScopeIdentityComparisonExpr(fieldSQExprs, values));
20961 }
20962 return SemanticFilter.fromSQExpr(data.SQExprBuilder.equal(fieldSQExprs, value));
20963 };
20964 SemanticFilter.prototype.from = function () {
20965 return this.fromValue.clone();
20966 };
20967 SemanticFilter.prototype.conditions = function () {
20968 var expressions = [];
20969 var where = this.whereItems;
20970 for (var i = 0, len = where.length; i < len; i++) {
20971 var filter = where[i];
20972 expressions.push(filter.condition);
20973 }
20974 return expressions;
20975 };
20976 SemanticFilter.prototype.where = function () {
20977 var result = [];
20978 var whereItems = this.whereItems;
20979 for (var i = 0, len = whereItems.length; i < len; i++)
20980 result.push(whereItems[i]);
20981 return result;
20982 };
20983 SemanticFilter.prototype.rewrite = function (exprRewriter) {
20984 var rewriter = new data.SemanticQueryRewriter(exprRewriter);
20985 var from = rewriter.rewriteFrom(this.fromValue);
20986 var where = rewriter.rewriteWhere(this.whereItems, from);
20987 return new SemanticFilter(from, where);
20988 };
20989 SemanticFilter.prototype.validate = function (schema, aggrUtils, errors) {
20990 var validator = new data.SQExprValidationVisitor(schema, aggrUtils, errors);
20991 this.rewrite(validator);
20992 return validator.errors;
20993 };
20994 /** Merges a list of SemanticFilters into one. */
20995 SemanticFilter.merge = function (filters) {
20996 if (_.isEmpty(filters))
20997 return null;
20998 if (filters.length === 1)
20999 return filters[0];
21000 var firstFilter = filters[0];
21001 var from = firstFilter.from(), where = ArrayExtensions.take(firstFilter.whereItems, firstFilter.whereItems.length);
21002 for (var i = 1, len = filters.length; i < len; i++)
21003 SemanticFilter.applyFilter(filters[i], from, where);
21004 return new SemanticFilter(from, where);
21005 };
21006 SemanticFilter.isDefaultFilter = function (filter) {
21007 if (!filter || filter.where().length !== 1)
21008 return false;
21009 return data.SQExprUtils.isDefaultValue(filter.where()[0].condition);
21010 };
21011 SemanticFilter.isAnyFilter = function (filter) {
21012 if (!filter || filter.where().length !== 1)
21013 return false;
21014 return data.SQExprUtils.isAnyValue(filter.where()[0].condition);
21015 };
21016 SemanticFilter.isSameFilter = function (leftFilter, rightFilter) {
21017 if (jsCommon.JsonComparer.equals(leftFilter, rightFilter)) {
21018 return !((SemanticFilter.isDefaultFilter(leftFilter) && SemanticFilter.isAnyFilter(rightFilter))
21019 || (SemanticFilter.isAnyFilter(leftFilter) && SemanticFilter.isDefaultFilter(rightFilter)));
21020 }
21021 return false;
21022 };
21023 SemanticFilter.applyFilter = function (filter, from, where) {
21024 debug.assertValue(filter, 'filter');
21025 debug.assertValue(from, 'from');
21026 debug.assertValue(where, 'where');
21027 // Where
21028 var filterWhereItems = filter.whereItems;
21029 for (var i = 0; i < filterWhereItems.length; i++) {
21030 var filterWhereItem = filterWhereItems[i];
21031 var updatedWhereItem = {
21032 condition: SQExprRewriterWithSourceRenames.rewrite(filterWhereItem.condition, from),
21033 };
21034 if (filterWhereItem.target)
21035 updatedWhereItem.target = _.map(filterWhereItem.target, function (e) { return SQExprRewriterWithSourceRenames.rewrite(e, from); });
21036 where.push(updatedWhereItem);
21037 }
21038 };
21039 return SemanticFilter;
21040 }());
21041 data.SemanticFilter = SemanticFilter;
21042 /** Represents a SemanticQuery/SemanticFilter from clause. */
21043 var SQFrom = (function () {
21044 function SQFrom(items) {
21045 this.items = items || {};
21046 }
21047 SQFrom.prototype.keys = function () {
21048 return Object.keys(this.items);
21049 };
21050 SQFrom.prototype.entity = function (key) {
21051 return this.items[key];
21052 };
21053 SQFrom.prototype.ensureEntity = function (entity, desiredVariableName) {
21054 debug.assertValue(entity, 'entity');
21055 // 1) Reuse a reference to the entity among the already referenced
21056 var keys = this.keys();
21057 for (var i_1 = 0, len = keys.length; i_1 < len; i_1++) {
21058 var key = keys[i_1], item = this.items[key];
21059 if (item && entity.entity === item.entity && entity.schema === item.schema)
21060 return { name: key };
21061 }
21062 // 2) Add a reference to the entity
21063 var candidateName = desiredVariableName || this.candidateName(entity.entity), uniqueName = candidateName, i = 2;
21064 while (this.items[uniqueName]) {
21065 uniqueName = candidateName + i++;
21066 }
21067 this.items[uniqueName] = entity;
21068 return { name: uniqueName, new: true };
21069 };
21070 SQFrom.prototype.remove = function (key) {
21071 delete this.items[key];
21072 };
21073 /** Converts the entity name into a short reference name. Follows the Semantic Query convention of a short name. */
21074 SQFrom.prototype.candidateName = function (ref) {
21075 debug.assertValue(ref, 'ref');
21076 var idx = ref.lastIndexOf('.');
21077 if (idx >= 0 && (idx !== ref.length - 1))
21078 ref = ref.substr(idx + 1);
21079 return ref.substring(0, 1).toLowerCase();
21080 };
21081 SQFrom.prototype.clone = function () {
21082 // NOTE: consider deprecating this method and instead making QueryFrom be CopyOnWrite (currently we proactively clone).
21083 var cloned = new SQFrom();
21084 // NOTE: we use extend rather than prototypical inheritance on items because we use Object.keys.
21085 $.extend(cloned.items, this.items);
21086 return cloned;
21087 };
21088 return SQFrom;
21089 }());
21090 data.SQFrom = SQFrom;
21091 var SQExprRewriterWithSourceRenames = (function (_super) {
21092 __extends(SQExprRewriterWithSourceRenames, _super);
21093 function SQExprRewriterWithSourceRenames(renames) {
21094 debug.assertValue(renames, 'renames');
21095 _super.call(this);
21096 this.renames = renames;
21097 }
21098 SQExprRewriterWithSourceRenames.prototype.visitEntity = function (expr) {
21099 var updatedName = this.renames[expr.entity];
21100 if (updatedName)
21101 return new data.SQEntityExpr(expr.schema, expr.entity, updatedName);
21102 return _super.prototype.visitEntity.call(this, expr);
21103 };
21104 SQExprRewriterWithSourceRenames.prototype.rewriteFilter = function (filter) {
21105 debug.assertValue(filter, 'filter');
21106 var updatedTargets = undefined;
21107 if (filter.target)
21108 updatedTargets = this.rewriteArray(filter.target);
21109 var updatedCondition = filter.condition.accept(this);
21110 if (filter.condition === updatedCondition && filter.target === updatedTargets)
21111 return filter;
21112 var updatedFilter = {
21113 condition: updatedCondition,
21114 };
21115 if (updatedTargets)
21116 updatedFilter.target = updatedTargets;
21117 return updatedFilter;
21118 };
21119 SQExprRewriterWithSourceRenames.prototype.rewriteArray = function (exprs) {
21120 debug.assertValue(exprs, 'exprs');
21121 var updatedExprs;
21122 for (var i = 0, len = exprs.length; i < len; i++) {
21123 var expr = exprs[i], rewrittenExpr = expr.accept(this);
21124 if (expr !== rewrittenExpr && !updatedExprs)
21125 updatedExprs = ArrayExtensions.take(exprs, i);
21126 if (updatedExprs)
21127 updatedExprs.push(rewrittenExpr);
21128 }
21129 return updatedExprs || exprs;
21130 };
21131 SQExprRewriterWithSourceRenames.rewrite = function (expr, from) {
21132 debug.assertValue(expr, 'expr');
21133 debug.assertValue(from, 'from');
21134 var renames = QuerySourceRenameDetector.run(expr, from);
21135 var rewriter = new SQExprRewriterWithSourceRenames(renames);
21136 return expr.accept(rewriter);
21137 };
21138 return SQExprRewriterWithSourceRenames;
21139 }(data.SQExprRewriter));
21140 data.SQExprRewriterWithSourceRenames = SQExprRewriterWithSourceRenames;
21141 /** Responsible for updating a QueryFrom based on SQExpr references. */
21142 var QuerySourceRenameDetector = (function (_super) {
21143 __extends(QuerySourceRenameDetector, _super);
21144 function QuerySourceRenameDetector(from) {
21145 debug.assertValue(from, 'from');
21146 _super.call(this);
21147 this.from = from;
21148 this.renames = {};
21149 }
21150 QuerySourceRenameDetector.run = function (expr, from) {
21151 var detector = new QuerySourceRenameDetector(from);
21152 expr.accept(detector);
21153 return detector.renames;
21154 };
21155 QuerySourceRenameDetector.prototype.visitEntity = function (expr) {
21156 // TODO: Renames must take the schema into account, not just entity set name.
21157 var existingEntity = this.from.entity(expr.variable);
21158 if (existingEntity && existingEntity.schema === expr.schema && existingEntity.entity === expr.entity)
21159 return;
21160 var actualEntity = this.from.ensureEntity({
21161 schema: expr.schema,
21162 entity: expr.entity,
21163 }, expr.variable);
21164 this.renames[expr.entity] = actualEntity.name;
21165 };
21166 return QuerySourceRenameDetector;
21167 }(data.DefaultSQExprVisitorWithTraversal));
21168 /** Visitor for finding unreferenced sources. */
21169 var UnreferencedKeyFinder = (function (_super) {
21170 __extends(UnreferencedKeyFinder, _super);
21171 function UnreferencedKeyFinder(keys) {
21172 debug.assertValue(keys, 'keys');
21173 _super.call(this);
21174 this.keys = keys;
21175 }
21176 UnreferencedKeyFinder.prototype.visitEntity = function (expr) {
21177 var index = this.keys.indexOf(expr.variable);
21178 if (index >= 0)
21179 this.keys.splice(index, 1);
21180 };
21181 UnreferencedKeyFinder.prototype.result = function () {
21182 return this.keys;
21183 };
21184 return UnreferencedKeyFinder;
21185 }(data.DefaultSQExprVisitorWithTraversal));
21186 })(data = powerbi.data || (powerbi.data = {}));
21187})(powerbi || (powerbi = {}));
21188/*
21189 * Power BI Visualizations
21190 *
21191 * Copyright (c) Microsoft Corporation
21192 * All rights reserved.
21193 * MIT License
21194 *
21195 * Permission is hereby granted, free of charge, to any person obtaining a copy
21196 * of this software and associated documentation files (the ""Software""), to deal
21197 * in the Software without restriction, including without limitation the rights
21198 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21199 * copies of the Software, and to permit persons to whom the Software is
21200 * furnished to do so, subject to the following conditions:
21201 *
21202 * The above copyright notice and this permission notice shall be included in
21203 * all copies or substantial portions of the Software.
21204 *
21205 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21206 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21207 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21208 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21209 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21210 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21211 * THE SOFTWARE.
21212 */
21213var powerbi;
21214(function (powerbi) {
21215 var data;
21216 (function (data) {
21217 var DataViewTransform = powerbi.data.DataViewTransform;
21218 var SQExprBuilder = powerbi.data.SQExprBuilder;
21219 function createCategoricalDataViewBuilder() {
21220 return new CategoricalDataViewBuilder();
21221 }
21222 data.createCategoricalDataViewBuilder = createCategoricalDataViewBuilder;
21223 var CategoricalDataViewBuilder = (function () {
21224 function CategoricalDataViewBuilder() {
21225 this.categories = [];
21226 this.staticMeasureColumns = [];
21227 this.dynamicMeasureColumns = [];
21228 this.columnIndex = 0;
21229 }
21230 CategoricalDataViewBuilder.prototype.withCategory = function (options) {
21231 var categoryValues = options.values, identityFrom = options.identityFrom, type = options.source.type;
21232 var categoryColumn = {
21233 source: options.source,
21234 identityFields: options.identityFrom.fields,
21235 identity: options.identityFrom.identities || [],
21236 values: categoryValues,
21237 };
21238 if (!options.identityFrom.identities) {
21239 for (var categoryIndex = 0, categoryLength = categoryValues.length; categoryIndex < categoryLength; categoryIndex++) {
21240 categoryColumn.identity.push(getScopeIdentity(identityFrom, categoryIndex, categoryValues[categoryIndex], type));
21241 }
21242 }
21243 if (!this.categories)
21244 this.categories = [];
21245 this.categories.push(categoryColumn);
21246 return this;
21247 };
21248 CategoricalDataViewBuilder.prototype.withCategories = function (categories) {
21249 if (_.isEmpty(this.categories))
21250 this.categories = categories;
21251 else
21252 Array.prototype.push.apply(this.categories, categories);
21253 return this;
21254 };
21255 /**
21256 * Adds static series columns.
21257 *
21258 * Note that it is illegal to have both dynamic series and static series in a visual DataViewCategorical. It is only legal to have them both in
21259 * a query DataViewCategorical, where DataViewTransform is expected to split them up into separate visual DataViewCategorical objects.
21260 */
21261 CategoricalDataViewBuilder.prototype.withValues = function (options) {
21262 debug.assertValue(options, 'options');
21263 var columns = options.columns;
21264 debug.assertValue(columns, 'columns');
21265 for (var _i = 0, columns_8 = columns; _i < columns_8.length; _i++) {
21266 var column = columns_8[_i];
21267 this.staticMeasureColumns.push(column.source);
21268 }
21269 this.staticSeriesValues = columns;
21270 return this;
21271 };
21272 /**
21273 * Adds dynamic series columns.
21274 *
21275 * Note that it is illegal to have both dynamic series and static series in a visual DataViewCategorical. It is only legal to have them both in
21276 * a query DataViewCategorical, where DataViewTransform is expected to split them up into separate visual DataViewCategorical objects.
21277 */
21278 CategoricalDataViewBuilder.prototype.withGroupedValues = function (options) {
21279 debug.assertValue(options, 'options');
21280 var groupColumn = options.groupColumn;
21281 debug.assertValue(groupColumn, 'groupColumn');
21282 this.dynamicSeriesMetadata = {
21283 column: groupColumn.source,
21284 identityFrom: groupColumn.identityFrom,
21285 values: groupColumn.values,
21286 };
21287 var valueColumns = options.valueColumns;
21288 for (var _i = 0, valueColumns_1 = valueColumns; _i < valueColumns_1.length; _i++) {
21289 var valueColumn = valueColumns_1[_i];
21290 this.dynamicMeasureColumns.push(valueColumn.source);
21291 }
21292 this.dynamicSeriesValues = options.data;
21293 return this;
21294 };
21295 CategoricalDataViewBuilder.prototype.fillData = function (dataViewValues) {
21296 var categoryColumn = _.first(this.categories);
21297 var categoryLength = (categoryColumn && categoryColumn.values) ? categoryColumn.values.length : 1;
21298 if (this.hasDynamicSeries) {
21299 for (var seriesIndex = 0; seriesIndex < this.dynamicSeriesMetadata.values.length; seriesIndex++) {
21300 var seriesMeasures = this.dynamicSeriesValues[seriesIndex];
21301 debug.assert(seriesMeasures.length === this.dynamicMeasureColumns.length, 'seriesMeasures.length === this.dynamicMeasureColumns.length');
21302 for (var measureIndex = 0, measuresLen = this.dynamicMeasureColumns.length; measureIndex < measuresLen; measureIndex++) {
21303 var groupIndex = seriesIndex * measuresLen + measureIndex;
21304 applySeriesData(dataViewValues[groupIndex], seriesMeasures[measureIndex], categoryLength);
21305 }
21306 }
21307 }
21308 if (this.hasStaticSeries) {
21309 // Note: when the target categorical has both dynamic and static series, append static measures at the end of the values array.
21310 var staticColumnsStartingIndex = this.hasDynamicSeries ? (this.dynamicSeriesValues.length * this.dynamicMeasureColumns.length) : 0;
21311 for (var measureIndex = 0, measuresLen = this.staticMeasureColumns.length; measureIndex < measuresLen; measureIndex++) {
21312 applySeriesData(dataViewValues[staticColumnsStartingIndex + measureIndex], this.staticSeriesValues[measureIndex], categoryLength);
21313 }
21314 }
21315 };
21316 /**
21317 * Returns the DataView with metadata and DataViewCategorical.
21318 * Returns undefined if the combination of parameters is illegal, such as having both dynamic series and static series when building a visual DataView.
21319 */
21320 CategoricalDataViewBuilder.prototype.build = function () {
21321 var metadataColumns = [];
21322 var categorical = {};
21323 var categoryMetadata = this.categories;
21324 var dynamicSeriesMetadata = this.dynamicSeriesMetadata;
21325 // --- Build metadata columns and value groups ---
21326 for (var _i = 0, categoryMetadata_1 = categoryMetadata; _i < categoryMetadata_1.length; _i++) {
21327 var columnMetadata = categoryMetadata_1[_i];
21328 pushIfNotExists(metadataColumns, columnMetadata.source);
21329 }
21330 if (this.hasDynamicSeries) {
21331 // Dynamic series, or Dyanmic & Static series.
21332 pushIfNotExists(metadataColumns, dynamicSeriesMetadata.column);
21333 categorical.values = DataViewTransform.createValueColumns([], dynamicSeriesMetadata.identityFrom.fields, dynamicSeriesMetadata.column);
21334 // For each series value we will make one column per measure
21335 var seriesValues = dynamicSeriesMetadata.values;
21336 for (var seriesIndex = 0; seriesIndex < seriesValues.length; seriesIndex++) {
21337 var seriesValue = seriesValues[seriesIndex];
21338 var seriesIdentity = getScopeIdentity(dynamicSeriesMetadata.identityFrom, seriesIndex, seriesValue, dynamicSeriesMetadata.column.type);
21339 for (var _a = 0, _b = this.dynamicMeasureColumns; _a < _b.length; _a++) {
21340 var measure = _b[_a];
21341 var column = _.clone(measure);
21342 column.groupName = seriesValue;
21343 pushIfNotExists(metadataColumns, column);
21344 categorical.values.push({
21345 source: column,
21346 values: [],
21347 identity: seriesIdentity,
21348 });
21349 }
21350 }
21351 if (this.hasStaticSeries) {
21352 // IMPORTANT: In the Dyanmic & Static series case, the groups array shall not include any static group. This is to match the behavior of dsrReader.
21353 // Get the current return value of grouped() before adding static measure columns, an use that as the return value of this categorical.
21354 // Otherwise, the default behavior of DataViewValueColumns.grouped() from DataViewTransform.createValueColumns() is to create series groups from all measure columns.
21355 var dynamicSeriesGroups_1 = categorical.values.grouped();
21356 categorical.values.grouped = function () { return dynamicSeriesGroups_1; };
21357 this.appendStaticMeasureColumns(metadataColumns, categorical.values);
21358 }
21359 }
21360 else {
21361 // Static series only / no series
21362 categorical.values = DataViewTransform.createValueColumns();
21363 this.appendStaticMeasureColumns(metadataColumns, categorical.values);
21364 }
21365 var categories = this.categories;
21366 if (!_.isEmpty(categories))
21367 categorical.categories = categories;
21368 // --- Fill in data point values ---
21369 this.fillData(categorical.values);
21370 var dataView = {
21371 metadata: {
21372 columns: metadataColumns,
21373 },
21374 categorical: categorical,
21375 };
21376 if (this.isLegalDataView(dataView)) {
21377 return dataView;
21378 }
21379 };
21380 CategoricalDataViewBuilder.prototype.appendStaticMeasureColumns = function (metadataColumns, valueColumns) {
21381 debug.assertValue(metadataColumns, 'metadataColumns');
21382 debug.assertValue(valueColumns, 'valueColumns');
21383 if (!_.isEmpty(this.staticMeasureColumns)) {
21384 for (var _i = 0, _a = this.staticMeasureColumns; _i < _a.length; _i++) {
21385 var column = _a[_i];
21386 pushIfNotExists(metadataColumns, column);
21387 valueColumns.push({
21388 source: column,
21389 values: [],
21390 });
21391 }
21392 }
21393 };
21394 CategoricalDataViewBuilder.prototype.isLegalDataView = function (dataView) {
21395 if (this.hasDynamicSeries && this.hasStaticSeries && CategoricalDataViewBuilder.isVisualDataView(dataView.metadata.columns)) {
21396 // It is illegal to have both dynamic series and static series in a visual DataViewCategorical,
21397 // because the DataViewValueColumns interface today cannot express that 100% (see its 'source' property and return value of its 'grouped()' function).
21398 return false;
21399 }
21400 return true;
21401 };
21402 /**
21403 * This function infers that if any metdata column has 'queryName',
21404 * then the user of this builder is building a visual DataView (as opposed to query DataView).
21405 *
21406 * @param metadataColumns The complete collection of metadata columns in the categorical.
21407 */
21408 CategoricalDataViewBuilder.isVisualDataView = function (metadataColumns) {
21409 return !_.isEmpty(metadataColumns) &&
21410 _.any(metadataColumns, function (metadataColumn) { return !!metadataColumn.queryName; });
21411 };
21412 Object.defineProperty(CategoricalDataViewBuilder.prototype, "hasDynamicSeries", {
21413 get: function () {
21414 return !!this.dynamicSeriesMetadata; // In Map visual scenarios, you can have dynamic series without measure columns
21415 },
21416 enumerable: true,
21417 configurable: true
21418 });
21419 Object.defineProperty(CategoricalDataViewBuilder.prototype, "hasStaticSeries", {
21420 get: function () {
21421 return !!this.staticSeriesValues;
21422 },
21423 enumerable: true,
21424 configurable: true
21425 });
21426 return CategoricalDataViewBuilder;
21427 }());
21428 function getScopeIdentity(source, index, value, valueType) {
21429 var identities = source.identities;
21430 if (identities) {
21431 return identities[index];
21432 }
21433 debug.assert(source.fields && source.fields.length === 1, 'Inferring identity, expect exactly one field.');
21434 return data.createDataViewScopeIdentity(SQExprBuilder.equal(source.fields[0], SQExprBuilder.typedConstant(value, valueType)));
21435 }
21436 function pushIfNotExists(items, itemToAdd) {
21437 if (_.contains(items, itemToAdd))
21438 return;
21439 items.push(itemToAdd);
21440 }
21441 function applySeriesData(target, source, categoryLength) {
21442 debug.assertValue(target, 'target');
21443 debug.assertValue(source, 'source');
21444 debug.assertValue(categoryLength, 'categoryLength');
21445 var values = source.values;
21446 debug.assert(categoryLength === values.length, 'categoryLength === values.length');
21447 target.values = values;
21448 var highlights = source.highlights;
21449 if (highlights) {
21450 debug.assert(categoryLength === highlights.length, 'categoryLength === highlights.length');
21451 target.highlights = highlights;
21452 }
21453 var aggregates;
21454 if (source.minLocal !== undefined) {
21455 if (!aggregates)
21456 aggregates = {};
21457 aggregates.minLocal = source.minLocal;
21458 }
21459 if (source.maxLocal !== undefined) {
21460 if (!aggregates)
21461 aggregates = {};
21462 aggregates.maxLocal = source.maxLocal;
21463 }
21464 if (aggregates) {
21465 target.source.aggregates = aggregates;
21466 _.extend(target, aggregates);
21467 }
21468 }
21469 })(data = powerbi.data || (powerbi.data = {}));
21470})(powerbi || (powerbi = {}));
21471/*
21472 * Power BI Visualizations
21473 *
21474 * Copyright (c) Microsoft Corporation
21475 * All rights reserved.
21476 * MIT License
21477 *
21478 * Permission is hereby granted, free of charge, to any person obtaining a copy
21479 * of this software and associated documentation files (the ""Software""), to deal
21480 * in the Software without restriction, including without limitation the rights
21481 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21482 * copies of the Software, and to permit persons to whom the Software is
21483 * furnished to do so, subject to the following conditions:
21484 *
21485 * The above copyright notice and this permission notice shall be included in
21486 * all copies or substantial portions of the Software.
21487 *
21488 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21489 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21490 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21491 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21492 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21493 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21494 * THE SOFTWARE.
21495 */
21496var powerbi;
21497(function (powerbi) {
21498 var data;
21499 (function (data) {
21500 var SQExpr = powerbi.data.SQExpr;
21501 function createStaticEvalContext(colorAllocatorCache, dataView, selectTransforms) {
21502 return new StaticEvalContext(colorAllocatorCache || data.createColorAllocatorCache(), dataView || { metadata: { columns: [] } }, selectTransforms);
21503 }
21504 data.createStaticEvalContext = createStaticEvalContext;
21505 /**
21506 * Represents an eval context over a potentially empty DataView. Only static repetition data view objects
21507 * are supported.
21508 */
21509 var StaticEvalContext = (function () {
21510 function StaticEvalContext(colorAllocatorCache, dataView, selectTransforms) {
21511 debug.assertValue(colorAllocatorCache, 'colorAllocatorCache');
21512 debug.assertValue(dataView, 'dataView');
21513 debug.assertAnyValue(selectTransforms, 'selectTransforms');
21514 this.colorAllocatorCache = colorAllocatorCache;
21515 this.dataView = dataView;
21516 this.selectTransforms = selectTransforms;
21517 }
21518 StaticEvalContext.prototype.getColorAllocator = function (expr) {
21519 return this.colorAllocatorCache.get(expr);
21520 };
21521 StaticEvalContext.prototype.getExprValue = function (expr) {
21522 var dataView = this.dataView, selectTransforms = this.selectTransforms;
21523 if (dataView && dataView.table && selectTransforms)
21524 return getExprValueFromTable(expr, selectTransforms, dataView.table, /*rowIdx*/ 0);
21525 };
21526 StaticEvalContext.prototype.getRoleValue = function (roleName) {
21527 return;
21528 };
21529 return StaticEvalContext;
21530 }());
21531 function getExprValueFromTable(expr, selectTransforms, table, rowIdx) {
21532 debug.assertValue(expr, 'expr');
21533 debug.assertValue(selectTransforms, 'selectTransforms');
21534 debug.assertValue(table, 'table');
21535 debug.assertValue(rowIdx, 'rowIdx');
21536 var rows = table.rows;
21537 if (_.isEmpty(rows) || rows.length <= rowIdx)
21538 return;
21539 var targetExpr = getTargetExpr(expr, selectTransforms);
21540 var cols = table.columns;
21541 for (var selectIdx = 0, selectLen = selectTransforms.length; selectIdx < selectLen; selectIdx++) {
21542 var selectTransform = selectTransforms[selectIdx];
21543 if (!SQExpr.equals(selectTransform.expr, targetExpr) || !selectTransform.queryName)
21544 continue;
21545 for (var colIdx = 0, colLen = cols.length; colIdx < colLen; colIdx++) {
21546 if (selectIdx !== cols[colIdx].index)
21547 continue;
21548 return rows[rowIdx][colIdx];
21549 }
21550 }
21551 }
21552 data.getExprValueFromTable = getExprValueFromTable;
21553 function getTargetExpr(expr, selectTransforms) {
21554 if (SQExpr.isSelectRef(expr)) {
21555 for (var _i = 0, selectTransforms_2 = selectTransforms; _i < selectTransforms_2.length; _i++) {
21556 var selectTransform = selectTransforms_2[_i];
21557 if (selectTransform.queryName === expr.expressionName) {
21558 return selectTransform.expr;
21559 }
21560 }
21561 }
21562 return expr;
21563 }
21564 })(data = powerbi.data || (powerbi.data = {}));
21565})(powerbi || (powerbi = {}));
21566/*
21567 * Power BI Visualizations
21568 *
21569 * Copyright (c) Microsoft Corporation
21570 * All rights reserved.
21571 * MIT License
21572 *
21573 * Permission is hereby granted, free of charge, to any person obtaining a copy
21574 * of this software and associated documentation files (the ""Software""), to deal
21575 * in the Software without restriction, including without limitation the rights
21576 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21577 * copies of the Software, and to permit persons to whom the Software is
21578 * furnished to do so, subject to the following conditions:
21579 *
21580 * The above copyright notice and this permission notice shall be included in
21581 * all copies or substantial portions of the Software.
21582 *
21583 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21584 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21585 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21586 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21587 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21588 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21589 * THE SOFTWARE.
21590 */
21591var powerbi;
21592(function (powerbi) {
21593 var data;
21594 (function (data) {
21595 function createMatrixEvalContext(colorAllocatorProvider, dataViewMatrix) {
21596 // NOTE: Matrix context-sensitive evaluation is not yet implemented.
21597 return data.createStaticEvalContext(colorAllocatorProvider);
21598 }
21599 data.createMatrixEvalContext = createMatrixEvalContext;
21600 })(data = powerbi.data || (powerbi.data = {}));
21601})(powerbi || (powerbi = {}));
21602/*
21603 * Power BI Visualizations
21604 *
21605 * Copyright (c) Microsoft Corporation
21606 * All rights reserved.
21607 * MIT License
21608 *
21609 * Permission is hereby granted, free of charge, to any person obtaining a copy
21610 * of this software and associated documentation files (the ""Software""), to deal
21611 * in the Software without restriction, including without limitation the rights
21612 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21613 * copies of the Software, and to permit persons to whom the Software is
21614 * furnished to do so, subject to the following conditions:
21615 *
21616 * The above copyright notice and this permission notice shall be included in
21617 * all copies or substantial portions of the Software.
21618 *
21619 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21620 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21621 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21622 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21623 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21624 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21625 * THE SOFTWARE.
21626 */
21627var powerbi;
21628(function (powerbi_1) {
21629 var StringExtensions = jsCommon.StringExtensions;
21630 var Formatting = jsCommon.Formatting;
21631 var RegExpExtensions = jsCommon.RegExpExtensions;
21632 /** Formatting Encoder */
21633 var FormattingEncoder;
21634 (function (FormattingEncoder) {
21635 function preserveEscaped(format, specialChars) {
21636 // Unicode U+E000 - U+F8FF is a private area and so we can use the chars from the range to encode the escaped sequences
21637 var length = specialChars.length;
21638 for (var i = 0; i < length; i++) {
21639 var oldText = "\\" + specialChars[i];
21640 var newText = String.fromCharCode(0xE000 + i);
21641 format = StringExtensions.replaceAll(format, oldText, newText);
21642 }
21643 return format;
21644 }
21645 FormattingEncoder.preserveEscaped = preserveEscaped;
21646 function restoreEscaped(format, specialChars) {
21647 // After formatting is complete we should restore the encoded escaped chars into the unescaped chars
21648 var length = specialChars.length;
21649 for (var i = 0; i < length; i++) {
21650 var oldText = String.fromCharCode(0xE000 + i);
21651 var newText = specialChars[i];
21652 format = StringExtensions.replaceAll(format, oldText, newText);
21653 }
21654 return StringExtensions.replaceAll(format, "\\", "");
21655 }
21656 FormattingEncoder.restoreEscaped = restoreEscaped;
21657 function preserveLiterals(format, literals) {
21658 // Unicode U+E000 - U+F8FF is a private area and so we can use the chars from the range to encode the escaped sequences
21659 format = StringExtensions.replaceAll(format, "\"", "'");
21660 for (var i = 0;; i++) {
21661 var fromIndex = format.indexOf("'");
21662 if (fromIndex < 0) {
21663 break;
21664 }
21665 var toIndex = format.indexOf("'", fromIndex + 1);
21666 if (toIndex < 0) {
21667 break;
21668 }
21669 var literal = format.substring(fromIndex, toIndex + 1);
21670 literals.push(literal.substring(1, toIndex - fromIndex));
21671 var token = String.fromCharCode(0xE100 + i);
21672 format = format.replace(literal, token);
21673 }
21674 return format;
21675 }
21676 FormattingEncoder.preserveLiterals = preserveLiterals;
21677 function restoreLiterals(format, literals) {
21678 var count = literals.length;
21679 for (var i = 0; i < count; i++) {
21680 var token = String.fromCharCode(0xE100 + i);
21681 var literal = literals[i];
21682 format = format.replace(token, literal);
21683 }
21684 return format;
21685 }
21686 FormattingEncoder.restoreLiterals = restoreLiterals;
21687 })(FormattingEncoder || (FormattingEncoder = {}));
21688 var IndexedTokensRegex = /({{)|(}})|{(\d+[^}]*)}/g;
21689 var ZeroPlaceholder = '0';
21690 var DigitPlaceholder = '#';
21691 var ExponentialFormatChar = 'E';
21692 var NumericPlaceholders = [ZeroPlaceholder, DigitPlaceholder];
21693 var NumericPlaceholderRegex = new RegExp(NumericPlaceholders.join('|'), 'g');
21694 /** Formatting Service */
21695 var FormattingService = (function () {
21696 function FormattingService() {
21697 }
21698 FormattingService.prototype.formatValue = function (value, format, culture) {
21699 // Handle special cases
21700 if (value === undefined || value === null) {
21701 return '';
21702 }
21703 var gculture = this.getCulture(culture);
21704 if (DateTimeFormat.canFormat(value)) {
21705 // Dates
21706 return DateTimeFormat.format(value, format, gculture);
21707 }
21708 else if (NumberFormat.canFormat(value)) {
21709 // Numbers
21710 return NumberFormat.format(value, format, gculture);
21711 }
21712 else {
21713 // Other data types - return as string
21714 return value.toString();
21715 }
21716 };
21717 FormattingService.prototype.format = function (formatWithIndexedTokens, args, culture) {
21718 var _this = this;
21719 if (!formatWithIndexedTokens) {
21720 return "";
21721 }
21722 var result = formatWithIndexedTokens.replace(IndexedTokensRegex, function (match, left, right, argToken) {
21723 if (left) {
21724 return "{";
21725 }
21726 else if (right) {
21727 return "}";
21728 }
21729 else {
21730 var parts = argToken.split(":");
21731 var argIndex = parseInt(parts[0], 10);
21732 var argFormat = parts[1];
21733 return _this.formatValue(args[argIndex], argFormat, culture);
21734 }
21735 });
21736 return result;
21737 };
21738 FormattingService.prototype.isStandardNumberFormat = function (format) {
21739 return NumberFormat.isStandardFormat(format);
21740 };
21741 FormattingService.prototype.formatNumberWithCustomOverride = function (value, format, nonScientificOverrideFormat, culture) {
21742 var gculture = this.getCulture(culture);
21743 return NumberFormat.formatWithCustomOverride(value, format, nonScientificOverrideFormat, gculture);
21744 };
21745 FormattingService.prototype.dateFormatString = function (unit) {
21746 if (!this._dateTimeScaleFormatInfo)
21747 this.initialize();
21748 return this._dateTimeScaleFormatInfo.getFormatString(unit);
21749 };
21750 /**
21751 * Sets the current localization culture
21752 * @param cultureSelector - name of a culture: "en", "en-UK", "fr-FR" etc. (See National Language Support (NLS) for full lists. Use "default" for invariant culture).
21753 */
21754 FormattingService.prototype.setCurrentCulture = function (cultureSelector) {
21755 if (this._currentCultureSelector !== cultureSelector) {
21756 this._currentCulture = this.getCulture(cultureSelector);
21757 this._currentCultureSelector = cultureSelector;
21758 this._dateTimeScaleFormatInfo = new DateTimeScaleFormatInfo(this._currentCulture);
21759 }
21760 };
21761 /**
21762 * Gets the culture assotiated with the specified cultureSelector ("en", "en-US", "fr-FR" etc).
21763 * @param cultureSelector - name of a culture: "en", "en-UK", "fr-FR" etc. (See National Language Support (NLS) for full lists. Use "default" for invariant culture).
21764 * Exposing this function for testability of unsupported cultures
21765 */
21766 FormattingService.prototype.getCulture = function (cultureSelector) {
21767 if (cultureSelector == null) {
21768 if (this._currentCulture == null) {
21769 this.initialize();
21770 }
21771 return this._currentCulture;
21772 }
21773 else {
21774 var culture = Globalize.findClosestCulture(cultureSelector);
21775 if (!culture)
21776 culture = Globalize.culture("en-US");
21777 return culture;
21778 }
21779 };
21780 /** By default the Globalization module initializes to the culture/calendar provided in the language/culture URL params */
21781 FormattingService.prototype.initialize = function () {
21782 var cultureName = this.getCurrentCulture();
21783 this.setCurrentCulture(cultureName);
21784 var calendarName = this.getUrlParam("calendar");
21785 if (calendarName) {
21786 var culture = this._currentCulture;
21787 var c = culture.calendars[calendarName];
21788 if (c) {
21789 culture.calendar = c;
21790 }
21791 }
21792 };
21793 /**
21794 * Exposing this function for testability
21795 */
21796 FormattingService.prototype.getCurrentCulture = function () {
21797 var urlParam = this.getUrlParam("language");
21798 if (urlParam) {
21799 return urlParam;
21800 }
21801 if (powerbi && powerbi.common && powerbi.common.cultureInfo) {
21802 // Get cultureInfo set in powerbi
21803 return powerbi.common.cultureInfo;
21804 }
21805 return window.navigator.userLanguage || window.navigator["language"] || Globalize.culture().name;
21806 };
21807 /**
21808 * Exposing this function for testability
21809 * @param name: queryString name
21810 */
21811 FormattingService.prototype.getUrlParam = function (name) {
21812 var param = window.location.search.match(RegExp("[?&]" + name + "=([^&]*)"));
21813 return param ? param[1] : undefined;
21814 };
21815 return FormattingService;
21816 }());
21817 /**
21818 * DateTimeFormat module contains the static methods for formatting the DateTimes.
21819 * It extends the JQuery.Globalize functionality to support complete set of .NET
21820 * formatting expressions for dates.
21821 */
21822 var DateTimeFormat;
21823 (function (DateTimeFormat) {
21824 var _currentCachedFormat;
21825 var _currentCachedProcessedFormat;
21826 /** Evaluates if the value can be formatted using the NumberFormat */
21827 function canFormat(value) {
21828 var result = value instanceof Date;
21829 return result;
21830 }
21831 DateTimeFormat.canFormat = canFormat;
21832 /** Formats the date using provided format and culture */
21833 function format(value, format, culture) {
21834 format = format || "G";
21835 var isStandard = format.length === 1;
21836 try {
21837 if (isStandard) {
21838 return formatDateStandard(value, format, culture);
21839 }
21840 else {
21841 return formatDateCustom(value, format, culture);
21842 }
21843 }
21844 catch (e) {
21845 return formatDateStandard(value, "G", culture);
21846 }
21847 }
21848 DateTimeFormat.format = format;
21849 /** Formats the date using standard format expression */
21850 function formatDateStandard(value, format, culture) {
21851 // In order to provide parity with .NET we have to support additional set of DateTime patterns.
21852 var patterns = culture.calendar.patterns;
21853 // Extend supported set of patterns
21854 ensurePatterns(culture.calendar);
21855 // Handle extended set of formats
21856 var output = Formatting.findDateFormat(value, format, culture.name);
21857 if (output.format.length === 1)
21858 format = patterns[output.format];
21859 else
21860 format = output.format;
21861 //need to revisit when globalization is enabled
21862 culture = Globalize.culture("en-US");
21863 return Globalize.format(output.value, format, culture);
21864 }
21865 /** Formats the date using custom format expression */
21866 function formatDateCustom(value, format, culture) {
21867 var result;
21868 var literals = [];
21869 format = FormattingEncoder.preserveEscaped(format, "\\dfFghHKmstyz:/%'\"");
21870 format = FormattingEncoder.preserveLiterals(format, literals);
21871 format = StringExtensions.replaceAll(format, "\"", "'");
21872 if (format.indexOf("F") > -1) {
21873 // F is not supported so we need to replace the F with f based on the milliseconds
21874 // Replace all sequences of F longer than 3 with "FFF"
21875 format = StringExtensions.replaceAll(format, "FFFF", "FFF");
21876 // Based on milliseconds update the format to use fff
21877 var milliseconds = value.getMilliseconds();
21878 if (milliseconds % 10 >= 1) {
21879 format = StringExtensions.replaceAll(format, "FFF", "fff");
21880 }
21881 format = StringExtensions.replaceAll(format, "FFF", "FF");
21882 if ((milliseconds % 100) / 10 >= 1) {
21883 format = StringExtensions.replaceAll(format, "FF", "ff");
21884 }
21885 format = StringExtensions.replaceAll(format, "FF", "F");
21886 if ((milliseconds % 1000) / 100 >= 1) {
21887 format = StringExtensions.replaceAll(format, "F", "f");
21888 }
21889 format = StringExtensions.replaceAll(format, "F", "");
21890 if (format === "" || format === "%")
21891 return "";
21892 }
21893 format = processCustomDateTimeFormat(format);
21894 result = Globalize.format(value, format, culture);
21895 result = localize(result, culture.calendar);
21896 result = FormattingEncoder.restoreLiterals(result, literals);
21897 result = FormattingEncoder.restoreEscaped(result, "\\dfFghHKmstyz:/%'\"");
21898 return result;
21899 }
21900 /** Translates unsupported .NET custom format expressions to the custom expressions supported by JQuery.Globalize */
21901 function processCustomDateTimeFormat(format) {
21902 if (format === _currentCachedFormat) {
21903 return _currentCachedProcessedFormat;
21904 }
21905 _currentCachedFormat = format;
21906 format = Formatting.fixDateTimeFormat(format);
21907 _currentCachedProcessedFormat = format;
21908 return format;
21909 }
21910 /** Localizes the time separator symbol */
21911 function localize(value, dictionary) {
21912 var timeSeparator = dictionary[":"];
21913 if (timeSeparator === ":") {
21914 return value;
21915 }
21916 var result = "";
21917 var count = value.length;
21918 for (var i = 0; i < count; i++) {
21919 var char = value.charAt(i);
21920 switch (char) {
21921 case ":":
21922 result += timeSeparator;
21923 break;
21924 default:
21925 result += char;
21926 break;
21927 }
21928 }
21929 return result;
21930 }
21931 function ensurePatterns(calendar) {
21932 var patterns = calendar.patterns;
21933 if (patterns["g"] === undefined) {
21934 patterns["g"] = patterns["f"].replace(patterns["D"], patterns["d"]); // Generic: Short date, short time
21935 patterns["G"] = patterns["F"].replace(patterns["D"], patterns["d"]); // Generic: Short date, long time
21936 }
21937 }
21938 })(DateTimeFormat || (DateTimeFormat = {}));
21939 /**
21940 * NumberFormat module contains the static methods for formatting the numbers.
21941 * It extends the JQuery.Globalize functionality to support complete set of .NET
21942 * formatting expressions for numeric types including custom formats.
21943 */
21944 var NumberFormat;
21945 (function (NumberFormat) {
21946 var NonScientificFormatRegex = /^\{.+\}.*/;
21947 var NumericalPlaceHolderRegex = /\{.+\}/;
21948 var ScientificFormatRegex = /e[+-]*[0#]+/i;
21949 var StandardFormatRegex = /^[a-z]\d{0,2}$/i; // a letter + up to 2 digits for precision specifier
21950 var TrailingZerosRegex = /0+$/;
21951 var DecimalFormatRegex = /\.([0#]*)/g;
21952 var NumericFormatRegex = /[0#,\.]+[0,#]*/g;
21953 var LastNumericPlaceholderRegex = /(0|#)([^(0|#)]*)$/;
21954 var DecimalFormatCharacter = '.';
21955 NumberFormat.NumberFormatComponentsDelimeter = ';';
21956 function getNonScientificFormatWithPrecision(baseFormat, numericFormat) {
21957 if (!numericFormat || baseFormat === undefined)
21958 return baseFormat;
21959 var newFormat = "{0:" + numericFormat + "}";
21960 return baseFormat.replace("{0}", newFormat);
21961 }
21962 function getNumericFormat(value, baseFormat) {
21963 if (baseFormat == null)
21964 return baseFormat;
21965 if (hasFormatComponents(baseFormat)) {
21966 var _a = NumberFormat.getComponents(baseFormat), positive = _a.positive, negative = _a.negative, zero = _a.zero;
21967 if (value > 0)
21968 return getNumericFormatFromComponent(value, positive);
21969 else if (value === 0)
21970 return getNumericFormatFromComponent(value, zero);
21971 return getNumericFormatFromComponent(value, negative);
21972 }
21973 return getNumericFormatFromComponent(value, baseFormat);
21974 }
21975 NumberFormat.getNumericFormat = getNumericFormat;
21976 function getNumericFormatFromComponent(value, format) {
21977 var match = RegExpExtensions.run(NumericFormatRegex, format);
21978 if (match)
21979 return match[0];
21980 return format;
21981 }
21982 function addDecimalsToFormat(baseFormat, decimals, trailingZeros) {
21983 if (decimals == null)
21984 return baseFormat;
21985 // Default format string
21986 if (baseFormat == null)
21987 baseFormat = ZeroPlaceholder;
21988 if (hasFormatComponents(baseFormat)) {
21989 var _a = NumberFormat.getComponents(baseFormat), positive = _a.positive, negative = _a.negative, zero = _a.zero;
21990 var formats = [positive, negative, zero];
21991 for (var i = 0; i < formats.length; i++) {
21992 // Update format in formats array
21993 formats[i] = addDecimalsToFormatComponent(formats[i], decimals, trailingZeros);
21994 }
21995 return formats.join(NumberFormat.NumberFormatComponentsDelimeter);
21996 }
21997 return addDecimalsToFormatComponent(baseFormat, decimals, trailingZeros);
21998 }
21999 NumberFormat.addDecimalsToFormat = addDecimalsToFormat;
22000 function addDecimalsToFormatComponent(format, decimals, trailingZeros) {
22001 decimals = Math.abs(decimals);
22002 if (decimals >= 0) {
22003 var placeholder = trailingZeros ? ZeroPlaceholder : DigitPlaceholder;
22004 var decimalPlaceholders = StringExtensions.repeat(placeholder, Math.abs(decimals));
22005 var match = RegExpExtensions.run(DecimalFormatRegex, format);
22006 if (match) {
22007 var beforeDecimal = format.substr(0, match.index);
22008 var formatDecimal = format.substr(match.index + 1, match[1].length);
22009 var afterDecimal = format.substr(match.index + match[0].length);
22010 if (trailingZeros)
22011 // Use explicit decimals argument as placeholders
22012 formatDecimal = decimalPlaceholders;
22013 else {
22014 var decimalChange = decimalPlaceholders.length - formatDecimal.length;
22015 if (decimalChange > 0)
22016 // Append decimalPlaceholders to existing decimal portion of format string
22017 formatDecimal = formatDecimal + decimalPlaceholders.slice(-decimalChange);
22018 else if (decimalChange < 0)
22019 // Remove decimals from formatDecimal
22020 formatDecimal = formatDecimal.slice(0, decimalChange);
22021 }
22022 if (formatDecimal.length > 0)
22023 formatDecimal = DecimalFormatCharacter + formatDecimal;
22024 return beforeDecimal + formatDecimal + afterDecimal;
22025 }
22026 else if (decimalPlaceholders.length > 0)
22027 // Replace last numeric placeholder with decimal portion
22028 return format.replace(LastNumericPlaceholderRegex, '$1' + DecimalFormatCharacter + decimalPlaceholders);
22029 }
22030 return format;
22031 }
22032 function hasFormatComponents(format) {
22033 return format.indexOf(NumberFormat.NumberFormatComponentsDelimeter) !== -1;
22034 }
22035 NumberFormat.hasFormatComponents = hasFormatComponents;
22036 function getComponents(format) {
22037 var signFormat = {
22038 hasNegative: false,
22039 positive: format,
22040 negative: format,
22041 zero: format,
22042 };
22043 var signSpecificFormats = format.split(NumberFormat.NumberFormatComponentsDelimeter);
22044 var formatCount = signSpecificFormats.length;
22045 debug.assert(!(formatCount > 3), 'format string should be of form positive[;negative;zero]');
22046 if (formatCount > 1) {
22047 signFormat.hasNegative = true;
22048 signFormat.positive = signFormat.zero = signSpecificFormats[0];
22049 signFormat.negative = signSpecificFormats[1];
22050 if (formatCount > 2)
22051 signFormat.zero = signSpecificFormats[2];
22052 }
22053 return signFormat;
22054 }
22055 NumberFormat.getComponents = getComponents;
22056 var _lastCustomFormatMeta;
22057 /** Evaluates if the value can be formatted using the NumberFormat */
22058 function canFormat(value) {
22059 var result = typeof (value) === "number";
22060 return result;
22061 }
22062 NumberFormat.canFormat = canFormat;
22063 function isStandardFormat(format) {
22064 debug.assertValue(format, 'format');
22065 return StandardFormatRegex.test(format);
22066 }
22067 NumberFormat.isStandardFormat = isStandardFormat;
22068 /** Formats the number using specified format expression and culture */
22069 function format(value, format, culture) {
22070 format = format || "G";
22071 try {
22072 if (isStandardFormat(format))
22073 return formatNumberStandard(value, format, culture);
22074 return formatNumberCustom(value, format, culture);
22075 }
22076 catch (e) {
22077 return Globalize.format(value, undefined, culture);
22078 }
22079 }
22080 NumberFormat.format = format;
22081 /** Performs a custom format with a value override. Typically used for custom formats showing scaled values. */
22082 function formatWithCustomOverride(value, format, nonScientificOverrideFormat, culture) {
22083 debug.assertValue(value, 'value');
22084 debug.assertValue(format, 'format');
22085 debug.assertValue(nonScientificOverrideFormat, 'nonScientificOverrideFormat');
22086 debug.assertValue(culture, 'culture');
22087 debug.assert(!isStandardFormat(format), 'Standard format');
22088 return formatNumberCustom(value, format, culture, nonScientificOverrideFormat);
22089 }
22090 NumberFormat.formatWithCustomOverride = formatWithCustomOverride;
22091 /** Formats the number using standard format expression */
22092 function formatNumberStandard(value, format, culture) {
22093 var result;
22094 var precision = (format.length > 1 ? parseInt(format.substr(1, format.length - 1), 10) : undefined);
22095 var numberFormatInfo = culture.numberFormat;
22096 var formatChar = format.charAt(0);
22097 switch (formatChar) {
22098 case "e":
22099 case "E":
22100 if (precision === undefined) {
22101 precision = 6;
22102 }
22103 var mantissaDecimalDigits = StringExtensions.repeat("0", precision);
22104 format = "0." + mantissaDecimalDigits + formatChar + "+000";
22105 result = formatNumberCustom(value, format, culture);
22106 break;
22107 case "f":
22108 case "F":
22109 result = precision !== undefined ? value.toFixed(precision) : value.toFixed(numberFormatInfo.decimals);
22110 result = localize(result, numberFormatInfo);
22111 break;
22112 case "g":
22113 case "G":
22114 var abs = Math.abs(value);
22115 if (abs === 0 || (1E-4 <= abs && abs < 1E15)) {
22116 // For the range of 0.0001 to 1,000,000,000,000,000 - use the normal form
22117 result = precision !== undefined ? value.toPrecision(precision) : value.toString();
22118 }
22119 else {
22120 // Otherwise use exponential
22121 // Assert that value is a number and fall back on returning value if it is not
22122 debug.assert(typeof (value) === "number", "value must be a number");
22123 if (typeof (value) !== "number")
22124 return String(value);
22125 result = precision !== undefined ? value.toExponential(precision) : value.toExponential();
22126 result = result.replace("e", "E");
22127 }
22128 result = localize(result, numberFormatInfo);
22129 break;
22130 case "r":
22131 case "R":
22132 result = value.toString();
22133 result = localize(result, numberFormatInfo);
22134 break;
22135 case "x":
22136 case "X":
22137 result = value.toString(16);
22138 if (formatChar === "X") {
22139 result = result.toUpperCase();
22140 }
22141 if (precision !== undefined) {
22142 var actualPrecision = result.length;
22143 var isNegative = value < 0;
22144 if (isNegative) {
22145 actualPrecision--;
22146 }
22147 var paddingZerosCount = precision - actualPrecision;
22148 var paddingZeros = undefined;
22149 if (paddingZerosCount > 0) {
22150 paddingZeros = StringExtensions.repeat("0", paddingZerosCount);
22151 }
22152 if (isNegative) {
22153 result = "-" + paddingZeros + result.substr(1);
22154 }
22155 else {
22156 result = paddingZeros + result;
22157 }
22158 }
22159 result = localize(result, numberFormatInfo);
22160 break;
22161 default:
22162 result = Globalize.format(value, format, culture);
22163 }
22164 return result;
22165 }
22166 /** Formats the number using custom format expression */
22167 function formatNumberCustom(value, format, culture, nonScientificOverrideFormat) {
22168 var result;
22169 var numberFormatInfo = culture.numberFormat;
22170 if (isFinite(value)) {
22171 // Split format by positive[;negative;zero] pattern
22172 var formatComponents = getComponents(format);
22173 // Pick a format based on the sign of value
22174 if (value > 0) {
22175 format = formatComponents.positive;
22176 }
22177 else if (value === 0) {
22178 format = formatComponents.zero;
22179 }
22180 else {
22181 format = formatComponents.negative;
22182 }
22183 // Normalize value if we have an explicit negative format
22184 if (formatComponents.hasNegative)
22185 value = Math.abs(value);
22186 // Get format metadata
22187 var formatMeta = getCustomFormatMetadata(format, true /*calculatePrecision*/);
22188 // Preserve literals and escaped chars
22189 if (formatMeta.hasEscapes) {
22190 format = FormattingEncoder.preserveEscaped(format, "\\0#.,%‰");
22191 }
22192 var literals = [];
22193 if (formatMeta.hasQuotes) {
22194 format = FormattingEncoder.preserveLiterals(format, literals);
22195 }
22196 // Scientific format
22197 if (formatMeta.hasE && !nonScientificOverrideFormat) {
22198 var scientificMatch = RegExpExtensions.run(ScientificFormatRegex, format);
22199 if (scientificMatch) {
22200 // Case 2.1. Scientific custom format
22201 var formatM = format.substr(0, scientificMatch.index);
22202 var formatE = format.substr(scientificMatch.index + 2); // E(+|-)
22203 var precision = getCustomFormatPrecision(formatM, formatMeta);
22204 var scale = getCustomFormatScale(formatM, formatMeta);
22205 if (scale !== 1) {
22206 value = value * scale;
22207 }
22208 // Assert that value is a number and fall back on returning value if it is not
22209 debug.assert(typeof (value) === "number", "value must be a number");
22210 if (typeof (value) !== "number")
22211 return String(value);
22212 var s = value.toExponential(precision);
22213 var indexOfE = s.indexOf("e");
22214 var mantissa = s.substr(0, indexOfE);
22215 var exp = s.substr(indexOfE + 1);
22216 var resultM = fuseNumberWithCustomFormat(mantissa, formatM, numberFormatInfo);
22217 var resultE = fuseNumberWithCustomFormat(exp, formatE, numberFormatInfo);
22218 if (resultE.charAt(0) === "+" && scientificMatch[0].charAt(1) !== "+") {
22219 resultE = resultE.substr(1);
22220 }
22221 var e = scientificMatch[0].charAt(0);
22222 result = resultM + e + resultE;
22223 }
22224 }
22225 // Non scientific format
22226 if (result === undefined) {
22227 var valueFormatted = void 0;
22228 var isValueGlobalized = false;
22229 var precision = getCustomFormatPrecision(format, formatMeta);
22230 var scale = getCustomFormatScale(format, formatMeta);
22231 if (scale !== 1)
22232 value = value * scale;
22233 // Rounding
22234 value = parseFloat(toNonScientific(value, precision));
22235 if (nonScientificOverrideFormat) {
22236 // Get numeric format from format string
22237 var numericFormat = NumberFormat.getNumericFormat(value, format);
22238 // Add separators and decimalFormat to nonScientificFormat
22239 nonScientificOverrideFormat = getNonScientificFormatWithPrecision(nonScientificOverrideFormat, numericFormat);
22240 // Format the value
22241 valueFormatted = powerbi_1.formattingService.format(nonScientificOverrideFormat, [value], culture.name);
22242 isValueGlobalized = true;
22243 }
22244 else
22245 valueFormatted = toNonScientific(value, precision);
22246 result = fuseNumberWithCustomFormat(valueFormatted, format, numberFormatInfo, nonScientificOverrideFormat, isValueGlobalized);
22247 }
22248 if (formatMeta.hasQuotes) {
22249 result = FormattingEncoder.restoreLiterals(result, literals);
22250 }
22251 if (formatMeta.hasEscapes) {
22252 result = FormattingEncoder.restoreEscaped(result, "\\0#.,%‰");
22253 }
22254 _lastCustomFormatMeta = formatMeta;
22255 }
22256 else {
22257 return Globalize.format(value, undefined);
22258 }
22259 return result;
22260 }
22261 /** Returns string with the fixed point respresentation of the number */
22262 function toNonScientific(value, precision) {
22263 var result = "";
22264 var precisionZeros = 0;
22265 // Double precision numbers support actual 15-16 decimal digits of precision.
22266 if (precision > 16) {
22267 precisionZeros = precision - 16;
22268 precision = 16;
22269 }
22270 var digitsBeforeDecimalPoint = powerbi_1.Double.log10(Math.abs(value));
22271 if (digitsBeforeDecimalPoint < 16) {
22272 if (digitsBeforeDecimalPoint > 0) {
22273 var maxPrecision = 16 - digitsBeforeDecimalPoint;
22274 if (precision > maxPrecision) {
22275 precisionZeros += precision - maxPrecision;
22276 precision = maxPrecision;
22277 }
22278 }
22279 result = value.toFixed(precision);
22280 }
22281 else if (digitsBeforeDecimalPoint === 16) {
22282 result = value.toFixed(0);
22283 precisionZeros += precision;
22284 if (precisionZeros > 0) {
22285 result += ".";
22286 }
22287 }
22288 else {
22289 // Different browsers have different implementations of the toFixed().
22290 // In IE it returns fixed format no matter what's the number. In FF and Chrome the method returns exponential format for numbers greater than 1E21.
22291 // So we need to check for range and convert the to exponential with the max precision.
22292 // Then we convert exponential string to fixed by removing the dot and padding with "power" zeros.
22293 // Assert that value is a number and fall back on returning value if it is not
22294 debug.assert(typeof (value) === "number", "value must be a number");
22295 if (typeof (value) !== "number")
22296 return String(value);
22297 result = value.toExponential(15);
22298 var indexOfE = result.indexOf("e");
22299 if (indexOfE > 0) {
22300 var indexOfDot = result.indexOf(".");
22301 var mantissa = result.substr(0, indexOfE);
22302 var exp = result.substr(indexOfE + 1);
22303 var powerZeros = parseInt(exp, 10) - (mantissa.length - indexOfDot - 1);
22304 result = mantissa.replace(".", "") + StringExtensions.repeat("0", powerZeros);
22305 if (precision > 0) {
22306 result = result + "." + StringExtensions.repeat("0", precision);
22307 }
22308 }
22309 }
22310 if (precisionZeros > 0) {
22311 result = result + StringExtensions.repeat("0", precisionZeros);
22312 }
22313 return result;
22314 }
22315 /**
22316 * Returns the formatMetadata of the format
22317 * When calculating precision and scale, if format string of
22318 * positive[;negative;zero] => positive format will be used
22319 * @param (required) format - format string
22320 * @param (optional) calculatePrecision - calculate precision of positive format
22321 * @param (optional) calculateScale - calculate scale of positive format
22322 */
22323 function getCustomFormatMetadata(format, calculatePrecision, calculateScale) {
22324 if (_lastCustomFormatMeta !== undefined && format === _lastCustomFormatMeta.format) {
22325 return _lastCustomFormatMeta;
22326 }
22327 var result = {
22328 format: format,
22329 hasEscapes: false,
22330 hasQuotes: false,
22331 hasE: false,
22332 hasCommas: false,
22333 hasDots: false,
22334 hasPercent: false,
22335 hasPermile: false,
22336 precision: undefined,
22337 scale: undefined,
22338 };
22339 for (var i = 0, length_1 = format.length; i < length_1; i++) {
22340 var c = format.charAt(i);
22341 switch (c) {
22342 case "\\":
22343 result.hasEscapes = true;
22344 break;
22345 case "'":
22346 case "\"":
22347 result.hasQuotes = true;
22348 break;
22349 case "e":
22350 case "E":
22351 result.hasE = true;
22352 break;
22353 case ",":
22354 result.hasCommas = true;
22355 break;
22356 case ".":
22357 result.hasDots = true;
22358 break;
22359 case "%":
22360 result.hasPercent = true;
22361 break;
22362 case "‰":
22363 result.hasPermile = true;
22364 break;
22365 }
22366 }
22367 // Use positive format for calculating these values
22368 var formatComponents = getComponents(format);
22369 if (calculatePrecision)
22370 result.precision = getCustomFormatPrecision(formatComponents.positive, result);
22371 if (calculateScale)
22372 result.scale = getCustomFormatScale(formatComponents.positive, result);
22373 return result;
22374 }
22375 NumberFormat.getCustomFormatMetadata = getCustomFormatMetadata;
22376 /** Returns the decimal precision of format based on the number of # and 0 chars after the decimal point
22377 * Important: The input format string needs to be split to the appropriate pos/neg/zero portion to work correctly */
22378 function getCustomFormatPrecision(format, formatMeta) {
22379 if (formatMeta.precision > -1) {
22380 return formatMeta.precision;
22381 }
22382 var result = 0;
22383 if (formatMeta.hasDots) {
22384 var dotIndex = format.indexOf(".");
22385 if (dotIndex > -1) {
22386 var count = format.length;
22387 for (var i = dotIndex; i < count; i++) {
22388 var char = format.charAt(i);
22389 if (char.match(NumericPlaceholderRegex))
22390 result++;
22391 // 0.00E+0 :: Break before counting 0 in
22392 // exponential portion of format string
22393 if (char === ExponentialFormatChar)
22394 break;
22395 }
22396 result = Math.min(19, result);
22397 }
22398 }
22399 formatMeta.precision = result;
22400 return result;
22401 }
22402 /** Returns the scale factor of the format based on the "%" and scaling "," chars in the format */
22403 function getCustomFormatScale(format, formatMeta) {
22404 if (formatMeta.scale > -1) {
22405 return formatMeta.scale;
22406 }
22407 var result = 1;
22408 if (formatMeta.hasPercent && format.indexOf("%") > -1) {
22409 result = result * 100;
22410 }
22411 if (formatMeta.hasPermile && format.indexOf("‰") > -1) {
22412 result = result * 1000;
22413 }
22414 if (formatMeta.hasCommas) {
22415 var dotIndex = format.indexOf(".");
22416 if (dotIndex === -1) {
22417 dotIndex = format.length;
22418 }
22419 for (var i = dotIndex - 1; i > -1; i--) {
22420 var char = format.charAt(i);
22421 if (char === ",") {
22422 result = result / 1000;
22423 }
22424 else {
22425 break;
22426 }
22427 }
22428 }
22429 formatMeta.scale = result;
22430 return result;
22431 }
22432 function fuseNumberWithCustomFormat(value, format, numberFormatInfo, nonScientificOverrideFormat, isValueGlobalized) {
22433 var suppressModifyValue = !!nonScientificOverrideFormat;
22434 var formatParts = format.split(".", 2);
22435 if (formatParts.length === 2) {
22436 var wholeFormat = formatParts[0];
22437 var fractionFormat = formatParts[1];
22438 var displayUnit = "";
22439 // Remove display unit from value before splitting on "." as localized display units sometimes end with "."
22440 if (nonScientificOverrideFormat) {
22441 debug.assert(NonScientificFormatRegex.test(nonScientificOverrideFormat), "Number should always precede the display unit");
22442 displayUnit = nonScientificOverrideFormat.replace(NumericalPlaceHolderRegex, "");
22443 value = value.replace(displayUnit, "");
22444 }
22445 var globalizedDecimalSeparator = numberFormatInfo["."];
22446 var decimalSeparator = isValueGlobalized ? globalizedDecimalSeparator : ".";
22447 var valueParts = value.split(decimalSeparator, 2);
22448 var wholeValue = valueParts.length === 1 ? valueParts[0] + displayUnit : valueParts[0];
22449 var fractionValue = valueParts.length === 2 ? valueParts[1] + displayUnit : "";
22450 fractionValue = fractionValue.replace(TrailingZerosRegex, "");
22451 var wholeFormattedValue = fuseNumberWithCustomFormatLeft(wholeValue, wholeFormat, numberFormatInfo, suppressModifyValue);
22452 var fractionFormattedValue = fuseNumberWithCustomFormatRight(fractionValue, fractionFormat, suppressModifyValue);
22453 if (fractionFormattedValue.fmtOnly || fractionFormattedValue.value === "")
22454 return wholeFormattedValue + fractionFormattedValue.value;
22455 return wholeFormattedValue + globalizedDecimalSeparator + fractionFormattedValue.value;
22456 }
22457 return fuseNumberWithCustomFormatLeft(value, format, numberFormatInfo, suppressModifyValue);
22458 }
22459 function fuseNumberWithCustomFormatLeft(value, format, numberFormatInfo, suppressModifyValue) {
22460 var groupSymbolIndex = format.indexOf(",");
22461 var enableGroups = groupSymbolIndex > -1 && groupSymbolIndex < Math.max(format.lastIndexOf("0"), format.lastIndexOf("#")) && numberFormatInfo[","];
22462 var groupDigitCount = 0;
22463 var groupIndex = 0;
22464 var groupSizes = numberFormatInfo.groupSizes || [3];
22465 var groupSize = groupSizes[0];
22466 var groupSeparator = numberFormatInfo[","];
22467 var sign = "";
22468 var firstChar = value.charAt(0);
22469 if (firstChar === "+" || firstChar === "-") {
22470 sign = numberFormatInfo[firstChar];
22471 value = value.substr(1);
22472 }
22473 var isZero = value === "0";
22474 var result = "";
22475 var leftBuffer = "";
22476 var vi = value.length - 1;
22477 var fmtOnly = true;
22478 // Iterate through format chars and replace 0 and # with the digits from the value string
22479 for (var fi = format.length - 1; fi > -1; fi--) {
22480 var formatChar = format.charAt(fi);
22481 switch (formatChar) {
22482 case ZeroPlaceholder:
22483 case DigitPlaceholder:
22484 fmtOnly = false;
22485 if (leftBuffer !== "") {
22486 result = leftBuffer + result;
22487 leftBuffer = "";
22488 }
22489 if (!suppressModifyValue) {
22490 if (vi > -1 || formatChar === ZeroPlaceholder) {
22491 if (enableGroups) {
22492 // If the groups are enabled we'll need to keep track of the current group index and periodically insert group separator,
22493 if (groupDigitCount === groupSize) {
22494 result = groupSeparator + result;
22495 groupIndex++;
22496 if (groupIndex < groupSizes.length) {
22497 groupSize = groupSizes[groupIndex];
22498 }
22499 groupDigitCount = 1;
22500 }
22501 else {
22502 groupDigitCount++;
22503 }
22504 }
22505 }
22506 if (vi > -1) {
22507 if (isZero && formatChar === DigitPlaceholder) {
22508 }
22509 else {
22510 result = value.charAt(vi) + result;
22511 }
22512 vi--;
22513 }
22514 else if (formatChar !== DigitPlaceholder) {
22515 result = formatChar + result;
22516 }
22517 }
22518 break;
22519 case ",":
22520 // We should skip all the , chars
22521 break;
22522 default:
22523 leftBuffer = formatChar + leftBuffer;
22524 break;
22525 }
22526 }
22527 // If the value didn't fit into the number of zeros provided in the format then we should insert the missing part of the value into the result
22528 if (!suppressModifyValue) {
22529 if (vi > -1 && result !== "") {
22530 if (enableGroups) {
22531 while (vi > -1) {
22532 if (groupDigitCount === groupSize) {
22533 result = groupSeparator + result;
22534 groupIndex++;
22535 if (groupIndex < groupSizes.length) {
22536 groupSize = groupSizes[groupIndex];
22537 }
22538 groupDigitCount = 1;
22539 }
22540 else {
22541 groupDigitCount++;
22542 }
22543 result = value.charAt(vi) + result;
22544 vi--;
22545 }
22546 }
22547 else {
22548 result = value.substr(0, vi + 1) + result;
22549 }
22550 }
22551 // Insert sign in front of the leftBuffer and result
22552 return sign + leftBuffer + result;
22553 }
22554 if (fmtOnly)
22555 // If the format doesn't specify any digits to be displayed, then just return the format we've parsed up until now.
22556 return sign + leftBuffer + result;
22557 return sign + leftBuffer + value + result;
22558 }
22559 function fuseNumberWithCustomFormatRight(value, format, suppressModifyValue) {
22560 var vi = 0;
22561 var fCount = format.length;
22562 var vCount = value.length;
22563 if (suppressModifyValue) {
22564 debug.assert(fCount > 0, "Empty formatting string");
22565 var lastChar = format.charAt(fCount - 1);
22566 if (!lastChar.match(NumericPlaceholderRegex))
22567 return {
22568 value: value + lastChar,
22569 fmtOnly: value === "",
22570 };
22571 return {
22572 value: value,
22573 fmtOnly: value === "",
22574 };
22575 }
22576 var result = "", fmtOnly = true;
22577 for (var fi = 0; fi < fCount; fi++) {
22578 var formatChar = format.charAt(fi);
22579 if (vi < vCount) {
22580 switch (formatChar) {
22581 case ZeroPlaceholder:
22582 case DigitPlaceholder:
22583 result += value[vi++];
22584 fmtOnly = false;
22585 break;
22586 default:
22587 result += formatChar;
22588 }
22589 }
22590 else {
22591 if (formatChar !== DigitPlaceholder) {
22592 result += formatChar;
22593 fmtOnly = fmtOnly && (formatChar !== ZeroPlaceholder);
22594 }
22595 }
22596 }
22597 return {
22598 value: result,
22599 fmtOnly: fmtOnly,
22600 };
22601 }
22602 function localize(value, dictionary) {
22603 var plus = dictionary["+"];
22604 var minus = dictionary["-"];
22605 var dot = dictionary["."];
22606 var comma = dictionary[","];
22607 if (plus === "+" && minus === "-" && dot === "." && comma === ",") {
22608 return value;
22609 }
22610 var count = value.length;
22611 var result = "";
22612 for (var i = 0; i < count; i++) {
22613 var char = value.charAt(i);
22614 switch (char) {
22615 case "+":
22616 result = result + plus;
22617 break;
22618 case "-":
22619 result = result + minus;
22620 break;
22621 case ".":
22622 result = result + dot;
22623 break;
22624 case ",":
22625 result = result + comma;
22626 break;
22627 default:
22628 result = result + char;
22629 break;
22630 }
22631 }
22632 return result;
22633 }
22634 })(NumberFormat = powerbi_1.NumberFormat || (powerbi_1.NumberFormat = {}));
22635 /** DateTimeScaleFormatInfo is used to calculate and keep the Date formats used for different units supported by the DateTimeScaleModel */
22636 var DateTimeScaleFormatInfo = (function () {
22637 // Constructor
22638 /**
22639 * Creates new instance of the DateTimeScaleFormatInfo class.
22640 * @param culture - culture which calendar info is going to be used to derive the formats.
22641 */
22642 function DateTimeScaleFormatInfo(culture) {
22643 var calendar = culture.calendar;
22644 var patterns = calendar.patterns;
22645 var monthAbbreviations = calendar["months"]["namesAbbr"];
22646 var cultureHasMonthAbbr = monthAbbreviations && monthAbbreviations[0];
22647 var yearMonthPattern = patterns["Y"];
22648 var monthDayPattern = patterns["M"];
22649 var fullPattern = patterns["f"];
22650 var longTimePattern = patterns["T"];
22651 var shortTimePattern = patterns["t"];
22652 var separator = fullPattern.indexOf(",") > -1 ? ", " : " ";
22653 var hasYearSymbol = yearMonthPattern.indexOf("yyyy'") === 0 && yearMonthPattern.length > 6 && yearMonthPattern[6] === '\'';
22654 this.YearPattern = hasYearSymbol ? yearMonthPattern.substr(0, 7) : "yyyy";
22655 var yearPos = fullPattern.indexOf("yy");
22656 var monthPos = fullPattern.indexOf("MMMM");
22657 this.MonthPattern = cultureHasMonthAbbr && monthPos > -1 ? (yearPos > monthPos ? "MMM yyyy" : "yyyy MMM") : yearMonthPattern;
22658 this.DayPattern = cultureHasMonthAbbr ? monthDayPattern.replace("MMMM", "MMM") : monthDayPattern;
22659 var minutePos = fullPattern.indexOf("mm");
22660 var pmPos = fullPattern.indexOf("tt");
22661 var shortHourPattern = pmPos > -1 ? shortTimePattern.replace(":mm ", "") : shortTimePattern;
22662 this.HourPattern = yearPos < minutePos ? this.DayPattern + separator + shortHourPattern : shortHourPattern + separator + this.DayPattern;
22663 this.MinutePattern = shortTimePattern;
22664 this.SecondPattern = longTimePattern;
22665 this.MillisecondPattern = longTimePattern.replace("ss", "ss.fff");
22666 // Special cases
22667 switch (culture.name) {
22668 case "fi-FI":
22669 this.DayPattern = this.DayPattern.replace("'ta'", ""); // Fix for finish 'ta' suffix for month names.
22670 this.HourPattern = this.HourPattern.replace("'ta'", "");
22671 break;
22672 }
22673 }
22674 // Methods
22675 /**
22676 * Returns the format string of the provided DateTimeUnit.
22677 * @param unit - date or time unit
22678 */
22679 DateTimeScaleFormatInfo.prototype.getFormatString = function (unit) {
22680 switch (unit) {
22681 case powerbi_1.DateTimeUnit.Year:
22682 return this.YearPattern;
22683 case powerbi_1.DateTimeUnit.Month:
22684 return this.MonthPattern;
22685 case powerbi_1.DateTimeUnit.Week:
22686 case powerbi_1.DateTimeUnit.Day:
22687 return this.DayPattern;
22688 case powerbi_1.DateTimeUnit.Hour:
22689 return this.HourPattern;
22690 case powerbi_1.DateTimeUnit.Minute:
22691 return this.MinutePattern;
22692 case powerbi_1.DateTimeUnit.Second:
22693 return this.SecondPattern;
22694 case powerbi_1.DateTimeUnit.Millisecond:
22695 return this.MillisecondPattern;
22696 }
22697 debug.assertFail('Unexpected unit: ' + unit);
22698 };
22699 return DateTimeScaleFormatInfo;
22700 }());
22701 powerbi_1.formattingService = new FormattingService();
22702})(powerbi || (powerbi = {}));
22703/*
22704 * Power BI Visualizations
22705 *
22706 * Copyright (c) Microsoft Corporation
22707 * All rights reserved.
22708 * MIT License
22709 *
22710 * Permission is hereby granted, free of charge, to any person obtaining a copy
22711 * of this software and associated documentation files (the ""Software""), to deal
22712 * in the Software without restriction, including without limitation the rights
22713 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22714 * copies of the Software, and to permit persons to whom the Software is
22715 * furnished to do so, subject to the following conditions:
22716 *
22717 * The above copyright notice and this permission notice shall be included in
22718 * all copies or substantial portions of the Software.
22719 *
22720 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22721 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22722 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22723 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22724 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22725 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22726 * THE SOFTWARE.
22727 */
22728var powerbi;
22729(function (powerbi) {
22730 var data;
22731 (function (data) {
22732 /** Serializes SQExpr in a form optimized in-memory comparison, but not intended for storage on disk. */
22733 var SQExprShortSerializer;
22734 (function (SQExprShortSerializer) {
22735 function serialize(expr) {
22736 return JSON.stringify(expr.accept(SQExprSerializer.instance));
22737 }
22738 SQExprShortSerializer.serialize = serialize;
22739 function serializeArray(exprs) {
22740 var str = '[';
22741 for (var i = 0, len = exprs.length; i < len; i++) {
22742 if (i > 0)
22743 str += ',';
22744 str += SQExprShortSerializer.serialize(exprs[i]);
22745 }
22746 return str + ']';
22747 }
22748 SQExprShortSerializer.serializeArray = serializeArray;
22749 /** Responsible for serializing an SQExpr into a comparable string. */
22750 var SQExprSerializer = (function (_super) {
22751 __extends(SQExprSerializer, _super);
22752 function SQExprSerializer() {
22753 _super.apply(this, arguments);
22754 }
22755 SQExprSerializer.prototype.visitColumnRef = function (expr) {
22756 return {
22757 col: {
22758 s: expr.source.accept(this),
22759 r: expr.ref,
22760 }
22761 };
22762 };
22763 SQExprSerializer.prototype.visitMeasureRef = function (expr) {
22764 return {
22765 measure: {
22766 s: expr.source.accept(this),
22767 r: expr.ref,
22768 }
22769 };
22770 };
22771 SQExprSerializer.prototype.visitAggr = function (expr) {
22772 return {
22773 agg: {
22774 a: expr.arg.accept(this),
22775 f: expr.func,
22776 }
22777 };
22778 };
22779 SQExprSerializer.prototype.visitEntity = function (expr) {
22780 debug.assertValue(expr, 'expr');
22781 debug.assertValue(expr.entity, 'expr.entity');
22782 return {
22783 e: expr.entity
22784 };
22785 };
22786 SQExprSerializer.prototype.visitHierarchyLevel = function (expr) {
22787 return {
22788 h: expr.arg.accept(this),
22789 l: expr.level,
22790 };
22791 };
22792 SQExprSerializer.prototype.visitHierarchy = function (expr) {
22793 return {
22794 e: expr.arg.accept(this),
22795 h: expr.hierarchy,
22796 };
22797 };
22798 SQExprSerializer.prototype.visitPropertyVariationSource = function (expr) {
22799 return {
22800 e: expr.arg.accept(this),
22801 n: expr.name,
22802 p: expr.property,
22803 };
22804 };
22805 SQExprSerializer.prototype.visitAnd = function (expr) {
22806 debug.assertValue(expr, 'expr');
22807 return {
22808 and: {
22809 l: expr.left.accept(this),
22810 r: expr.right.accept(this),
22811 }
22812 };
22813 };
22814 SQExprSerializer.prototype.visitCompare = function (expr) {
22815 debug.assertValue(expr, 'expr');
22816 return {
22817 comp: {
22818 k: expr.comparison,
22819 l: expr.left.accept(this),
22820 r: expr.right.accept(this),
22821 }
22822 };
22823 };
22824 SQExprSerializer.prototype.visitConstant = function (expr) {
22825 debug.assertValue(expr, 'expr');
22826 return {
22827 const: {
22828 t: expr.type.primitiveType,
22829 v: expr.value,
22830 }
22831 };
22832 };
22833 SQExprSerializer.prototype.visitArithmetic = function (expr) {
22834 debug.assertValue(expr, 'expr');
22835 return {
22836 arithmetic: {
22837 o: expr.operator,
22838 l: expr.left.accept(this),
22839 r: expr.right.accept(this)
22840 }
22841 };
22842 };
22843 SQExprSerializer.prototype.visitScopedEval = function (expr) {
22844 debug.assertValue(expr, 'expr');
22845 return {
22846 scopedEval: {
22847 e: expr.expression.accept(this),
22848 s: serializeArray(expr.scope)
22849 }
22850 };
22851 };
22852 SQExprSerializer.prototype.visitDefault = function (expr) {
22853 debug.assertFail('Unexpected expression type found in DataViewScopeIdentity.');
22854 return;
22855 };
22856 SQExprSerializer.instance = new SQExprSerializer();
22857 return SQExprSerializer;
22858 }(data.DefaultSQExprVisitor));
22859 })(SQExprShortSerializer = data.SQExprShortSerializer || (data.SQExprShortSerializer = {}));
22860 })(data = powerbi.data || (powerbi.data = {}));
22861})(powerbi || (powerbi = {}));
22862/*
22863 * Power BI Visualizations
22864 *
22865 * Copyright (c) Microsoft Corporation
22866 * All rights reserved.
22867 * MIT License
22868 *
22869 * Permission is hereby granted, free of charge, to any person obtaining a copy
22870 * of this software and associated documentation files (the ""Software""), to deal
22871 * in the Software without restriction, including without limitation the rights
22872 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22873 * copies of the Software, and to permit persons to whom the Software is
22874 * furnished to do so, subject to the following conditions:
22875 *
22876 * The above copyright notice and this permission notice shall be included in
22877 * all copies or substantial portions of the Software.
22878 *
22879 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22880 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22881 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22882 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22883 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22884 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22885 * THE SOFTWARE.
22886 */
22887var powerbi;
22888(function (powerbi) {
22889 var visuals;
22890 (function (visuals) {
22891 var Selector = powerbi.data.Selector;
22892 /**
22893 * A combination of identifiers used to uniquely identify
22894 * data points and their bound geometry.
22895 */
22896 var SelectionId = (function () {
22897 function SelectionId(selector, highlight) {
22898 this.selector = selector;
22899 this.highlight = highlight;
22900 this.key = JSON.stringify({ selector: selector ? Selector.getKey(selector) : null, highlight: highlight });
22901 this.keyWithoutHighlight = JSON.stringify({ selector: selector ? Selector.getKey(selector) : null });
22902 }
22903 SelectionId.prototype.equals = function (other) {
22904 if (!this.selector || !other.selector) {
22905 return (!this.selector === !other.selector) && this.highlight === other.highlight;
22906 }
22907 return this.highlight === other.highlight && Selector.equals(this.selector, other.selector);
22908 };
22909 /**
22910 * Checks equality against other for all identifiers existing in this.
22911 */
22912 SelectionId.prototype.includes = function (other, ignoreHighlight) {
22913 if (ignoreHighlight === void 0) { ignoreHighlight = false; }
22914 var thisSelector = this.selector;
22915 var otherSelector = other.selector;
22916 if (!thisSelector || !otherSelector) {
22917 return false;
22918 }
22919 var thisData = thisSelector.data;
22920 var otherData = otherSelector.data;
22921 if (!thisData && (thisSelector.metadata && thisSelector.metadata !== otherSelector.metadata))
22922 return false;
22923 if (!ignoreHighlight && this.highlight !== other.highlight)
22924 return false;
22925 if (thisData) {
22926 if (!otherData)
22927 return false;
22928 if (thisData.length > 0) {
22929 for (var i = 0, ilen = thisData.length; i < ilen; i++) {
22930 var thisValue = thisData[i];
22931 if (!otherData.some(function (otherValue) { return powerbi.DataViewScopeIdentity.equals(thisValue, otherValue); }))
22932 return false;
22933 }
22934 }
22935 }
22936 return true;
22937 };
22938 SelectionId.prototype.getKey = function () {
22939 return this.key;
22940 };
22941 SelectionId.prototype.getKeyWithoutHighlight = function () {
22942 return this.keyWithoutHighlight;
22943 };
22944 SelectionId.prototype.hasIdentity = function () {
22945 return (this.selector && !!this.selector.data);
22946 };
22947 SelectionId.prototype.getSelector = function () {
22948 return this.selector;
22949 };
22950 SelectionId.prototype.getSelectorsByColumn = function () {
22951 return this.selectorsByColumn;
22952 };
22953 SelectionId.createNull = function (highlight) {
22954 if (highlight === void 0) { highlight = false; }
22955 return new SelectionId(null, highlight);
22956 };
22957 SelectionId.createWithId = function (id, highlight) {
22958 if (highlight === void 0) { highlight = false; }
22959 var selector = null;
22960 if (id) {
22961 selector = {
22962 data: [id]
22963 };
22964 }
22965 return new SelectionId(selector, highlight);
22966 };
22967 SelectionId.createWithMeasure = function (measureId, highlight) {
22968 if (highlight === void 0) { highlight = false; }
22969 debug.assertValue(measureId, 'measureId');
22970 var selector = {
22971 metadata: measureId
22972 };
22973 var selectionId = new SelectionId(selector, highlight);
22974 selectionId.selectorsByColumn = { metadata: measureId };
22975 return selectionId;
22976 };
22977 SelectionId.createWithIdAndMeasure = function (id, measureId, highlight) {
22978 if (highlight === void 0) { highlight = false; }
22979 var selector = {};
22980 if (id) {
22981 selector.data = [id];
22982 }
22983 if (measureId)
22984 selector.metadata = measureId;
22985 if (!id && !measureId)
22986 selector = null;
22987 var selectionId = new SelectionId(selector, highlight);
22988 return selectionId;
22989 };
22990 SelectionId.createWithIdAndMeasureAndCategory = function (id, measureId, queryName, highlight) {
22991 if (highlight === void 0) { highlight = false; }
22992 var selectionId = this.createWithIdAndMeasure(id, measureId, highlight);
22993 if (selectionId.selector) {
22994 selectionId.selectorsByColumn = {};
22995 if (id && queryName) {
22996 selectionId.selectorsByColumn.dataMap = {};
22997 selectionId.selectorsByColumn.dataMap[queryName] = id;
22998 }
22999 if (measureId)
23000 selectionId.selectorsByColumn.metadata = measureId;
23001 }
23002 return selectionId;
23003 };
23004 SelectionId.createWithIds = function (id1, id2, highlight) {
23005 if (highlight === void 0) { highlight = false; }
23006 var selector = null;
23007 var selectorData = SelectionId.idArray(id1, id2);
23008 if (selectorData)
23009 selector = { data: selectorData };
23010 return new SelectionId(selector, highlight);
23011 };
23012 SelectionId.createWithIdsAndMeasure = function (id1, id2, measureId, highlight) {
23013 if (highlight === void 0) { highlight = false; }
23014 var selector = {};
23015 var selectorData = SelectionId.idArray(id1, id2);
23016 if (selectorData)
23017 selector.data = selectorData;
23018 if (measureId)
23019 selector.metadata = measureId;
23020 if (!id1 && !id2 && !measureId)
23021 selector = null;
23022 return new SelectionId(selector, highlight);
23023 };
23024 SelectionId.createWithSelectorForColumnAndMeasure = function (dataMap, measureId, highlight) {
23025 if (highlight === void 0) { highlight = false; }
23026 var selectionId;
23027 var keys = Object.keys(dataMap);
23028 if (keys.length === 2) {
23029 selectionId = this.createWithIdsAndMeasure(dataMap[keys[0]], dataMap[keys[1]], measureId, highlight);
23030 }
23031 else if (keys.length === 1) {
23032 selectionId = this.createWithIdsAndMeasure(dataMap[keys[0]], null, measureId, highlight);
23033 }
23034 else {
23035 selectionId = this.createWithIdsAndMeasure(null, null, measureId, highlight);
23036 }
23037 var selectorsByColumn = {};
23038 if (!_.isEmpty(dataMap))
23039 selectorsByColumn.dataMap = dataMap;
23040 if (measureId)
23041 selectorsByColumn.metadata = measureId;
23042 if (!dataMap && !measureId)
23043 selectorsByColumn = null;
23044 selectionId.selectorsByColumn = selectorsByColumn;
23045 return selectionId;
23046 };
23047 SelectionId.createWithHighlight = function (original) {
23048 debug.assertValue(original, 'original');
23049 debug.assert(!original.highlight, '!original.highlight');
23050 var newId = new SelectionId(original.getSelector(), /*highlight*/ true);
23051 newId.selectorsByColumn = original.selectorsByColumn;
23052 return newId;
23053 };
23054 SelectionId.idArray = function (id1, id2) {
23055 if (id1 || id2) {
23056 var data_4 = [];
23057 if (id1)
23058 data_4.push(id1);
23059 if (id2 && id2 !== id1)
23060 data_4.push(id2);
23061 return data_4;
23062 }
23063 };
23064 return SelectionId;
23065 }());
23066 visuals.SelectionId = SelectionId;
23067 /**
23068 * This class is designed to simplify the creation of SelectionId objects
23069 * It allows chaining to build up an object before calling 'create' to build a SelectionId
23070 */
23071 var SelectionIdBuilder = (function () {
23072 function SelectionIdBuilder() {
23073 }
23074 SelectionIdBuilder.builder = function () {
23075 return new SelectionIdBuilder();
23076 };
23077 SelectionIdBuilder.prototype.withCategory = function (categoryColumn, index) {
23078 if (categoryColumn && categoryColumn.source && categoryColumn.source.queryName && categoryColumn.identity)
23079 this.ensureDataMap()[categoryColumn.source.queryName] = categoryColumn.identity[index];
23080 return this;
23081 };
23082 SelectionIdBuilder.prototype.withSeries = function (seriesColumn, valueColumn) {
23083 if (seriesColumn && seriesColumn.source && seriesColumn.source.queryName && valueColumn)
23084 this.ensureDataMap()[seriesColumn.source.queryName] = valueColumn.identity;
23085 return this;
23086 };
23087 SelectionIdBuilder.prototype.withMeasure = function (measureId) {
23088 this.measure = measureId;
23089 return this;
23090 };
23091 SelectionIdBuilder.prototype.createSelectionId = function () {
23092 return SelectionId.createWithSelectorForColumnAndMeasure(this.ensureDataMap(), this.measure);
23093 };
23094 SelectionIdBuilder.prototype.ensureDataMap = function () {
23095 if (!this.dataMap)
23096 this.dataMap = {};
23097 return this.dataMap;
23098 };
23099 return SelectionIdBuilder;
23100 }());
23101 visuals.SelectionIdBuilder = SelectionIdBuilder;
23102 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
23103})(powerbi || (powerbi = {}));
23104
23105
23106;var __extends = (this && this.__extends) || function (d, b) {
23107 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
23108 function __() { this.constructor = d; }
23109 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
23110};
23111/*
23112 * Power BI Visualizations
23113 *
23114 * Copyright (c) Microsoft Corporation
23115 * All rights reserved.
23116 * MIT License
23117 *
23118 * Permission is hereby granted, free of charge, to any person obtaining a copy
23119 * of this software and associated documentation files (the ""Software""), to deal
23120 * in the Software without restriction, including without limitation the rights
23121 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23122 * copies of the Software, and to permit persons to whom the Software is
23123 * furnished to do so, subject to the following conditions:
23124 *
23125 * The above copyright notice and this permission notice shall be included in
23126 * all copies or substantial portions of the Software.
23127 *
23128 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23129 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23130 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23131 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23132 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23133 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23134 * THE SOFTWARE.
23135 */
23136///<reference path="../../Typedefs/d3/d3.d.ts"/>
23137///<reference path="../../Typedefs/jquery-visible/jquery-visible.d.ts"/>
23138///<reference path="../../Typedefs/jquery/jquery.d.ts"/>
23139///<reference path="../../Typedefs/microsoftMaps/Microsoft.Maps.d.ts" />
23140///<reference path="../../Typedefs/moment/moment.d.ts"/>
23141///<reference path="../../Typedefs/velocity/velocity-animate.d.ts"/>
23142///<reference path="../../Typedefs/lodash/lodash.d.ts"/>
23143///<reference path="../../Typedefs/quill/quill.d.ts"/>
23144///<reference path="../../Typedefs/ie/ie.d.ts"/>
23145///<reference path="../../Typedefs/noUiSlider/noUiSlider.d.ts"/>
23146///<reference path="../../Typedefs/jquery.scrollbar/jquery.scrollbar.d.ts"/>
23147/*
23148 * Power BI Visualizations
23149 *
23150 * Copyright (c) Microsoft Corporation
23151 * All rights reserved.
23152 * MIT License
23153 *
23154 * Permission is hereby granted, free of charge, to any person obtaining a copy
23155 * of this software and associated documentation files (the ""Software""), to deal
23156 * in the Software without restriction, including without limitation the rights
23157 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23158 * copies of the Software, and to permit persons to whom the Software is
23159 * furnished to do so, subject to the following conditions:
23160 *
23161 * The above copyright notice and this permission notice shall be included in
23162 * all copies or substantial portions of the Software.
23163 *
23164 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23165 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23166 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23167 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23168 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23169 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23170 * THE SOFTWARE.
23171 */
23172var powerbi;
23173(function (powerbi) {
23174 var visuals;
23175 (function (visuals) {
23176 var Point = (function () {
23177 function Point(x, y) {
23178 this.x = x || 0;
23179 this.y = y || 0;
23180 }
23181 return Point;
23182 }());
23183 visuals.Point = Point;
23184 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
23185})(powerbi || (powerbi = {}));
23186/*
23187 * Power BI Visualizations
23188 *
23189 * Copyright (c) Microsoft Corporation
23190 * All rights reserved.
23191 * MIT License
23192 *
23193 * Permission is hereby granted, free of charge, to any person obtaining a copy
23194 * of this software and associated documentation files (the ""Software""), to deal
23195 * in the Software without restriction, including without limitation the rights
23196 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23197 * copies of the Software, and to permit persons to whom the Software is
23198 * furnished to do so, subject to the following conditions:
23199 *
23200 * The above copyright notice and this permission notice shall be included in
23201 * all copies or substantial portions of the Software.
23202 *
23203 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23204 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23205 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23206 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23207 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23208 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23209 * THE SOFTWARE.
23210 */
23211var powerbi;
23212(function (powerbi) {
23213 var visuals;
23214 (function (visuals) {
23215 var Rect = (function () {
23216 // Constructor
23217 function Rect(left, top, width, height) {
23218 this.left = left || 0;
23219 this.top = top || 0;
23220 this.width = width || 0;
23221 this.height = height || 0;
23222 }
23223 return Rect;
23224 }());
23225 visuals.Rect = Rect;
23226 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
23227})(powerbi || (powerbi = {}));
23228/*
23229 * Power BI Visualizations
23230 *
23231 * Copyright (c) Microsoft Corporation
23232 * All rights reserved.
23233 * MIT License
23234 *
23235 * Permission is hereby granted, free of charge, to any person obtaining a copy
23236 * of this software and associated documentation files (the ""Software""), to deal
23237 * in the Software without restriction, including without limitation the rights
23238 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23239 * copies of the Software, and to permit persons to whom the Software is
23240 * furnished to do so, subject to the following conditions:
23241 *
23242 * The above copyright notice and this permission notice shall be included in
23243 * all copies or substantial portions of the Software.
23244 *
23245 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23246 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23247 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23248 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23249 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23250 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23251 * THE SOFTWARE.
23252 */
23253var powerbi;
23254(function (powerbi) {
23255 var visuals;
23256 (function (visuals) {
23257 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
23258 var PixelConverter = jsCommon.PixelConverter;
23259 (function (LegendIcon) {
23260 LegendIcon[LegendIcon["Box"] = 0] = "Box";
23261 LegendIcon[LegendIcon["Circle"] = 1] = "Circle";
23262 LegendIcon[LegendIcon["Line"] = 2] = "Line";
23263 })(visuals.LegendIcon || (visuals.LegendIcon = {}));
23264 var LegendIcon = visuals.LegendIcon;
23265 (function (LegendPosition) {
23266 LegendPosition[LegendPosition["Top"] = 0] = "Top";
23267 LegendPosition[LegendPosition["Bottom"] = 1] = "Bottom";
23268 LegendPosition[LegendPosition["Right"] = 2] = "Right";
23269 LegendPosition[LegendPosition["Left"] = 3] = "Left";
23270 LegendPosition[LegendPosition["None"] = 4] = "None";
23271 LegendPosition[LegendPosition["TopCenter"] = 5] = "TopCenter";
23272 LegendPosition[LegendPosition["BottomCenter"] = 6] = "BottomCenter";
23273 LegendPosition[LegendPosition["RightCenter"] = 7] = "RightCenter";
23274 LegendPosition[LegendPosition["LeftCenter"] = 8] = "LeftCenter";
23275 })(visuals.LegendPosition || (visuals.LegendPosition = {}));
23276 var LegendPosition = visuals.LegendPosition;
23277 visuals.legendProps = {
23278 show: 'show',
23279 position: 'position',
23280 titleText: 'titleText',
23281 showTitle: 'showTitle',
23282 labelColor: 'labelColor',
23283 fontSize: 'fontSize',
23284 };
23285 function createLegend(legendParentElement, interactive, interactivityService, isScrollable, legendPosition) {
23286 if (isScrollable === void 0) { isScrollable = false; }
23287 if (legendPosition === void 0) { legendPosition = LegendPosition.Top; }
23288 if (interactive)
23289 return new CartesianChartInteractiveLegend(legendParentElement);
23290 else
23291 return new SVGLegend(legendParentElement, legendPosition, interactivityService, isScrollable);
23292 }
23293 visuals.createLegend = createLegend;
23294 var Legend;
23295 (function (Legend) {
23296 function isLeft(orientation) {
23297 switch (orientation) {
23298 case LegendPosition.Left:
23299 case LegendPosition.LeftCenter:
23300 return true;
23301 default:
23302 return false;
23303 }
23304 }
23305 Legend.isLeft = isLeft;
23306 function isTop(orientation) {
23307 switch (orientation) {
23308 case LegendPosition.Top:
23309 case LegendPosition.TopCenter:
23310 return true;
23311 default:
23312 return false;
23313 }
23314 }
23315 Legend.isTop = isTop;
23316 function positionChartArea(chartArea, legend) {
23317 var legendMargins = legend.getMargins();
23318 var legendOrientation = legend.getOrientation();
23319 chartArea.style({
23320 'margin-left': Legend.isLeft(legendOrientation) ? legendMargins.width + 'px' : null,
23321 'margin-top': Legend.isTop(legendOrientation) ? legendMargins.height + 'px' : null,
23322 });
23323 }
23324 Legend.positionChartArea = positionChartArea;
23325 })(Legend = visuals.Legend || (visuals.Legend = {}));
23326 var SVGLegend = (function () {
23327 function SVGLegend(element, legendPosition, interactivityService, isScrollable) {
23328 this.legendDataStartIndex = 0;
23329 this.arrowPosWindow = 1;
23330 this.lastCalculatedWidth = 0;
23331 this.visibleLegendWidth = 0;
23332 this.visibleLegendHeight = 0;
23333 this.legendFontSizeMarginDifference = 0;
23334 this.legendFontSizeMarginValue = 0;
23335 this.svg = d3.select(element.get(0)).append('svg').style('position', 'absolute');
23336 this.svg.style('display', 'inherit');
23337 this.svg.classed('legend', true);
23338 if (interactivityService)
23339 this.clearCatcher = visuals.appendClearCatcher(this.svg);
23340 this.group = this.svg.append('g').attr('id', 'legendGroup');
23341 this.interactivityService = interactivityService;
23342 this.isScrollable = isScrollable;
23343 this.element = element;
23344 this.changeOrientation(legendPosition);
23345 this.parentViewport = { height: 0, width: 0 };
23346 this.calculateViewport();
23347 this.updateLayout();
23348 }
23349 SVGLegend.prototype.updateLayout = function () {
23350 var legendViewport = this.viewport;
23351 var orientation = this.orientation;
23352 this.svg.attr({
23353 'height': legendViewport.height || (orientation === LegendPosition.None ? 0 : this.parentViewport.height),
23354 'width': legendViewport.width || (orientation === LegendPosition.None ? 0 : this.parentViewport.width)
23355 });
23356 var isRight = orientation === LegendPosition.Right || orientation === LegendPosition.RightCenter;
23357 var isBottom = orientation === LegendPosition.Bottom || orientation === LegendPosition.BottomCenter;
23358 this.svg.style({
23359 'margin-left': isRight ? (this.parentViewport.width - legendViewport.width) + 'px' : null,
23360 'margin-top': isBottom ? (this.parentViewport.height - legendViewport.height) + 'px' : null,
23361 });
23362 };
23363 SVGLegend.prototype.calculateViewport = function () {
23364 switch (this.orientation) {
23365 case LegendPosition.Top:
23366 case LegendPosition.Bottom:
23367 case LegendPosition.TopCenter:
23368 case LegendPosition.BottomCenter:
23369 var pixelHeight = PixelConverter.fromPointToPixel(this.data && this.data.fontSize ? this.data.fontSize : SVGLegend.DefaultFontSizeInPt);
23370 var fontHeightSize = SVGLegend.TopLegendHeight + (pixelHeight - SVGLegend.DefaultFontSizeInPt);
23371 this.viewport = { height: fontHeightSize, width: 0 };
23372 return;
23373 case LegendPosition.Right:
23374 case LegendPosition.Left:
23375 case LegendPosition.RightCenter:
23376 case LegendPosition.LeftCenter:
23377 var width = this.lastCalculatedWidth ? this.lastCalculatedWidth : this.parentViewport.width * SVGLegend.LegendMaxWidthFactor;
23378 this.viewport = { height: 0, width: width };
23379 return;
23380 case LegendPosition.None:
23381 this.viewport = { height: 0, width: 0 };
23382 }
23383 };
23384 SVGLegend.prototype.getMargins = function () {
23385 return this.viewport;
23386 };
23387 SVGLegend.prototype.isVisible = function () {
23388 return this.orientation !== LegendPosition.None;
23389 };
23390 SVGLegend.prototype.changeOrientation = function (orientation) {
23391 if (orientation) {
23392 this.orientation = orientation;
23393 }
23394 else {
23395 this.orientation = LegendPosition.Top;
23396 }
23397 this.svg.attr('orientation', orientation);
23398 };
23399 SVGLegend.prototype.getOrientation = function () {
23400 return this.orientation;
23401 };
23402 SVGLegend.prototype.drawLegend = function (data, viewport) {
23403 // clone because we modify legend item label with ellipsis if it is truncated
23404 var clonedData = powerbi.Prototype.inherit(data);
23405 var newDataPoints = [];
23406 for (var _i = 0, _a = data.dataPoints; _i < _a.length; _i++) {
23407 var dp = _a[_i];
23408 newDataPoints.push(powerbi.Prototype.inherit(dp));
23409 }
23410 clonedData.dataPoints = newDataPoints;
23411 this.setTooltipToLegendItems(clonedData);
23412 this.drawLegendInternal(clonedData, viewport, true /* perform auto width */);
23413 };
23414 SVGLegend.prototype.drawLegendInternal = function (data, viewport, autoWidth) {
23415 this.parentViewport = viewport;
23416 this.data = data;
23417 if (this.interactivityService)
23418 this.interactivityService.applySelectionStateToData(data.dataPoints);
23419 if (data.dataPoints.length === 0) {
23420 this.changeOrientation(LegendPosition.None);
23421 }
23422 if (this.getOrientation() === LegendPosition.None) {
23423 data.dataPoints = [];
23424 }
23425 // Adding back the workaround for Legend Left/Right position for Map
23426 var mapControl = this.element.children(".mapControl");
23427 if (mapControl.length > 0 && !this.isTopOrBottom(this.orientation)) {
23428 mapControl.css("display", "inline-block");
23429 }
23430 this.calculateViewport();
23431 var layout = this.calculateLayout(data, autoWidth);
23432 var titleLayout = layout.title;
23433 var titleData = titleLayout ? [titleLayout] : [];
23434 var hasSelection = this.interactivityService && powerbi.visuals.dataHasSelection(data.dataPoints);
23435 var group = this.group;
23436 //transform the wrapping group if position is centered
23437 if (this.isCentered(this.orientation)) {
23438 var centerOffset = 0;
23439 if (this.isTopOrBottom(this.orientation)) {
23440 centerOffset = Math.max(0, (this.parentViewport.width - this.visibleLegendWidth) / 2);
23441 group.attr('transform', visuals.SVGUtil.translate(centerOffset, 0));
23442 }
23443 else {
23444 centerOffset = Math.max((this.parentViewport.height - this.visibleLegendHeight) / 2);
23445 group.attr('transform', visuals.SVGUtil.translate(0, centerOffset));
23446 }
23447 }
23448 else {
23449 group.attr('transform', null);
23450 }
23451 var legendTitle = group
23452 .selectAll(SVGLegend.LegendTitle.selector)
23453 .data(titleData);
23454 legendTitle.enter()
23455 .append('text')
23456 .classed(SVGLegend.LegendTitle.class, true);
23457 legendTitle
23458 .style({
23459 'fill': data.labelColor,
23460 'font-size': PixelConverter.fromPoint(data.fontSize),
23461 'font-family': SVGLegend.DefaultTitleFontFamily
23462 })
23463 .text(function (d) { return d.text; })
23464 .attr({
23465 'x': function (d) { return d.x; },
23466 'y': function (d) { return d.y; }
23467 })
23468 .append('title').text(data.title);
23469 legendTitle.exit().remove();
23470 var virtualizedDataPoints = data.dataPoints.slice(this.legendDataStartIndex, this.legendDataStartIndex + layout.numberOfItems);
23471 var iconRadius = powerbi.TextMeasurementService.estimateSvgTextHeight(SVGLegend.getTextProperties(false, '', this.data.fontSize)) / SVGLegend.LegendIconRadiusFactor;
23472 iconRadius = (this.legendFontSizeMarginValue > SVGLegend.DefaultTextMargin) && iconRadius > SVGLegend.LegendIconRadius
23473 ? iconRadius :
23474 SVGLegend.LegendIconRadius;
23475 var legendItems = group
23476 .selectAll(SVGLegend.LegendItem.selector)
23477 .data(virtualizedDataPoints, function (d) { return d.identity.getKey() + (d.layerNumber != null ? d.layerNumber : ''); });
23478 var itemsEnter = legendItems.enter()
23479 .append('g')
23480 .classed(SVGLegend.LegendItem.class, true);
23481 itemsEnter
23482 .append('circle')
23483 .classed(SVGLegend.LegendIcon.class, true);
23484 itemsEnter
23485 .append('text')
23486 .classed(SVGLegend.LegendText.class, true);
23487 itemsEnter
23488 .append('title')
23489 .text(function (d) { return d.tooltip; });
23490 itemsEnter
23491 .style({
23492 'font-family': SVGLegend.DefaultFontFamily
23493 });
23494 legendItems
23495 .select(SVGLegend.LegendIcon.selector)
23496 .attr({
23497 'cx': function (d, i) { return d.glyphPosition.x; },
23498 'cy': function (d) { return d.glyphPosition.y; },
23499 'r': iconRadius,
23500 })
23501 .style({
23502 'fill': function (d) {
23503 if (hasSelection && !d.selected)
23504 return visuals.LegendBehavior.dimmedLegendColor;
23505 else
23506 return d.color;
23507 }
23508 });
23509 legendItems
23510 .select('title')
23511 .text(function (d) { return d.tooltip; });
23512 legendItems
23513 .select(SVGLegend.LegendText.selector)
23514 .attr({
23515 'x': function (d) { return d.textPosition.x; },
23516 'y': function (d) { return d.textPosition.y; },
23517 })
23518 .text(function (d) { return d.label; })
23519 .style({
23520 'fill': data.labelColor,
23521 'font-size': PixelConverter.fromPoint(data.fontSize)
23522 });
23523 if (this.interactivityService) {
23524 var iconsSelection = legendItems.select(SVGLegend.LegendIcon.selector);
23525 var behaviorOptions = {
23526 legendItems: legendItems,
23527 legendIcons: iconsSelection,
23528 clearCatcher: this.clearCatcher,
23529 };
23530 this.interactivityService.bind(data.dataPoints, new visuals.LegendBehavior(), behaviorOptions, { isLegend: true });
23531 }
23532 legendItems.exit().remove();
23533 this.drawNavigationArrows(layout.navigationArrows);
23534 this.updateLayout();
23535 };
23536 SVGLegend.prototype.normalizePosition = function (points) {
23537 if (this.legendDataStartIndex >= points.length) {
23538 this.legendDataStartIndex = points.length - 1;
23539 }
23540 if (this.legendDataStartIndex < 0) {
23541 this.legendDataStartIndex = 0;
23542 }
23543 };
23544 SVGLegend.prototype.calculateTitleLayout = function (title) {
23545 var width = 0;
23546 var hasTitle = !_.isEmpty(title);
23547 if (hasTitle) {
23548 var isHorizontal = this.isTopOrBottom(this.orientation);
23549 var maxMeasureLength = void 0;
23550 if (isHorizontal) {
23551 var fontSizeMargin = this.legendFontSizeMarginValue > SVGLegend.DefaultTextMargin ? SVGLegend.TextAndIconPadding + this.legendFontSizeMarginDifference : SVGLegend.TextAndIconPadding;
23552 var fixedHorizontalIconShift = SVGLegend.TextAndIconPadding + SVGLegend.LegendIconRadius;
23553 var fixedHorizontalTextShift = SVGLegend.LegendIconRadius + fontSizeMargin + fixedHorizontalIconShift;
23554 // TODO This can be negative for narrow viewports. May need to rework this logic.
23555 maxMeasureLength = this.parentViewport.width * SVGLegend.LegendMaxWidthFactor - fixedHorizontalTextShift - SVGLegend.LegendEdgeMariginWidth;
23556 }
23557 else {
23558 maxMeasureLength = this.legendFontSizeMarginValue < SVGLegend.DefaultTextMargin ? SVGLegend.MaxTitleLength :
23559 SVGLegend.MaxTitleLength + (SVGLegend.DefaultMaxLegendFactor * this.legendFontSizeMarginDifference);
23560 }
23561 var textProperties = SVGLegend.getTextProperties(true, title, this.data.fontSize);
23562 var text = title;
23563 width = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
23564 if (width > maxMeasureLength) {
23565 text = powerbi.TextMeasurementService.getTailoredTextOrDefault(textProperties, maxMeasureLength);
23566 textProperties.text = text;
23567 // Remeasure the text since its measurement may be different than the max (ex. when the max is negative, the text will be ellipsis, and not have a negative width)
23568 width = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
23569 }
23570 ;
23571 if (isHorizontal)
23572 width += SVGLegend.TitlePadding;
23573 else
23574 text = powerbi.TextMeasurementService.getTailoredTextOrDefault(textProperties, this.viewport.width);
23575 return {
23576 x: 0,
23577 y: 0,
23578 text: text,
23579 width: width,
23580 height: powerbi.TextMeasurementService.estimateSvgTextHeight(textProperties)
23581 };
23582 }
23583 return null;
23584 };
23585 /** Performs layout offline for optimal perfomance */
23586 SVGLegend.prototype.calculateLayout = function (data, autoWidth) {
23587 var dataPoints = data.dataPoints;
23588 if (data.dataPoints.length === 0) {
23589 return {
23590 startIndex: null,
23591 numberOfItems: 0,
23592 title: null,
23593 navigationArrows: []
23594 };
23595 }
23596 this.legendFontSizeMarginValue = PixelConverter.fromPointToPixel(this.data && this.data.fontSize !== undefined ? this.data.fontSize : SVGLegend.DefaultFontSizeInPt);
23597 this.legendFontSizeMarginDifference = (this.legendFontSizeMarginValue - SVGLegend.DefaultTextMargin);
23598 this.normalizePosition(dataPoints);
23599 if (this.legendDataStartIndex < dataPoints.length) {
23600 dataPoints = dataPoints.slice(this.legendDataStartIndex);
23601 }
23602 var title = this.calculateTitleLayout(data.title);
23603 var navArrows;
23604 var numberOfItems;
23605 if (this.isTopOrBottom(this.orientation)) {
23606 navArrows = this.isScrollable ? this.calculateHorizontalNavigationArrowsLayout(title) : [];
23607 numberOfItems = this.calculateHorizontalLayout(dataPoints, title, navArrows);
23608 }
23609 else {
23610 navArrows = this.isScrollable ? this.calculateVerticalNavigationArrowsLayout(title) : [];
23611 numberOfItems = this.calculateVerticalLayout(dataPoints, title, navArrows, autoWidth);
23612 }
23613 return {
23614 numberOfItems: numberOfItems,
23615 title: title,
23616 navigationArrows: navArrows
23617 };
23618 };
23619 SVGLegend.prototype.updateNavigationArrowLayout = function (navigationArrows, remainingDataLength, visibleDataLength) {
23620 if (this.legendDataStartIndex === 0) {
23621 navigationArrows.shift();
23622 }
23623 var lastWindow = this.arrowPosWindow;
23624 this.arrowPosWindow = visibleDataLength;
23625 if (navigationArrows && navigationArrows.length > 0 && this.arrowPosWindow === remainingDataLength) {
23626 this.arrowPosWindow = lastWindow;
23627 navigationArrows.length = navigationArrows.length - 1;
23628 }
23629 };
23630 SVGLegend.prototype.calculateHorizontalNavigationArrowsLayout = function (title) {
23631 var height = SVGLegend.LegendArrowHeight;
23632 var width = SVGLegend.LegendArrowWidth;
23633 var translateY = (this.viewport.height / 2) - (height / 2);
23634 var data = [];
23635 var rightShift = title ? title.x + title.width : 0;
23636 var arrowLeft = visuals.SVGUtil.createArrow(width, height, 180 /*angle*/);
23637 var arrowRight = visuals.SVGUtil.createArrow(width, height, 0 /*angle*/);
23638 data.push({
23639 x: rightShift,
23640 y: translateY,
23641 path: arrowLeft.path,
23642 rotateTransform: arrowLeft.transform,
23643 type: 1 /* Decrease */
23644 });
23645 data.push({
23646 x: this.parentViewport.width - width,
23647 y: translateY,
23648 path: arrowRight.path,
23649 rotateTransform: arrowRight.transform,
23650 type: 0 /* Increase */
23651 });
23652 return data;
23653 };
23654 SVGLegend.prototype.calculateVerticalNavigationArrowsLayout = function (title) {
23655 var height = SVGLegend.LegendArrowHeight;
23656 var width = SVGLegend.LegendArrowWidth;
23657 var verticalCenter = this.viewport.height / 2;
23658 var data = [];
23659 var rightShift = verticalCenter + height / 2;
23660 var arrowTop = visuals.SVGUtil.createArrow(width, height, 270 /*angle*/);
23661 var arrowBottom = visuals.SVGUtil.createArrow(width, height, 90 /*angle*/);
23662 var titleHeight = title ? title.height : 0;
23663 data.push({
23664 x: rightShift,
23665 y: width + titleHeight,
23666 path: arrowTop.path,
23667 rotateTransform: arrowTop.transform,
23668 type: 1 /* Decrease */
23669 });
23670 data.push({
23671 x: rightShift,
23672 y: this.parentViewport.height - height,
23673 path: arrowBottom.path,
23674 rotateTransform: arrowBottom.transform,
23675 type: 0 /* Increase */
23676 });
23677 return data;
23678 };
23679 /**
23680 * Calculates the widths for each horizontal legend item.
23681 */
23682 SVGLegend.calculateHorizontalLegendItemsWidths = function (dataPoints, availableWidth, iconPadding, fontSize) {
23683 var dataPointsLength = dataPoints.length;
23684 // Set the maximum amount of space available to each item. They can use less, but can't go over this number.
23685 var maxItemWidth = dataPointsLength > 0 ? availableWidth / dataPointsLength | 0 : 0;
23686 var maxItemTextWidth = maxItemWidth - iconPadding;
23687 // Makes sure the amount of space available to each item is at least SVGLegend.MaxTextLength wide.
23688 // If you had many items and/or a narrow amount of available width, the availableTextWidthPerItem would be small, essentially making everything ellipsis.
23689 // This prevents that from happening by giving each item at least SVGLegend.MaxTextLength of space.
23690 if (maxItemTextWidth < SVGLegend.MaxTextLength) {
23691 maxItemTextWidth = SVGLegend.MaxTextLength;
23692 maxItemWidth = maxItemTextWidth + iconPadding;
23693 }
23694 // Make sure the availableWidthPerItem is less than the availableWidth. This lets the long text properly add ellipsis when we're displaying one item at a time.
23695 if (maxItemWidth > availableWidth) {
23696 maxItemWidth = availableWidth;
23697 maxItemTextWidth = maxItemWidth - iconPadding;
23698 }
23699 var occupiedWidth = 0;
23700 var legendItems = [];
23701 // Add legend items until we can't fit any more (the last one doesn't fit) or we've added all of them
23702 for (var _i = 0, dataPoints_1 = dataPoints; _i < dataPoints_1.length; _i++) {
23703 var dataPoint = dataPoints_1[_i];
23704 var textProperties = SVGLegend.getTextProperties(false, dataPoint.label, fontSize);
23705 var itemTextWidth = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
23706 var desiredWidth = itemTextWidth + iconPadding;
23707 var overMaxWidth = desiredWidth > maxItemWidth;
23708 var actualWidth = overMaxWidth ? maxItemWidth : desiredWidth;
23709 occupiedWidth += actualWidth;
23710 if (occupiedWidth >= availableWidth) {
23711 // Always add at least 1 element
23712 if (legendItems.length === 0) {
23713 legendItems.push({
23714 dataPoint: dataPoint,
23715 textProperties: textProperties,
23716 desiredWidth: desiredWidth,
23717 desiredOverMaxWidth: true,
23718 width: desiredWidth
23719 });
23720 // Set the width to the amount of space we actually have
23721 occupiedWidth = availableWidth;
23722 }
23723 else {
23724 // Subtract the width from what was just added since it won't fit
23725 occupiedWidth -= actualWidth;
23726 }
23727 break;
23728 }
23729 legendItems.push({
23730 dataPoint: dataPoint,
23731 textProperties: textProperties,
23732 desiredWidth: desiredWidth,
23733 desiredOverMaxWidth: overMaxWidth,
23734 width: desiredWidth
23735 });
23736 }
23737 // If there are items at max width, evenly redistribute the extra space to them
23738 var itemsOverMax = _.filter(legendItems, function (li) { return li.desiredOverMaxWidth; });
23739 var numItemsOverMax = itemsOverMax.length;
23740 if (numItemsOverMax > 0) {
23741 var extraWidth = availableWidth - occupiedWidth;
23742 for (var _a = 0, itemsOverMax_1 = itemsOverMax; _a < itemsOverMax_1.length; _a++) {
23743 var item = itemsOverMax_1[_a];
23744 // Divvy up the extra space and add it to the max
23745 // We need to do this calculation in every loop since the remainingWidth may not be changed by the same amount every time
23746 var extraWidthPerItem = extraWidth / numItemsOverMax;
23747 var newMaxItemWidth = maxItemWidth + extraWidthPerItem;
23748 var usedExtraWidth = void 0;
23749 if (item.desiredWidth <= newMaxItemWidth) {
23750 // If the item doesn't need all the extra space, it's not at max anymore
23751 item.desiredOverMaxWidth = false;
23752 usedExtraWidth = item.desiredWidth - maxItemWidth;
23753 }
23754 else {
23755 // Otherwise the item is taking up all the extra space so update the actual width to indicate that
23756 item.width = newMaxItemWidth;
23757 usedExtraWidth = newMaxItemWidth - maxItemWidth;
23758 }
23759 extraWidth -= usedExtraWidth;
23760 numItemsOverMax--;
23761 }
23762 }
23763 return legendItems;
23764 };
23765 SVGLegend.prototype.calculateHorizontalLayout = function (dataPoints, title, navigationArrows) {
23766 debug.assertValue(navigationArrows, 'navigationArrows');
23767 // calculate the text shift
23768 var HorizontalTextShift = 4 + SVGLegend.LegendIconRadius;
23769 // check if we need more space for the margin, or use the default text padding
23770 var fontSizeBiggerThanDefault = this.legendFontSizeMarginDifference > 0;
23771 var fontSizeMargin = fontSizeBiggerThanDefault ? SVGLegend.TextAndIconPadding + this.legendFontSizeMarginDifference : SVGLegend.TextAndIconPadding;
23772 var fixedTextShift = (fontSizeMargin / (SVGLegend.LegendIconRadiusFactor / 2)) + HorizontalTextShift;
23773 var occupiedWidth = 0;
23774 // calculate the size of the space for both sides of the radius
23775 var iconTotalItemPadding = SVGLegend.LegendIconRadius * 2 + fontSizeMargin * 1.5;
23776 var numberOfItems = dataPoints.length;
23777 // get the Y coordinate which is the middle of the container + the middle of the text height - the delta of the text
23778 var defaultTextProperties = SVGLegend.getTextProperties(false, '', this.data.fontSize);
23779 var verticalCenter = this.viewport.height / 2;
23780 var textYCoordinate = verticalCenter + powerbi.TextMeasurementService.estimateSvgTextHeight(defaultTextProperties) / 2
23781 - powerbi.TextMeasurementService.estimateSvgTextBaselineDelta(defaultTextProperties);
23782 if (title) {
23783 occupiedWidth += title.width;
23784 // get the Y coordinate which is the middle of the container + the middle of the text height - the delta of the text
23785 title.y = verticalCenter + title.height / 2 - powerbi.TextMeasurementService.estimateSvgTextBaselineDelta(SVGLegend.getTextProperties(true, title.text, this.data.fontSize));
23786 }
23787 // if an arrow should be added, we add space for it
23788 if (this.legendDataStartIndex > 0) {
23789 occupiedWidth += SVGLegend.LegendArrowOffset;
23790 }
23791 // Calculate the width for each of the legend items
23792 var dataPointsLength = dataPoints.length;
23793 var availableWidth = this.parentViewport.width - occupiedWidth;
23794 var legendItems = SVGLegend.calculateHorizontalLegendItemsWidths(dataPoints, availableWidth, iconTotalItemPadding, this.data.fontSize);
23795 numberOfItems = legendItems.length;
23796 // If we can't show all the legend items, subtract the "next" arrow space from the available space and re-run the width calculations
23797 if (numberOfItems !== dataPointsLength) {
23798 availableWidth -= SVGLegend.LegendArrowOffset;
23799 legendItems = SVGLegend.calculateHorizontalLegendItemsWidths(dataPoints, availableWidth, iconTotalItemPadding, this.data.fontSize);
23800 numberOfItems = legendItems.length;
23801 }
23802 for (var _i = 0, legendItems_1 = legendItems; _i < legendItems_1.length; _i++) {
23803 var legendItem = legendItems_1[_i];
23804 var dataPoint = legendItem.dataPoint;
23805 dataPoint.glyphPosition = {
23806 // the space taken so far + the radius + the margin / radiusFactor to prevent huge spaces
23807 x: occupiedWidth + SVGLegend.LegendIconRadius + (this.legendFontSizeMarginDifference / SVGLegend.LegendIconRadiusFactor),
23808 // The middle of the container but a bit lower due to text not being in the middle (qP for example making middle between q and P)
23809 y: (this.viewport.height * SVGLegend.LegendIconYRatio),
23810 };
23811 dataPoint.textPosition = {
23812 x: occupiedWidth + fixedTextShift,
23813 y: textYCoordinate,
23814 };
23815 // If we're over the max width, process it so it fits
23816 if (legendItem.desiredOverMaxWidth) {
23817 var textWidth = legendItem.width - iconTotalItemPadding;
23818 var text = powerbi.TextMeasurementService.getTailoredTextOrDefault(legendItem.textProperties, textWidth);
23819 dataPoint.label = text;
23820 }
23821 occupiedWidth += legendItem.width;
23822 }
23823 this.visibleLegendWidth = occupiedWidth;
23824 this.updateNavigationArrowLayout(navigationArrows, dataPointsLength, numberOfItems);
23825 return numberOfItems;
23826 };
23827 SVGLegend.prototype.calculateVerticalLayout = function (dataPoints, title, navigationArrows, autoWidth) {
23828 var _this = this;
23829 // check if we need more space for the margin, or use the default text padding
23830 var fontSizeBiggerThenDefault = this.legendFontSizeMarginDifference > 0;
23831 var fontFactor = fontSizeBiggerThenDefault ? this.legendFontSizeMarginDifference : 0;
23832 // calculate the size needed after font size change
23833 var verticalLegendHeight = 20 + fontFactor;
23834 var spaceNeededByTitle = 15 + fontFactor;
23835 var extraShiftForTextAlignmentToIcon = 4 + fontFactor;
23836 var totalSpaceOccupiedThusFar = verticalLegendHeight;
23837 // the default space for text and icon radius + the margin after the font size change
23838 var fixedHorizontalIconShift = SVGLegend.TextAndIconPadding + SVGLegend.LegendIconRadius + (this.legendFontSizeMarginDifference / SVGLegend.LegendIconRadiusFactor);
23839 var fixedHorizontalTextShift = fixedHorizontalIconShift * 2;
23840 // check how much space is needed
23841 var maxHorizontalSpaceAvaliable = autoWidth
23842 ? this.parentViewport.width * SVGLegend.LegendMaxWidthFactor
23843 - fixedHorizontalTextShift - SVGLegend.LegendEdgeMariginWidth
23844 : this.lastCalculatedWidth
23845 - fixedHorizontalTextShift - SVGLegend.LegendEdgeMariginWidth;
23846 var numberOfItems = dataPoints.length;
23847 var maxHorizontalSpaceUsed = 0;
23848 var parentHeight = this.parentViewport.height;
23849 if (title) {
23850 totalSpaceOccupiedThusFar += spaceNeededByTitle;
23851 title.x = SVGLegend.TextAndIconPadding;
23852 title.y = spaceNeededByTitle;
23853 maxHorizontalSpaceUsed = title.width || 0;
23854 }
23855 // if an arrow should be added, we add space for it
23856 if (this.legendDataStartIndex > 0)
23857 totalSpaceOccupiedThusFar += SVGLegend.LegendArrowOffset;
23858 var dataPointsLength = dataPoints.length;
23859 for (var i = 0; i < dataPointsLength; i++) {
23860 var dp = dataPoints[i];
23861 var textProperties = SVGLegend.getTextProperties(false, dp.label, this.data.fontSize);
23862 dp.glyphPosition = {
23863 x: fixedHorizontalIconShift,
23864 y: (totalSpaceOccupiedThusFar + extraShiftForTextAlignmentToIcon) - powerbi.TextMeasurementService.estimateSvgTextBaselineDelta(textProperties)
23865 };
23866 dp.textPosition = {
23867 x: fixedHorizontalTextShift,
23868 y: totalSpaceOccupiedThusFar + extraShiftForTextAlignmentToIcon
23869 };
23870 // TODO: [PERF] Get rid of this extra measurement, and modify
23871 // getTailoredTextToReturnWidth + Text
23872 var width = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
23873 if (width > maxHorizontalSpaceUsed) {
23874 maxHorizontalSpaceUsed = width;
23875 }
23876 if (width > maxHorizontalSpaceAvaliable) {
23877 var text = powerbi.TextMeasurementService.getTailoredTextOrDefault(textProperties, maxHorizontalSpaceAvaliable);
23878 dp.label = text;
23879 }
23880 totalSpaceOccupiedThusFar += verticalLegendHeight;
23881 if (totalSpaceOccupiedThusFar > parentHeight) {
23882 numberOfItems = i;
23883 break;
23884 }
23885 }
23886 if (autoWidth) {
23887 if (maxHorizontalSpaceUsed < maxHorizontalSpaceAvaliable) {
23888 this.lastCalculatedWidth = this.viewport.width = Math.ceil(maxHorizontalSpaceUsed + fixedHorizontalTextShift + SVGLegend.LegendEdgeMariginWidth);
23889 }
23890 else {
23891 this.lastCalculatedWidth = this.viewport.width = Math.ceil(this.parentViewport.width * SVGLegend.LegendMaxWidthFactor);
23892 }
23893 }
23894 else {
23895 this.viewport.width = this.lastCalculatedWidth;
23896 }
23897 this.visibleLegendHeight = totalSpaceOccupiedThusFar;
23898 navigationArrows.forEach(function (d) { return d.x = _this.lastCalculatedWidth / 2; });
23899 this.updateNavigationArrowLayout(navigationArrows, dataPointsLength, numberOfItems);
23900 return numberOfItems;
23901 };
23902 SVGLegend.prototype.drawNavigationArrows = function (layout) {
23903 var _this = this;
23904 var arrows = this.group.selectAll(SVGLegend.NavigationArrow.selector)
23905 .data(layout);
23906 arrows
23907 .enter()
23908 .append('g')
23909 .on('click', function (d) {
23910 var pos = _this.legendDataStartIndex;
23911 _this.legendDataStartIndex = d.type === 0 /* Increase */
23912 ? pos + _this.arrowPosWindow : pos - _this.arrowPosWindow;
23913 _this.drawLegendInternal(_this.data, _this.parentViewport, false);
23914 })
23915 .classed(SVGLegend.NavigationArrow.class, true)
23916 .append('path');
23917 arrows
23918 .attr('transform', function (d) { return visuals.SVGUtil.translate(d.x, d.y); })
23919 .select('path')
23920 .attr({
23921 'd': function (d) { return d.path; },
23922 'transform': function (d) { return d.rotateTransform; }
23923 });
23924 arrows.exit().remove();
23925 };
23926 SVGLegend.prototype.isTopOrBottom = function (orientation) {
23927 switch (orientation) {
23928 case LegendPosition.Top:
23929 case LegendPosition.Bottom:
23930 case LegendPosition.BottomCenter:
23931 case LegendPosition.TopCenter:
23932 return true;
23933 default:
23934 return false;
23935 }
23936 };
23937 SVGLegend.prototype.isCentered = function (orientation) {
23938 switch (orientation) {
23939 case LegendPosition.BottomCenter:
23940 case LegendPosition.LeftCenter:
23941 case LegendPosition.RightCenter:
23942 case LegendPosition.TopCenter:
23943 return true;
23944 default:
23945 return false;
23946 }
23947 };
23948 SVGLegend.prototype.reset = function () {
23949 // Intentionally left blank.
23950 };
23951 SVGLegend.getTextProperties = function (isTitle, text, fontSize) {
23952 return {
23953 text: text,
23954 fontFamily: isTitle ? SVGLegend.DefaultTitleFontFamily : SVGLegend.DefaultFontFamily,
23955 fontSize: PixelConverter.fromPoint(fontSize || SVGLegend.DefaultFontSizeInPt)
23956 };
23957 };
23958 SVGLegend.prototype.setTooltipToLegendItems = function (data) {
23959 //we save the values to tooltip before cut
23960 for (var _i = 0, _a = data.dataPoints; _i < _a.length; _i++) {
23961 var dataPoint = _a[_i];
23962 dataPoint.tooltip = dataPoint.label;
23963 }
23964 };
23965 SVGLegend.DefaultFontSizeInPt = 8;
23966 SVGLegend.LegendIconRadius = 5;
23967 SVGLegend.LegendIconRadiusFactor = 5;
23968 SVGLegend.MaxTextLength = 60;
23969 SVGLegend.MaxTitleLength = 80;
23970 SVGLegend.TextAndIconPadding = 5;
23971 SVGLegend.TitlePadding = 15;
23972 SVGLegend.LegendEdgeMariginWidth = 10;
23973 SVGLegend.LegendMaxWidthFactor = 0.3;
23974 SVGLegend.TopLegendHeight = 24;
23975 SVGLegend.DefaultTextMargin = PixelConverter.fromPointToPixel(SVGLegend.DefaultFontSizeInPt);
23976 SVGLegend.DefaultMaxLegendFactor = SVGLegend.MaxTitleLength / SVGLegend.DefaultTextMargin;
23977 SVGLegend.LegendIconYRatio = 0.52;
23978 // Navigation Arrow constants
23979 SVGLegend.LegendArrowOffset = 10;
23980 SVGLegend.LegendArrowHeight = 15;
23981 SVGLegend.LegendArrowWidth = 7.5;
23982 SVGLegend.DefaultFontFamily = 'wf_segoe-ui_normal';
23983 SVGLegend.DefaultTitleFontFamily = 'wf_segoe-ui_Semibold';
23984 SVGLegend.LegendItem = createClassAndSelector('legendItem');
23985 SVGLegend.LegendText = createClassAndSelector('legendText');
23986 SVGLegend.LegendIcon = createClassAndSelector('legendIcon');
23987 SVGLegend.LegendTitle = createClassAndSelector('legendTitle');
23988 SVGLegend.NavigationArrow = createClassAndSelector('navArrow');
23989 return SVGLegend;
23990 }());
23991 visuals.SVGLegend = SVGLegend;
23992 var CartesianChartInteractiveLegend = (function () {
23993 function CartesianChartInteractiveLegend(element) {
23994 this.legendContainerParent = d3.select(element.get(0));
23995 }
23996 CartesianChartInteractiveLegend.prototype.getMargins = function () {
23997 return {
23998 height: CartesianChartInteractiveLegend.LegendHeight,
23999 width: 0
24000 };
24001 };
24002 CartesianChartInteractiveLegend.prototype.drawLegend = function (legendData) {
24003 debug.assertValue(legendData, 'legendData');
24004 var data = legendData.dataPoints;
24005 debug.assertValue(data, 'dataPoints');
24006 if (data.length < 1)
24007 return;
24008 var legendContainerDiv = this.legendContainerParent.select(CartesianChartInteractiveLegend.LegendContainerSelector);
24009 if (legendContainerDiv.empty()) {
24010 if (!data.length)
24011 return;
24012 var divToPrepend = $('<div></div>')
24013 .height(this.getMargins().height)
24014 .addClass(CartesianChartInteractiveLegend.LegendContainerClass);
24015 // Prepending, as legend should always be on topmost visual.
24016 $(this.legendContainerParent[0]).prepend(divToPrepend);
24017 legendContainerDiv = d3.select(divToPrepend.get(0));
24018 }
24019 this.legendContainerDiv = legendContainerDiv;
24020 // Construct the legend title and items.
24021 this.drawTitle(data);
24022 this.drawLegendItems(data);
24023 };
24024 CartesianChartInteractiveLegend.prototype.reset = function () {
24025 if (this.legendContainerDiv) {
24026 this.legendContainerDiv.remove();
24027 this.legendContainerDiv = null;
24028 }
24029 };
24030 CartesianChartInteractiveLegend.prototype.isVisible = function () {
24031 return true;
24032 };
24033 CartesianChartInteractiveLegend.prototype.changeOrientation = function (orientation) {
24034 // Not supported
24035 };
24036 CartesianChartInteractiveLegend.prototype.getOrientation = function () {
24037 return LegendPosition.Top;
24038 };
24039 /**
24040 * Draw the legend title
24041 */
24042 CartesianChartInteractiveLegend.prototype.drawTitle = function (data) {
24043 debug.assert(data && data.length > 0, 'data is null or empty');
24044 var titleDiv = this.legendContainerDiv.selectAll('div.' + CartesianChartInteractiveLegend.LegendTitleClass);
24045 var item = titleDiv.data([data[0]]);
24046 // Enter
24047 var itemEnter = item.enter();
24048 var titleDivEnter = itemEnter.append('div').attr('class', CartesianChartInteractiveLegend.LegendTitleClass);
24049 titleDivEnter
24050 .filter(function (d) { return d.iconOnlyOnLabel; })
24051 .append('span')
24052 .attr('class', CartesianChartInteractiveLegend.legendIconClass)
24053 .html(CartesianChartInteractiveLegend.legendPlaceSelector);
24054 titleDivEnter.append('span');
24055 // Update
24056 item.filter(function (d) { return d.iconOnlyOnLabel; })
24057 .select('span.' + CartesianChartInteractiveLegend.legendIconClass)
24058 .style(CartesianChartInteractiveLegend.legendColorCss, function (d) { return d.color; });
24059 item.select('span:last-child').text(function (d) { return d.category; });
24060 };
24061 /**
24062 * Draw the legend items
24063 */
24064 CartesianChartInteractiveLegend.prototype.drawLegendItems = function (data) {
24065 // Add Mesaures - the items of the category in the legend
24066 this.ensureLegendTableCreated();
24067 var dataPointsMatrix = CartesianChartInteractiveLegend.splitArrayToOddEven(data);
24068 var legendItemsContainer = this.legendContainerDiv.select('tbody').selectAll('tr').data(dataPointsMatrix);
24069 // trs is table rows.
24070 // there are two table rows.
24071 // the order of insertion to the legend table is:
24072 // Even data points got inserted into the 1st line
24073 // Odd data points got inserted into the 2nd line
24074 // ----------------------------
24075 // | value0 | value 2 | value 4
24076 // ----------------------------
24077 // | value1 | value 3 |
24078 // ----------------------------
24079 //
24080 // Enter
24081 var legendItemsEnter = legendItemsContainer.enter();
24082 var rowEnter = legendItemsEnter.append('tr');
24083 var cellEnter = rowEnter.selectAll('td')
24084 .data(function (d) { return d; }, function (d) { return d.label; })
24085 .enter()
24086 .append('td').attr('class', CartesianChartInteractiveLegend.LegendItem);
24087 var cellSpanEnter = cellEnter.append('span');
24088 cellSpanEnter.filter(function (d) { return !d.iconOnlyOnLabel; })
24089 .append('span')
24090 .html(CartesianChartInteractiveLegend.legendPlaceSelector)
24091 .attr('class', CartesianChartInteractiveLegend.legendIconClass)
24092 .attr('white-space', 'nowrap');
24093 cellSpanEnter.append('span').attr('class', CartesianChartInteractiveLegend.legendItemNameClass);
24094 cellSpanEnter.append('span').attr('class', CartesianChartInteractiveLegend.legendItemMeasureClass);
24095 // Update
24096 var legendCells = legendItemsContainer.selectAll('td').data(function (d) { return d; }, function (d) { return d.label; });
24097 legendCells.select('span.' + CartesianChartInteractiveLegend.legendItemNameClass).html(function (d) { return powerbi.visuals.TextUtil.removeBreakingSpaces(d.label); });
24098 legendCells.select('span.' + CartesianChartInteractiveLegend.legendItemMeasureClass).html(function (d) { return '&nbsp;' + d.measure; });
24099 legendCells.select('span.' + CartesianChartInteractiveLegend.legendIconClass).style('color', function (d) { return d.color; });
24100 // Exit
24101 legendCells.exit().remove();
24102 };
24103 /**
24104 * Ensure legend table is created and set horizontal pan gestures on it
24105 */
24106 CartesianChartInteractiveLegend.prototype.ensureLegendTableCreated = function () {
24107 if (this.legendContainerDiv.select('div table').empty()) {
24108 var legendTable = this.legendContainerDiv.append('div').append('table');
24109 legendTable.style('table-layout', 'fixed').append('tbody');
24110 // Setup Pan Gestures of the legend
24111 this.setPanGestureOnLegend(legendTable);
24112 }
24113 };
24114 /**
24115 * Set Horizontal Pan gesture for the legend
24116 */
24117 CartesianChartInteractiveLegend.prototype.setPanGestureOnLegend = function (legendTable) {
24118 var viewportWidth = $(this.legendContainerDiv.select('div:nth-child(2)')[0]).width();
24119 var xscale = d3.scale.linear().domain([0, viewportWidth]).range([0, viewportWidth]);
24120 var zoom = d3.behavior.zoom()
24121 .scaleExtent([1, 1]) // disable scaling
24122 .x(xscale)
24123 .on("zoom", function () {
24124 // horizontal pan is valid only in case the legend items width are bigger than the viewport width
24125 if ($(legendTable[0]).width() > viewportWidth) {
24126 var t = zoom.translate();
24127 var tx_1 = t[0];
24128 var ty = t[1];
24129 tx_1 = Math.min(tx_1, 0);
24130 tx_1 = Math.max(tx_1, viewportWidth - $(legendTable[0]).width());
24131 zoom.translate([tx_1, ty]);
24132 legendTable.style("-ms-transform", function () {
24133 return visuals.SVGUtil.translateXWithPixels(tx_1);
24134 });
24135 legendTable.style("-webkit-transform", function () {
24136 return visuals.SVGUtil.translateXWithPixels(tx_1);
24137 });
24138 legendTable.style("transform", function () {
24139 return visuals.SVGUtil.translateXWithPixels(tx_1);
24140 });
24141 }
24142 });
24143 if (this.legendContainerDiv) {
24144 this.legendContainerDiv.call(zoom);
24145 }
24146 else {
24147 legendTable.call(zoom);
24148 }
24149 };
24150 /**
24151 * Split legend data points array into odd and even arrays
24152 * Even array will be the legend first line and Odd array will be the 2nd legend line
24153 */
24154 CartesianChartInteractiveLegend.splitArrayToOddEven = function (data) {
24155 var oddData = [];
24156 var evenData = [];
24157 for (var i = 0; i < data.length; ++i) {
24158 if (i % 2 === 0) {
24159 evenData.push(data[i]);
24160 }
24161 else {
24162 oddData.push(data[i]);
24163 }
24164 }
24165 return [evenData, oddData];
24166 };
24167 CartesianChartInteractiveLegend.LegendHeight = 70;
24168 CartesianChartInteractiveLegend.LegendContainerClass = 'interactive-legend';
24169 CartesianChartInteractiveLegend.LegendContainerSelector = '.interactive-legend';
24170 CartesianChartInteractiveLegend.LegendTitleClass = 'title';
24171 CartesianChartInteractiveLegend.LegendItem = 'item';
24172 CartesianChartInteractiveLegend.legendPlaceSelector = '\u25A0';
24173 CartesianChartInteractiveLegend.legendIconClass = 'icon';
24174 CartesianChartInteractiveLegend.legendColorCss = 'color';
24175 CartesianChartInteractiveLegend.legendItemNameClass = 'itemName';
24176 CartesianChartInteractiveLegend.legendItemMeasureClass = 'itemMeasure';
24177 return CartesianChartInteractiveLegend;
24178 }());
24179 var LegendData;
24180 (function (LegendData) {
24181 LegendData.DefaultLegendLabelFillColor = '#666666';
24182 function update(legendData, legendObject) {
24183 debug.assertValue(legendData, 'legendData');
24184 debug.assertValue(legendObject, 'legendObject');
24185 if (legendObject[visuals.legendProps.show] == null) {
24186 legendObject[visuals.legendProps.show] = true;
24187 }
24188 if (legendObject[visuals.legendProps.show] === false)
24189 legendData.dataPoints = [];
24190 if (legendObject[visuals.legendProps.show] === true && legendObject[visuals.legendProps.position] == null)
24191 legendObject[visuals.legendProps.position] = visuals.legendPosition.top;
24192 if (legendObject[visuals.legendProps.fontSize] !== undefined)
24193 legendData.fontSize = legendObject[visuals.legendProps.fontSize];
24194 if (legendObject[visuals.legendProps.labelColor] !== undefined) {
24195 var fillColor = legendObject[visuals.legendProps.labelColor];
24196 if (fillColor != null) {
24197 legendData.labelColor = fillColor.solid.color;
24198 }
24199 }
24200 if (legendObject[visuals.legendProps.showTitle] === false)
24201 legendData.title = "";
24202 else if (legendObject[visuals.legendProps.titleText] !== undefined) {
24203 legendData.title = legendObject[visuals.legendProps.titleText];
24204 }
24205 }
24206 LegendData.update = update;
24207 })(LegendData = visuals.LegendData || (visuals.LegendData = {}));
24208 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24209})(powerbi || (powerbi = {}));
24210/*
24211* Power BI Visualizations
24212*
24213* Copyright (c) Microsoft Corporation
24214* All rights reserved.
24215* MIT License
24216*
24217* Permission is hereby granted, free of charge, to any person obtaining a copy
24218* of this software and associated documentation files (the ""Software""), to deal
24219* in the Software without restriction, including without limitation the rights
24220* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24221* copies of the Software, and to permit persons to whom the Software is
24222* furnished to do so, subject to the following conditions:
24223*
24224* The above copyright notice and this permission notice shall be included in
24225* all copies or substantial portions of the Software.
24226*
24227* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24228* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24229* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24230* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24231* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24232* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24233* THE SOFTWARE.
24234*/
24235var powerbi;
24236(function (powerbi) {
24237 var visuals;
24238 (function (visuals) {
24239 var axisScale;
24240 (function (axisScale) {
24241 axisScale.linear = 'linear';
24242 axisScale.log = 'log';
24243 axisScale.type = powerbi.createEnumType([
24244 { value: axisScale.linear, displayName: function (resources) { return resources.get('Visual_Axis_Linear'); } },
24245 { value: axisScale.log, displayName: function (resources) { return resources.get('Visual_Axis_Log'); } }
24246 ]);
24247 })(axisScale = visuals.axisScale || (visuals.axisScale = {}));
24248 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24249})(powerbi || (powerbi = {}));
24250/*
24251 * Power BI Visualizations
24252 *
24253 * Copyright (c) Microsoft Corporation
24254 * All rights reserved.
24255 * MIT License
24256 *
24257 * Permission is hereby granted, free of charge, to any person obtaining a copy
24258 * of this software and associated documentation files (the ""Software""), to deal
24259 * in the Software without restriction, including without limitation the rights
24260 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24261 * copies of the Software, and to permit persons to whom the Software is
24262 * furnished to do so, subject to the following conditions:
24263 *
24264 * The above copyright notice and this permission notice shall be included in
24265 * all copies or substantial portions of the Software.
24266 *
24267 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24268 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24269 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24270 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24271 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24272 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24273 * THE SOFTWARE.
24274 */
24275var powerbi;
24276(function (powerbi) {
24277 var visuals;
24278 (function (visuals) {
24279 var axisStyle;
24280 (function (axisStyle) {
24281 axisStyle.showBoth = 'showBoth';
24282 axisStyle.showTitleOnly = 'showTitleOnly';
24283 axisStyle.showUnitOnly = 'showUnitOnly';
24284 axisStyle.type = powerbi.createEnumType([
24285 { value: axisStyle.showTitleOnly, displayName: function (resources) { return resources.get('Visual_Axis_ShowTitleOnly'); } },
24286 { value: axisStyle.showUnitOnly, displayName: function (resources) { return resources.get('Visual_Axis_ShowUnitOnly'); } },
24287 { value: axisStyle.showBoth, displayName: function (resources) { return resources.get('Visual_Axis_ShowBoth'); } }
24288 ]);
24289 })(axisStyle = visuals.axisStyle || (visuals.axisStyle = {}));
24290 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24291})(powerbi || (powerbi = {}));
24292/*
24293 * Power BI Visualizations
24294 *
24295 * Copyright (c) Microsoft Corporation
24296 * All rights reserved.
24297 * MIT License
24298 *
24299 * Permission is hereby granted, free of charge, to any person obtaining a copy
24300 * of this software and associated documentation files (the ""Software""), to deal
24301 * in the Software without restriction, including without limitation the rights
24302 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24303 * copies of the Software, and to permit persons to whom the Software is
24304 * furnished to do so, subject to the following conditions:
24305 *
24306 * The above copyright notice and this permission notice shall be included in
24307 * all copies or substantial portions of the Software.
24308 *
24309 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24310 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24311 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24312 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24313 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24314 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24315 * THE SOFTWARE.
24316 */
24317var powerbi;
24318(function (powerbi) {
24319 var visuals;
24320 (function (visuals) {
24321 var axisType;
24322 (function (axisType) {
24323 axisType.scalar = 'Scalar';
24324 axisType.categorical = 'Categorical';
24325 axisType.both = 'Both';
24326 axisType.type = powerbi.createEnumType([
24327 { value: axisType.scalar, displayName: function (resources) { return resources.get('Visual_Axis_Scalar'); } },
24328 { value: axisType.categorical, displayName: function (resources) { return resources.get('Visual_Axis_Categorical'); } },
24329 ]);
24330 })(axisType = visuals.axisType || (visuals.axisType = {}));
24331 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24332})(powerbi || (powerbi = {}));
24333/*
24334 * Power BI Visualizations
24335 *
24336 * Copyright (c) Microsoft Corporation
24337 * All rights reserved.
24338 * MIT License
24339 *
24340 * Permission is hereby granted, free of charge, to any person obtaining a copy
24341 * of this software and associated documentation files (the ""Software""), to deal
24342 * in the Software without restriction, including without limitation the rights
24343 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24344 * copies of the Software, and to permit persons to whom the Software is
24345 * furnished to do so, subject to the following conditions:
24346 *
24347 * The above copyright notice and this permission notice shall be included in
24348 * all copies or substantial portions of the Software.
24349 *
24350 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24351 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24352 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24353 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24354 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24355 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24356 * THE SOFTWARE.
24357 */
24358var powerbi;
24359(function (powerbi) {
24360 var visuals;
24361 (function (visuals) {
24362 var basicShapeType;
24363 (function (basicShapeType) {
24364 basicShapeType.rectangle = 'rectangle';
24365 basicShapeType.oval = 'oval';
24366 basicShapeType.line = 'line';
24367 basicShapeType.arrow = 'arrow';
24368 basicShapeType.triangle = 'triangle';
24369 basicShapeType.type = powerbi.createEnumType([
24370 { value: basicShapeType.rectangle, displayName: 'rectangle' },
24371 { value: basicShapeType.oval, displayName: 'oval' },
24372 { value: basicShapeType.line, displayName: 'line' },
24373 { value: basicShapeType.arrow, displayName: 'arrow' },
24374 { value: basicShapeType.triangle, displayName: 'triangle' }
24375 ]);
24376 })(basicShapeType = visuals.basicShapeType || (visuals.basicShapeType = {}));
24377 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24378})(powerbi || (powerbi = {}));
24379/*
24380 * Power BI Visualizations
24381 *
24382 * Copyright (c) Microsoft Corporation
24383 * All rights reserved.
24384 * MIT License
24385 *
24386 * Permission is hereby granted, free of charge, to any person obtaining a copy
24387 * of this software and associated documentation files (the ""Software""), to deal
24388 * in the Software without restriction, including without limitation the rights
24389 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24390 * copies of the Software, and to permit persons to whom the Software is
24391 * furnished to do so, subject to the following conditions:
24392 *
24393 * The above copyright notice and this permission notice shall be included in
24394 * all copies or substantial portions of the Software.
24395 *
24396 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24397 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24398 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24399 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24400 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24401 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24402 * THE SOFTWARE.
24403 */
24404var powerbi;
24405(function (powerbi) {
24406 var visuals;
24407 (function (visuals) {
24408 var imageScalingType;
24409 (function (imageScalingType) {
24410 imageScalingType.normal = 'Normal';
24411 imageScalingType.fit = 'Fit';
24412 imageScalingType.fill = 'Fill';
24413 imageScalingType.type = powerbi.createEnumType([
24414 { value: imageScalingType.normal, displayName: function (resources) { return resources.get('Visual_ImageScalingType_Normal'); } },
24415 { value: imageScalingType.fit, displayName: function (resources) { return resources.get('Visual_ImageScalingType_Fit'); } },
24416 { value: imageScalingType.fill, displayName: function (resources) { return resources.get('Visual_ImageScalingType_Fill'); } },
24417 ]);
24418 })(imageScalingType = visuals.imageScalingType || (visuals.imageScalingType = {}));
24419 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24420})(powerbi || (powerbi = {}));
24421/*
24422 * Power BI Visualizations
24423 *
24424 * Copyright (c) Microsoft Corporation
24425 * All rights reserved.
24426 * MIT License
24427 *
24428 * Permission is hereby granted, free of charge, to any person obtaining a copy
24429 * of this software and associated documentation files (the ""Software""), to deal
24430 * in the Software without restriction, including without limitation the rights
24431 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24432 * copies of the Software, and to permit persons to whom the Software is
24433 * furnished to do so, subject to the following conditions:
24434 *
24435 * The above copyright notice and this permission notice shall be included in
24436 * all copies or substantial portions of the Software.
24437 *
24438 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24439 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24440 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24441 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24442 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24443 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24444 * THE SOFTWARE.
24445 */
24446var powerbi;
24447(function (powerbi) {
24448 var visuals;
24449 (function (visuals) {
24450 var labelPosition;
24451 (function (labelPosition) {
24452 labelPosition.insideEnd = 'InsideEnd';
24453 labelPosition.insideCenter = 'InsideCenter';
24454 labelPosition.outsideEnd = 'OutsideEnd';
24455 labelPosition.insideBase = 'InsideBase';
24456 labelPosition.type = powerbi.createEnumType([
24457 { value: labelPosition.insideEnd, displayName: function (resources) { return resources.get('Visual_LabelPosition_InsideEnd'); } },
24458 { value: labelPosition.outsideEnd, displayName: function (resources) { return resources.get('Visual_LabelPosition_OutsideEnd'); } },
24459 { value: labelPosition.insideCenter, displayName: function (resources) { return resources.get('Visual_LabelPosition_InsideCenter'); } },
24460 { value: labelPosition.insideBase, displayName: function (resources) { return resources.get('Visual_LabelPosition_InsideBase'); } },
24461 ]);
24462 })(labelPosition = visuals.labelPosition || (visuals.labelPosition = {}));
24463 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24464})(powerbi || (powerbi = {}));
24465/*
24466 * Power BI Visualizations
24467 *
24468 * Copyright (c) Microsoft Corporation
24469 * All rights reserved.
24470 * MIT License
24471 *
24472 * Permission is hereby granted, free of charge, to any person obtaining a copy
24473 * of this software and associated documentation files (the ""Software""), to deal
24474 * in the Software without restriction, including without limitation the rights
24475 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24476 * copies of the Software, and to permit persons to whom the Software is
24477 * furnished to do so, subject to the following conditions:
24478 *
24479 * The above copyright notice and this permission notice shall be included in
24480 * all copies or substantial portions of the Software.
24481 *
24482 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24483 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24484 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24485 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24486 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24487 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24488 * THE SOFTWARE.
24489 */
24490var powerbi;
24491(function (powerbi) {
24492 var visuals;
24493 (function (visuals) {
24494 var labelStyle;
24495 (function (labelStyle) {
24496 labelStyle.category = 'Category';
24497 labelStyle.data = 'Data';
24498 labelStyle.both = 'Both';
24499 labelStyle.type = powerbi.createEnumType([
24500 { value: labelStyle.category, displayName: function (resources) { return resources.get('Visual_LabelStyle_Category'); } },
24501 { value: labelStyle.data, displayName: function (resources) { return resources.get('Visual_LabelStyle_DataValue'); } },
24502 { value: labelStyle.both, displayName: function (resources) { return resources.get('Visual_LabelStyle_Both'); } },
24503 ]);
24504 })(labelStyle = visuals.labelStyle || (visuals.labelStyle = {}));
24505 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24506})(powerbi || (powerbi = {}));
24507/*
24508 * Power BI Visualizations
24509 *
24510 * Copyright (c) Microsoft Corporation
24511 * All rights reserved.
24512 * MIT License
24513 *
24514 * Permission is hereby granted, free of charge, to any person obtaining a copy
24515 * of this software and associated documentation files (the ""Software""), to deal
24516 * in the Software without restriction, including without limitation the rights
24517 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24518 * copies of the Software, and to permit persons to whom the Software is
24519 * furnished to do so, subject to the following conditions:
24520 *
24521 * The above copyright notice and this permission notice shall be included in
24522 * all copies or substantial portions of the Software.
24523 *
24524 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24525 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24526 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24527 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24528 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24529 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24530 * THE SOFTWARE.
24531 */
24532var powerbi;
24533(function (powerbi) {
24534 var visuals;
24535 (function (visuals) {
24536 var legendPosition;
24537 (function (legendPosition) {
24538 legendPosition.top = 'Top';
24539 legendPosition.bottom = 'Bottom';
24540 legendPosition.left = 'Left';
24541 legendPosition.right = 'Right';
24542 legendPosition.topCenter = 'TopCenter';
24543 legendPosition.bottomCenter = 'BottomCenter';
24544 legendPosition.leftCenter = 'LeftCenter';
24545 legendPosition.rightCenter = 'RightCenter';
24546 legendPosition.type = powerbi.createEnumType([
24547 { value: legendPosition.top, displayName: function (resources) { return resources.get('Visual_LegendPosition_Top'); } },
24548 { value: legendPosition.bottom, displayName: function (resources) { return resources.get('Visual_LegendPosition_Bottom'); } },
24549 { value: legendPosition.left, displayName: function (resources) { return resources.get('Visual_LegendPosition_Left'); } },
24550 { value: legendPosition.right, displayName: function (resources) { return resources.get('Visual_LegendPosition_Right'); } },
24551 { value: legendPosition.topCenter, displayName: function (resources) { return resources.get('Visual_LegendPosition_TopCenter'); } },
24552 { value: legendPosition.bottomCenter, displayName: function (resources) { return resources.get('Visual_LegendPosition_BottomCenter'); } },
24553 { value: legendPosition.leftCenter, displayName: function (resources) { return resources.get('Visual_LegendPosition_LeftCenter'); } },
24554 { value: legendPosition.rightCenter, displayName: function (resources) { return resources.get('Visual_LegendPosition_RightCenter'); } },
24555 ]);
24556 })(legendPosition = visuals.legendPosition || (visuals.legendPosition = {}));
24557 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24558})(powerbi || (powerbi = {}));
24559/*
24560 * Power BI Visualizations
24561 *
24562 * Copyright (c) Microsoft Corporation
24563 * All rights reserved.
24564 * MIT License
24565 *
24566 * Permission is hereby granted, free of charge, to any person obtaining a copy
24567 * of this software and associated documentation files (the ""Software""), to deal
24568 * in the Software without restriction, including without limitation the rights
24569 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24570 * copies of the Software, and to permit persons to whom the Software is
24571 * furnished to do so, subject to the following conditions:
24572 *
24573 * The above copyright notice and this permission notice shall be included in
24574 * all copies or substantial portions of the Software.
24575 *
24576 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24577 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24578 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24579 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24580 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24581 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24582 * THE SOFTWARE.
24583 */
24584var powerbi;
24585(function (powerbi) {
24586 var visuals;
24587 (function (visuals) {
24588 var kpiDirection;
24589 (function (kpiDirection) {
24590 kpiDirection.positive = 'Positive';
24591 kpiDirection.negative = 'Negative';
24592 kpiDirection.type = powerbi.createEnumType([
24593 { value: kpiDirection.positive, displayName: function (resources) { return resources.get('Visual_KPI_Direction_Positive'); } },
24594 { value: kpiDirection.negative, displayName: function (resources) { return resources.get('Visual_KPI_Direction_Negative'); } }
24595 ]);
24596 })(kpiDirection = visuals.kpiDirection || (visuals.kpiDirection = {}));
24597 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24598})(powerbi || (powerbi = {}));
24599/*
24600 * Power BI Visualizations
24601 *
24602 * Copyright (c) Microsoft Corporation
24603 * All rights reserved.
24604 * MIT License
24605 *
24606 * Permission is hereby granted, free of charge, to any person obtaining a copy
24607 * of this software and associated documentation files (the ""Software""), to deal
24608 * in the Software without restriction, including without limitation the rights
24609 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24610 * copies of the Software, and to permit persons to whom the Software is
24611 * furnished to do so, subject to the following conditions:
24612 *
24613 * The above copyright notice and this permission notice shall be included in
24614 * all copies or substantial portions of the Software.
24615 *
24616 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24617 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24618 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24619 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24620 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24621 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24622 * THE SOFTWARE.
24623 */
24624var powerbi;
24625(function (powerbi) {
24626 var visuals;
24627 (function (visuals) {
24628 var lineStyle;
24629 (function (lineStyle) {
24630 lineStyle.dashed = 'dashed';
24631 lineStyle.solid = 'solid';
24632 lineStyle.dotted = 'dotted';
24633 lineStyle.type = powerbi.createEnumType([
24634 { value: lineStyle.dashed, displayName: function (resources) { return resources.get('Visual_LineStyle_Dashed'); } },
24635 { value: lineStyle.solid, displayName: function (resources) { return resources.get('Visual_LineStyle_Solid'); } },
24636 { value: lineStyle.dotted, displayName: function (resources) { return resources.get('Visual_LineStyle_Dotted'); } }
24637 ]);
24638 })(lineStyle = visuals.lineStyle || (visuals.lineStyle = {}));
24639 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24640})(powerbi || (powerbi = {}));
24641/*
24642* Power BI Visualizations
24643*
24644* Copyright (c) Microsoft Corporation
24645* All rights reserved.
24646* MIT License
24647*
24648* Permission is hereby granted, free of charge, to any person obtaining a copy
24649* of this software and associated documentation files (the ""Software""), to deal
24650* in the Software without restriction, including without limitation the rights
24651* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24652* copies of the Software, and to permit persons to whom the Software is
24653* furnished to do so, subject to the following conditions:
24654*
24655* The above copyright notice and this permission notice shall be included in
24656* all copies or substantial portions of the Software.
24657*
24658* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24659* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24660* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24661* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24662* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24663* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24664* THE SOFTWARE.
24665*/
24666var powerbi;
24667(function (powerbi) {
24668 var visuals;
24669 (function (visuals) {
24670 var outline;
24671 (function (outline_1) {
24672 outline_1.none = 'None';
24673 outline_1.bottomOnly = 'BottomOnly';
24674 outline_1.topOnly = 'TopOnly';
24675 outline_1.leftOnly = 'LeftOnly';
24676 outline_1.rightOnly = 'RightOnly';
24677 outline_1.topBottom = 'TopBottom';
24678 outline_1.leftRight = 'LeftRight';
24679 outline_1.frame = 'Frame';
24680 function showTop(outline) {
24681 return [outline_1.topOnly, outline_1.topBottom, outline_1.frame].some(function (o) { return o === outline; });
24682 }
24683 outline_1.showTop = showTop;
24684 function showRight(outline) {
24685 return [outline_1.rightOnly, outline_1.leftRight, outline_1.frame].some(function (o) { return o === outline; });
24686 }
24687 outline_1.showRight = showRight;
24688 function showBottom(outline) {
24689 return [outline_1.bottomOnly, outline_1.topBottom, outline_1.frame].some(function (o) { return o === outline; });
24690 }
24691 outline_1.showBottom = showBottom;
24692 function showLeft(outline) {
24693 return [outline_1.leftOnly, outline_1.leftRight, outline_1.frame].some(function (o) { return o === outline; });
24694 }
24695 outline_1.showLeft = showLeft;
24696 outline_1.type = powerbi.createEnumType([
24697 { value: outline_1.none, displayName: function (resources) { return resources.get('Visual_Outline_none'); } },
24698 { value: outline_1.bottomOnly, displayName: function (resources) { return resources.get('Visual_Outline_bottom_only'); } },
24699 { value: outline_1.topOnly, displayName: function (resources) { return resources.get('Visual_Outline_top_only'); } },
24700 { value: outline_1.leftOnly, displayName: function (resources) { return resources.get('Visual_Outline_LeftOnly'); } },
24701 { value: outline_1.rightOnly, displayName: function (resources) { return resources.get('Visual_Outline_RightOnly'); } },
24702 { value: outline_1.topBottom, displayName: function (resources) { return resources.get('Visual_Outline_top_Bottom'); } },
24703 { value: outline_1.leftRight, displayName: function (resources) { return resources.get('Visual_Outline_leftRight'); } },
24704 { value: outline_1.frame, displayName: function (resources) { return resources.get('Visual_Outline_frame'); } }
24705 ]);
24706 })(outline = visuals.outline || (visuals.outline = {}));
24707 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24708})(powerbi || (powerbi = {}));
24709/*
24710 * Power BI Visualizations
24711 *
24712 * Copyright (c) Microsoft Corporation
24713 * All rights reserved.
24714 * MIT License
24715 *
24716 * Permission is hereby granted, free of charge, to any person obtaining a copy
24717 * of this software and associated documentation files (the ""Software""), to deal
24718 * in the Software without restriction, including without limitation the rights
24719 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24720 * copies of the Software, and to permit persons to whom the Software is
24721 * furnished to do so, subject to the following conditions:
24722 *
24723 * The above copyright notice and this permission notice shall be included in
24724 * all copies or substantial portions of the Software.
24725 *
24726 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24727 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24728 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24729 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24730 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24731 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24732 * THE SOFTWARE.
24733 */
24734var powerbi;
24735(function (powerbi) {
24736 var visuals;
24737 (function (visuals) {
24738 var referenceLinePosition;
24739 (function (referenceLinePosition) {
24740 referenceLinePosition.back = 'back';
24741 referenceLinePosition.front = 'front';
24742 referenceLinePosition.type = powerbi.createEnumType([
24743 { value: referenceLinePosition.back, displayName: function (resources) { return resources.get('Visual_Reference_Line_Behind'); } },
24744 { value: referenceLinePosition.front, displayName: function (resources) { return resources.get('Visual_Reference_Line_InFront'); } },
24745 ]);
24746 })(referenceLinePosition = visuals.referenceLinePosition || (visuals.referenceLinePosition = {}));
24747 var referenceLineDataLabelHorizontalPosition;
24748 (function (referenceLineDataLabelHorizontalPosition) {
24749 referenceLineDataLabelHorizontalPosition.left = 'left';
24750 referenceLineDataLabelHorizontalPosition.right = 'right';
24751 referenceLineDataLabelHorizontalPosition.type = powerbi.createEnumType([
24752 { value: referenceLineDataLabelHorizontalPosition.left, displayName: function (resources) { return resources.get('Visual_Reference_Line_Data_Label_Left'); } },
24753 { value: referenceLineDataLabelHorizontalPosition.right, displayName: function (resources) { return resources.get('Visual_Reference_Line_Data_Label_Right'); } },
24754 ]);
24755 })(referenceLineDataLabelHorizontalPosition = visuals.referenceLineDataLabelHorizontalPosition || (visuals.referenceLineDataLabelHorizontalPosition = {}));
24756 var referenceLineDataLabelVerticalPosition;
24757 (function (referenceLineDataLabelVerticalPosition) {
24758 referenceLineDataLabelVerticalPosition.above = 'above';
24759 referenceLineDataLabelVerticalPosition.under = 'under';
24760 referenceLineDataLabelVerticalPosition.type = powerbi.createEnumType([
24761 { value: referenceLineDataLabelVerticalPosition.above, displayName: function (resources) { return resources.get('Visual_Reference_Line_Data_Label_Above'); } },
24762 { value: referenceLineDataLabelVerticalPosition.under, displayName: function (resources) { return resources.get('Visual_Reference_Line_Data_Label_Under'); } },
24763 ]);
24764 })(referenceLineDataLabelVerticalPosition = visuals.referenceLineDataLabelVerticalPosition || (visuals.referenceLineDataLabelVerticalPosition = {}));
24765 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24766})(powerbi || (powerbi = {}));
24767/*
24768* Power BI Visualizations
24769*
24770* Copyright (c) Microsoft Corporation
24771* All rights reserved.
24772* MIT License
24773*
24774* Permission is hereby granted, free of charge, to any person obtaining a copy
24775* of this software and associated documentation files (the ""Software""), to deal
24776* in the Software without restriction, including without limitation the rights
24777* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24778* copies of the Software, and to permit persons to whom the Software is
24779* furnished to do so, subject to the following conditions:
24780*
24781* The above copyright notice and this permission notice shall be included in
24782* all copies or substantial portions of the Software.
24783*
24784* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24785* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24786* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24787* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24788* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24789* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24790* THE SOFTWARE.
24791*/
24792var powerbi;
24793(function (powerbi) {
24794 var visuals;
24795 (function (visuals) {
24796 var slicerOrientation;
24797 (function (slicerOrientation) {
24798 slicerOrientation.type = powerbi.createEnumType([
24799 { value: 0 /* Vertical */, displayName: function (resources) { return resources.get('Slicer_Orientation_Vertical'); } },
24800 { value: 1 /* Horizontal */, displayName: function (resources) { return resources.get('Slicer_Orientation_Horizontal'); } },
24801 ]);
24802 })(slicerOrientation = visuals.slicerOrientation || (visuals.slicerOrientation = {}));
24803 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24804})(powerbi || (powerbi = {}));
24805/*
24806 * Power BI Visualizations
24807 *
24808 * Copyright (c) Microsoft Corporation
24809 * All rights reserved.
24810 * MIT License
24811 *
24812 * Permission is hereby granted, free of charge, to any person obtaining a copy
24813 * of this software and associated documentation files (the ""Software""), to deal
24814 * in the Software without restriction, including without limitation the rights
24815 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24816 * copies of the Software, and to permit persons to whom the Software is
24817 * furnished to do so, subject to the following conditions:
24818 *
24819 * The above copyright notice and this permission notice shall be included in
24820 * all copies or substantial portions of the Software.
24821 *
24822 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24823 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24824 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24825 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24826 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24827 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24828 * THE SOFTWARE.
24829 */
24830var powerbi;
24831(function (powerbi) {
24832 var visuals;
24833 (function (visuals) {
24834 var yAxisPosition;
24835 (function (yAxisPosition) {
24836 yAxisPosition.left = 'Left';
24837 yAxisPosition.right = 'Right';
24838 yAxisPosition.type = powerbi.createEnumType([
24839 { value: yAxisPosition.left, displayName: function (resources) { return resources.get('Visual_yAxis_Left'); } },
24840 { value: yAxisPosition.right, displayName: function (resources) { return resources.get('Visual_yAxis_Right'); } },
24841 ]);
24842 })(yAxisPosition = visuals.yAxisPosition || (visuals.yAxisPosition = {}));
24843 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24844})(powerbi || (powerbi = {}));
24845/*
24846* Power BI Visualizations
24847*
24848* Copyright (c) Microsoft Corporation
24849* All rights reserved.
24850* MIT License
24851*
24852* Permission is hereby granted, free of charge, to any person obtaining a copy
24853* of this software and associated documentation files (the ""Software""), to deal
24854* in the Software without restriction, including without limitation the rights
24855* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24856* copies of the Software, and to permit persons to whom the Software is
24857* furnished to do so, subject to the following conditions:
24858*
24859* The above copyright notice and this permission notice shall be included in
24860* all copies or substantial portions of the Software.
24861*
24862* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24863* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24864* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24865* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24866* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24867* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24868* THE SOFTWARE.
24869*/
24870var powerbi;
24871(function (powerbi) {
24872 var visuals;
24873 (function (visuals) {
24874 var AnimatorCommon;
24875 (function (AnimatorCommon) {
24876 AnimatorCommon.MinervaAnimationDuration = 250;
24877 // The maximum number of data points we can performantly animate with SVG. If we have more, turn off animations.
24878 AnimatorCommon.MaxDataPointsToAnimate = 1000;
24879 function GetAnimationDuration(animator, suppressAnimations) {
24880 return (suppressAnimations || !animator) ? 0 : animator.getDuration();
24881 }
24882 AnimatorCommon.GetAnimationDuration = GetAnimationDuration;
24883 })(AnimatorCommon = visuals.AnimatorCommon || (visuals.AnimatorCommon = {}));
24884 /**
24885 * We just need to have a non-null animator to allow axis animations in cartesianChart.
24886 * Note: Use this temporarily for Line/Scatter until we add more animations (MinervaPlugins only).
24887 */
24888 var BaseAnimator = (function () {
24889 function BaseAnimator(options) {
24890 if (options && options.duration) {
24891 this.animationDuration = options.duration;
24892 }
24893 this.animationDuration = this.animationDuration >= 0 ? this.animationDuration : AnimatorCommon.MinervaAnimationDuration;
24894 }
24895 BaseAnimator.prototype.getDuration = function () {
24896 return this.animationDuration;
24897 };
24898 BaseAnimator.prototype.animate = function (options) {
24899 return null;
24900 };
24901 BaseAnimator.prototype.getEasing = function () {
24902 return 'cubic-in-out';
24903 };
24904 return BaseAnimator;
24905 }());
24906 visuals.BaseAnimator = BaseAnimator;
24907 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
24908})(powerbi || (powerbi = {}));
24909/*
24910 * Power BI Visualizations
24911 *
24912 * Copyright (c) Microsoft Corporation
24913 * All rights reserved.
24914 * MIT License
24915 *
24916 * Permission is hereby granted, free of charge, to any person obtaining a copy
24917 * of this software and associated documentation files (the ""Software""), to deal
24918 * in the Software without restriction, including without limitation the rights
24919 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24920 * copies of the Software, and to permit persons to whom the Software is
24921 * furnished to do so, subject to the following conditions:
24922 *
24923 * The above copyright notice and this permission notice shall be included in
24924 * all copies or substantial portions of the Software.
24925 *
24926 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24927 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24928 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24929 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24930 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24931 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24932 * THE SOFTWARE.
24933 */
24934var powerbi;
24935(function (powerbi) {
24936 var visuals;
24937 (function (visuals) {
24938 var WebColumnChartAnimator = (function (_super) {
24939 __extends(WebColumnChartAnimator, _super);
24940 function WebColumnChartAnimator(options) {
24941 _super.call(this, options);
24942 }
24943 WebColumnChartAnimator.prototype.animate = function (options) {
24944 var result = {
24945 failed: true,
24946 shapes: null,
24947 };
24948 var viewModel = options.viewModel;
24949 var previousViewModel = this.previousViewModel;
24950 var dataPointCount = viewModel.categories.length * viewModel.series.length;
24951 if (dataPointCount > visuals.AnimatorCommon.MaxDataPointsToAnimate) {
24952 // Too many data points to animate.
24953 return result;
24954 }
24955 if (!previousViewModel) {
24956 }
24957 else if (viewModel.hasHighlights && !previousViewModel.hasHighlights) {
24958 result = this.animateNormalToHighlighted(options);
24959 }
24960 else if (viewModel.hasHighlights && previousViewModel.hasHighlights) {
24961 result = this.animateHighlightedToHighlighted(options);
24962 }
24963 else if (!viewModel.hasHighlights && previousViewModel.hasHighlights) {
24964 result = this.animateHighlightedToNormal(options);
24965 }
24966 this.previousViewModel = viewModel;
24967 return result;
24968 };
24969 WebColumnChartAnimator.prototype.animateNormalToHighlighted = function (options) {
24970 var data = options.viewModel;
24971 var itemCS = options.itemCS;
24972 var shapeSelection = options.series.selectAll(itemCS.selector);
24973 var shapes = shapeSelection.data(function (d) { return d.data; }, function (d) { return d.key; });
24974 var hasHighlights = data.hasHighlights;
24975 shapes
24976 .enter()
24977 .append('rect')
24978 .attr("class", function (d) { return itemCS.class.concat(d.highlight ? " highlight" : ""); })
24979 .attr(options.layout.shapeLayoutWithoutHighlights); // Start out at the non-highlight layout
24980 shapes
24981 .style("fill", function (d) { return d.color; })
24982 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, false, hasHighlights); })
24983 .transition()
24984 .duration(this.animationDuration)
24985 .attr(options.layout.shapeLayout);
24986 shapes
24987 .exit()
24988 .remove();
24989 return {
24990 failed: false,
24991 shapes: shapes,
24992 };
24993 };
24994 WebColumnChartAnimator.prototype.animateHighlightedToHighlighted = function (options) {
24995 var shapes = this.animateDefaultShapes(options.viewModel, options.series, options.layout, options.itemCS);
24996 return {
24997 failed: false,
24998 shapes: shapes,
24999 };
25000 };
25001 WebColumnChartAnimator.prototype.animateHighlightedToNormal = function (options) {
25002 var itemCS = options.itemCS;
25003 var shapeSelection = options.series.selectAll(itemCS.selector);
25004 var shapes = shapeSelection.data(function (d) { return d.data; }, function (d) { return d.key; });
25005 var hasSelection = options.interactivityService && options.interactivityService.hasSelection();
25006 shapes
25007 .enter()
25008 .append('rect')
25009 .attr("class", function (d) { return itemCS.class.concat(d.highlight ? " highlight" : ""); });
25010 shapes
25011 .style("fill", function (d) { return d.color; })
25012 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, d.selected, !d.selected); })
25013 .transition()
25014 .duration(this.animationDuration)
25015 .attr(options.layout.shapeLayout)
25016 .transition()
25017 .duration(0)
25018 .delay(this.animationDuration)
25019 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, false); });
25020 shapes
25021 .exit()
25022 .transition()
25023 .duration(this.animationDuration)
25024 .attr(hasSelection ? options.layout.zeroShapeLayout : options.layout.shapeLayoutWithoutHighlights)
25025 .remove();
25026 return {
25027 failed: false,
25028 shapes: shapes,
25029 };
25030 };
25031 WebColumnChartAnimator.prototype.animateDefaultShapes = function (data, series, layout, itemCS) {
25032 var shapeSelection = series.selectAll(itemCS.selector);
25033 var shapes = shapeSelection.data(function (d) { return d.data; }, function (d) { return d.key; });
25034 shapes
25035 .enter()
25036 .append('rect')
25037 .attr("class", function (d) { return itemCS.class.concat(d.highlight ? " highlight" : ""); });
25038 shapes
25039 .style("fill", function (d) { return d.color; })
25040 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, false, data.hasHighlights); })
25041 .transition()
25042 .duration(this.animationDuration)
25043 .attr(layout.shapeLayout);
25044 shapes
25045 .exit()
25046 .remove();
25047 return shapes;
25048 };
25049 return WebColumnChartAnimator;
25050 }(visuals.BaseAnimator));
25051 visuals.WebColumnChartAnimator = WebColumnChartAnimator;
25052 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
25053})(powerbi || (powerbi = {}));
25054/*
25055 * Power BI Visualizations
25056 *
25057 * Copyright (c) Microsoft Corporation
25058 * All rights reserved.
25059 * MIT License
25060 *
25061 * Permission is hereby granted, free of charge, to any person obtaining a copy
25062 * of this software and associated documentation files (the ""Software""), to deal
25063 * in the Software without restriction, including without limitation the rights
25064 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25065 * copies of the Software, and to permit persons to whom the Software is
25066 * furnished to do so, subject to the following conditions:
25067 *
25068 * The above copyright notice and this permission notice shall be included in
25069 * all copies or substantial portions of the Software.
25070 *
25071 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25072 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25073 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25074 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25075 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25076 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25077 * THE SOFTWARE.
25078 */
25079var powerbi;
25080(function (powerbi) {
25081 var visuals;
25082 (function (visuals) {
25083 var WebDonutChartAnimator = (function (_super) {
25084 __extends(WebDonutChartAnimator, _super);
25085 function WebDonutChartAnimator(options) {
25086 _super.call(this, options);
25087 }
25088 WebDonutChartAnimator.prototype.animate = function (options) {
25089 var result = {
25090 failed: true,
25091 shapes: null,
25092 highlightShapes: null,
25093 };
25094 var viewModel = options.viewModel;
25095 var previousViewModel = this.previousViewModel;
25096 if (!previousViewModel) {
25097 }
25098 else if (viewModel.hasHighlights && !previousViewModel.hasHighlights) {
25099 result = this.animateNormalToHighlighted(options);
25100 }
25101 else if (viewModel.hasHighlights && previousViewModel.hasHighlights) {
25102 result = this.animateHighlightedToHighlighted(options);
25103 }
25104 else if (!viewModel.hasHighlights && previousViewModel.hasHighlights) {
25105 result = this.animateHighlightedToNormal(options);
25106 }
25107 this.previousViewModel = viewModel;
25108 return result;
25109 };
25110 WebDonutChartAnimator.prototype.animateNormalToHighlighted = function (options) {
25111 var shapes = this.animateDefaultShapes(options);
25112 var highlightShapes = options.graphicsContext.select('.slices')
25113 .selectAll('path.slice-highlight')
25114 .data(options.viewModel.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }), function (d) { return d.data.identity.getKey(); });
25115 highlightShapes.enter()
25116 .insert('path')
25117 .classed('slice-highlight', true)
25118 .each(function (d) { this._current = d; });
25119 visuals.DonutChart.isSingleColor(options.viewModel.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }));
25120 highlightShapes
25121 .style('fill', function (d) { return d.data.color ? d.data.color : options.colors.getNewColorScale().getColor(d.data.identity.getKey()).value; })
25122 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, true, false, options.viewModel.hasHighlights); })
25123 .style("stroke-dasharray", function (d) { return visuals.DonutChart.drawStrokeForDonutChart(options.radius, options.innerArcRadiusRatio, d, options.sliceWidthRatio, d.data.highlightRatio); })
25124 .style("stroke-width", function (d) { return d.data.strokeWidth; })
25125 .attr(options.layout.shapeLayout) // Start at the non-highlight layout, then transition to the highlight layout.
25126 .transition()
25127 .duration(this.animationDuration)
25128 .attr(options.layout.highlightShapeLayout);
25129 highlightShapes.exit()
25130 .remove();
25131 visuals.NewDataLabelUtils.drawDefaultLabels(options.labelGraphicsContext, options.labels, false, true, true /*has tooltip */);
25132 visuals.NewDataLabelUtils.drawLabelLeaderLines(options.labelGraphicsContext, options.labels);
25133 return {
25134 failed: false,
25135 shapes: shapes,
25136 highlightShapes: highlightShapes,
25137 };
25138 };
25139 WebDonutChartAnimator.prototype.animateHighlightedToHighlighted = function (options) {
25140 var shapes = this.animateDefaultShapes(options);
25141 var highlightShapes = this.animateDefaultHighlightShapes(options);
25142 visuals.NewDataLabelUtils.drawDefaultLabels(options.labelGraphicsContext, options.labels, false, true, true /*has tooltip */);
25143 visuals.NewDataLabelUtils.drawLabelLeaderLines(options.labelGraphicsContext, options.labels);
25144 return {
25145 failed: false,
25146 shapes: shapes,
25147 highlightShapes: highlightShapes,
25148 };
25149 };
25150 WebDonutChartAnimator.prototype.animateHighlightedToNormal = function (options) {
25151 var hasSelection = options.interactivityService && options.interactivityService.hasSelection();
25152 var duration = this.animationDuration;
25153 var shapes = options.graphicsContext.select('.slices')
25154 .selectAll('path.slice')
25155 .data(options.viewModel.dataPoints, function (d) { return d.data.identity.getKey(); });
25156 shapes.enter()
25157 .insert('path')
25158 .classed('slice', true)
25159 .each(function (d) { this._current = d; });
25160 visuals.DonutChart.isSingleColor(options.viewModel.dataPoints);
25161 // For any slice that is selected we want to keep showing it as dimmed (partially highlighted). After the highlight animation
25162 // finishes we will set the opacity based on the selection state.
25163 shapes
25164 .style('fill', function (d) { return d.data.color ? d.data.color : options.colors.getNewColorScale().getColor(d.data.identity.getKey()).value; })
25165 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, d.data.selected, !d.data.selected); })
25166 .style("stroke-dasharray", function (d) { return visuals.DonutChart.drawStrokeForDonutChart(options.radius, options.innerArcRadiusRatio, d, options.sliceWidthRatio); })
25167 .style("stroke-width", function (d) { return d.data.strokeWidth; })
25168 .transition()
25169 .duration(duration)
25170 .attr(options.layout.shapeLayout)
25171 .transition()
25172 .duration(0)
25173 .delay(duration)
25174 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, false); });
25175 ;
25176 shapes.exit()
25177 .remove();
25178 var highlightShapes = options.graphicsContext.select('.slices')
25179 .selectAll('path.slice-highlight')
25180 .data(options.viewModel.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }), function (d) { return d.data.identity.getKey(); });
25181 highlightShapes.enter()
25182 .insert('path')
25183 .classed('slice-highlight', true)
25184 .each(function (d) { this._current = d; });
25185 visuals.DonutChart.isSingleColor(options.viewModel.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }));
25186 highlightShapes
25187 .style('fill', function (d) { return d.data.color ? d.data.color : options.colors.getNewColorScale().getColor(d.data.identity.getKey()).value; })
25188 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(false, true, false, true); })
25189 .style("stroke-dasharray", function (d) { return visuals.DonutChart.drawStrokeForDonutChart(options.radius, options.innerArcRadiusRatio, d, options.sliceWidthRatio, d.data.highlightRatio); })
25190 .style("stroke-width", function (d) { return d.data.strokeWidth; })
25191 .transition()
25192 .duration(duration)
25193 .attr(hasSelection ? options.layout.zeroShapeLayout : options.layout.shapeLayout) // Transition to the non-highlight layout
25194 .remove();
25195 highlightShapes.exit()
25196 .remove();
25197 visuals.NewDataLabelUtils.drawDefaultLabels(options.labelGraphicsContext, options.labels, false, true, true /*has tooltip */);
25198 visuals.NewDataLabelUtils.drawLabelLeaderLines(options.labelGraphicsContext, options.labels);
25199 return {
25200 failed: false,
25201 shapes: shapes,
25202 highlightShapes: highlightShapes,
25203 };
25204 };
25205 WebDonutChartAnimator.prototype.animateDefaultShapes = function (options) {
25206 var shapes = options.graphicsContext.select('.slices')
25207 .selectAll('path.slice')
25208 .data(options.viewModel.dataPoints, function (d) { return d.data.identity.getKey(); });
25209 shapes.enter()
25210 .insert('path')
25211 .classed('slice', true)
25212 .each(function (d) { this._current = d; });
25213 visuals.DonutChart.isSingleColor(options.viewModel.dataPoints);
25214 shapes
25215 .style('fill', function (d) { return d.data.color ? d.data.color : options.colors.getNewColorScale().getColor(d.data.identity.getKey()).value; })
25216 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, false, options.viewModel.hasHighlights); })
25217 .style("stroke-dasharray", function (d) { return visuals.DonutChart.drawStrokeForDonutChart(options.radius, options.innerArcRadiusRatio, d, options.sliceWidthRatio); })
25218 .style("stroke-width", function (d) { return d.data.strokeWidth; })
25219 .transition()
25220 .duration(this.animationDuration)
25221 .attr(options.layout.shapeLayout);
25222 shapes.exit()
25223 .remove();
25224 return shapes;
25225 };
25226 WebDonutChartAnimator.prototype.animateDefaultHighlightShapes = function (options) {
25227 var highlightShapes = options.graphicsContext.select('.slices')
25228 .selectAll('path.slice-highlight')
25229 .data(options.viewModel.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }), function (d) { return d.data.identity.getKey(); });
25230 highlightShapes.enter()
25231 .insert('path')
25232 .classed('slice-highlight', true)
25233 .each(function (d) { this._current = d; });
25234 visuals.DonutChart.isSingleColor(options.viewModel.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }));
25235 highlightShapes
25236 .style('fill', function (d) { return d.data.color ? d.data.color : options.colors.getNewColorScale().getColor(d.data.identity.getKey()).value; })
25237 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, true, false, options.viewModel.hasHighlights); })
25238 .style("stroke-dasharray", function (d) { return visuals.DonutChart.drawStrokeForDonutChart(options.radius, options.innerArcRadiusRatio, d, options.sliceWidthRatio, d.data.highlightRatio); })
25239 .style("stroke-width", function (d) { return d.data.strokeWidth; })
25240 .transition()
25241 .duration(this.animationDuration)
25242 .attr(options.layout.highlightShapeLayout);
25243 highlightShapes.exit()
25244 .remove();
25245 return highlightShapes;
25246 };
25247 return WebDonutChartAnimator;
25248 }(visuals.BaseAnimator));
25249 visuals.WebDonutChartAnimator = WebDonutChartAnimator;
25250 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
25251})(powerbi || (powerbi = {}));
25252/*
25253* Power BI Visualizations
25254*
25255* Copyright (c) Microsoft Corporation
25256* All rights reserved.
25257* MIT License
25258*
25259* Permission is hereby granted, free of charge, to any person obtaining a copy
25260* of this software and associated documentation files (the ""Software""), to deal
25261* in the Software without restriction, including without limitation the rights
25262* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25263* copies of the Software, and to permit persons to whom the Software is
25264* furnished to do so, subject to the following conditions:
25265*
25266* The above copyright notice and this permission notice shall be included in
25267* all copies or substantial portions of the Software.
25268*
25269* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25270* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25271* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25272* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25273* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25274* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25275* THE SOFTWARE.
25276*/
25277var powerbi;
25278(function (powerbi) {
25279 var visuals;
25280 (function (visuals) {
25281 var WebFunnelAnimator = (function (_super) {
25282 __extends(WebFunnelAnimator, _super);
25283 function WebFunnelAnimator(options) {
25284 _super.call(this, options);
25285 }
25286 WebFunnelAnimator.prototype.animate = function (options) {
25287 var result = {
25288 failed: true,
25289 shapes: null,
25290 dataLabels: null,
25291 };
25292 var viewModel = options.viewModel;
25293 var previousViewModel = this.previousViewModel;
25294 if (!previousViewModel) {
25295 }
25296 else if (viewModel.hasHighlights && !previousViewModel.hasHighlights) {
25297 result = this.animateNormalToHighlighted(options);
25298 }
25299 else if (viewModel.hasHighlights && previousViewModel.hasHighlights) {
25300 result = this.animateHighlightedToHighlighted(options);
25301 }
25302 else if (!viewModel.hasHighlights && previousViewModel.hasHighlights) {
25303 result = this.animateHighlightedToNormal(options);
25304 }
25305 this.previousViewModel = viewModel;
25306 return result;
25307 };
25308 WebFunnelAnimator.prototype.animateNormalToHighlighted = function (options) {
25309 var data = options.viewModel;
25310 var layout = options.layout;
25311 var hasHighlights = true;
25312 var hasSelection = false;
25313 this.animateDefaultAxis(options.axisGraphicsContext, options.axisOptions, options.isHidingPercentBars);
25314 var shapes = options.shapeGraphicsContext.selectAll(visuals.FunnelChart.Selectors.funnel.bars.selector).data(data.slices, function (d) { return d.key; });
25315 shapes.enter()
25316 .append('rect')
25317 .attr("class", function (d) { return d.highlight ? visuals.FunnelChart.FunnelBarHighlightClass : visuals.FunnelChart.Selectors.funnel.bars.class; })
25318 .attr(layout.shapeLayoutWithoutHighlights); // Start by laying out all rectangles ignoring highlights
25319 shapes
25320 .style("fill", function (d) { return d.color; })
25321 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, hasHighlights); })
25322 .transition()
25323 .duration(this.animationDuration)
25324 .attr(layout.shapeLayout); // Then transition to the layout that uses highlights
25325 shapes.exit().remove();
25326 this.animatePercentBars(options);
25327 var dataLabels = this.animateDefaultDataLabels(options);
25328 return {
25329 failed: false,
25330 shapes: shapes,
25331 dataLabels: dataLabels,
25332 };
25333 };
25334 WebFunnelAnimator.prototype.animateHighlightedToHighlighted = function (options) {
25335 var data = options.viewModel;
25336 var layout = options.layout;
25337 this.animateDefaultAxis(options.axisGraphicsContext, options.axisOptions, options.isHidingPercentBars);
25338 // Simply animate to the new shapes.
25339 var shapes = this.animateDefaultShapes(data, data.slices, options.shapeGraphicsContext, layout);
25340 this.animatePercentBars(options);
25341 var dataLabels = this.animateDefaultDataLabels(options);
25342 return {
25343 failed: false,
25344 shapes: shapes,
25345 dataLabels: dataLabels,
25346 };
25347 };
25348 WebFunnelAnimator.prototype.animateHighlightedToNormal = function (options) {
25349 var data = options.viewModel;
25350 var layout = options.layout;
25351 var hasSelection = options.interactivityService ? options.interactivityService.hasSelection() : false;
25352 this.animateDefaultAxis(options.axisGraphicsContext, options.axisOptions, options.isHidingPercentBars);
25353 var shapes = options.shapeGraphicsContext.selectAll(visuals.FunnelChart.Selectors.funnel.bars.selector).data(data.slices, function (d) { return d.key; });
25354 shapes.enter()
25355 .append('rect')
25356 .attr("class", function (d) { return d.highlight ? visuals.FunnelChart.FunnelBarHighlightClass : visuals.FunnelChart.Selectors.funnel.bars.class; });
25357 shapes
25358 .style("fill", function (d) { return d.color; })
25359 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, !d.selected); })
25360 .transition()
25361 .duration(this.animationDuration)
25362 .attr(layout.shapeLayoutWithoutHighlights) // Transition to layout without highlights
25363 .transition()
25364 .duration(0)
25365 .delay(this.animationDuration)
25366 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, false); });
25367 var exitShapes = shapes.exit();
25368 exitShapes
25369 .transition()
25370 .duration(this.animationDuration)
25371 .attr(hasSelection ? layout.zeroShapeLayout : layout.shapeLayoutWithoutHighlights) // Transition to layout without highlights
25372 .remove();
25373 this.animatePercentBars(options);
25374 var dataLabels = this.animateDefaultDataLabels(options);
25375 return {
25376 failed: false,
25377 shapes: shapes,
25378 dataLabels: dataLabels,
25379 };
25380 };
25381 WebFunnelAnimator.prototype.animateDefaultAxis = function (graphicsContext, axisOptions, isHidingPercentBars) {
25382 var xScaleForAxis = d3.scale.ordinal()
25383 .domain(axisOptions.categoryLabels)
25384 .rangeBands([axisOptions.rangeStart, axisOptions.rangeEnd], axisOptions.barToSpaceRatio, isHidingPercentBars ? axisOptions.barToSpaceRatio : visuals.FunnelChart.PercentBarToBarRatio);
25385 var xAxis = d3.svg.axis()
25386 .scale(xScaleForAxis)
25387 .orient("right")
25388 .tickPadding(visuals.FunnelChart.TickPadding)
25389 .innerTickSize(visuals.FunnelChart.InnerTickSize);
25390 graphicsContext.classed('axis', true)
25391 .transition()
25392 .duration(this.animationDuration)
25393 .attr('transform', visuals.SVGUtil.translate(0, axisOptions.margin.top))
25394 .call(xAxis);
25395 };
25396 WebFunnelAnimator.prototype.animateDefaultShapes = function (data, slices, graphicsContext, layout) {
25397 var hasHighlights = data.hasHighlights;
25398 var shapes = graphicsContext.selectAll(visuals.FunnelChart.Selectors.funnel.bars.selector).data(slices, function (d) { return d.key; });
25399 shapes.enter()
25400 .append('rect')
25401 .attr("class", function (d) { return d.highlight ? visuals.FunnelChart.FunnelBarHighlightClass : visuals.FunnelChart.Selectors.funnel.bars.class; });
25402 shapes
25403 .style("fill", function (d) { return d.color; })
25404 .style("fill-opacity", function (d) { return function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, false, hasHighlights); }; })
25405 .transition()
25406 .duration(this.animationDuration)
25407 .attr(layout.shapeLayout);
25408 shapes.exit().remove();
25409 return shapes;
25410 };
25411 WebFunnelAnimator.prototype.animateDefaultDataLabels = function (options) {
25412 var dataLabels;
25413 if (options.viewModel.dataLabelsSettings.show && options.viewModel.canShowDataLabels) {
25414 dataLabels = visuals.dataLabelUtils.drawDefaultLabelsForFunnelChart(options.viewModel.slices, options.labelGraphicsContext, options.labelLayout, true, this.animationDuration);
25415 }
25416 else {
25417 visuals.dataLabelUtils.cleanDataLabels(options.labelGraphicsContext);
25418 }
25419 return dataLabels;
25420 };
25421 WebFunnelAnimator.prototype.animatePercentBars = function (options) {
25422 var data = options.viewModel;
25423 var isHidingPercentBars = options.isHidingPercentBars;
25424 if (isHidingPercentBars || !data.slices || (data.hasHighlights ? data.slices.length / 2 : data.slices.length) < 2) {
25425 // TODO: call percentBarComponents with flag with empty data to clear drawing smoothly
25426 this.animatePercentBarComponents([], options);
25427 return;
25428 }
25429 var slices = [data.slices[data.hasHighlights ? 1 : 0], data.slices[data.slices.length - 1]];
25430 var baseline = visuals.FunnelChart.getFunnelSliceValue(slices[0]);
25431 if (baseline <= 0) {
25432 // TODO: call percentBarComponents with flag with empty data to clear drawing smoothly
25433 this.animatePercentBarComponents([], options);
25434 return;
25435 }
25436 var percentData = slices.map(function (slice, i) { return {
25437 value: visuals.FunnelChart.getFunnelSliceValue(slice),
25438 percent: i === 0 ? 1 : visuals.FunnelChart.getFunnelSliceValue(slice) / baseline,
25439 isTop: i === 0,
25440 }; });
25441 this.animatePercentBarComponents(percentData, options);
25442 };
25443 WebFunnelAnimator.prototype.animateToFunnelPercent = function (context, targetData, layout) {
25444 return context
25445 .data(targetData)
25446 .transition()
25447 .duration(this.animationDuration)
25448 .attr(layout);
25449 };
25450 WebFunnelAnimator.prototype.animatePercentBarComponents = function (data, options) {
25451 var graphicsContext = options.percentGraphicsContext;
25452 var layout = options.layout;
25453 var zeroData = [
25454 { percent: 0, value: 0, isTop: true },
25455 { percent: 0, value: 0, isTop: false },
25456 ];
25457 // Main line
25458 var mainLine = graphicsContext.selectAll(visuals.FunnelChart.Selectors.percentBar.mainLine.selector).data(data);
25459 this.animateToFunnelPercent(mainLine.exit(), zeroData, layout.percentBarLayout.mainLine)
25460 .remove();
25461 mainLine.enter()
25462 .append('line')
25463 .classed(visuals.FunnelChart.Selectors.percentBar.mainLine.class, true)
25464 .data(zeroData)
25465 .attr(layout.percentBarLayout.mainLine);
25466 this.animateToFunnelPercent(mainLine, data, layout.percentBarLayout.mainLine);
25467 // Left tick
25468 var leftTick = graphicsContext.selectAll(visuals.FunnelChart.Selectors.percentBar.leftTick.selector).data(data);
25469 this.animateToFunnelPercent(leftTick.exit(), zeroData, layout.percentBarLayout.leftTick)
25470 .remove();
25471 leftTick.enter()
25472 .append('line')
25473 .classed(visuals.FunnelChart.Selectors.percentBar.leftTick.class, true)
25474 .data(zeroData)
25475 .attr(layout.percentBarLayout.leftTick);
25476 this.animateToFunnelPercent(leftTick, data, layout.percentBarLayout.leftTick);
25477 // Right tick
25478 var rightTick = graphicsContext.selectAll(visuals.FunnelChart.Selectors.percentBar.rightTick.selector).data(data);
25479 this.animateToFunnelPercent(rightTick.exit(), zeroData, layout.percentBarLayout.rightTick)
25480 .remove();
25481 rightTick.enter()
25482 .append('line')
25483 .classed(visuals.FunnelChart.Selectors.percentBar.rightTick.class, true)
25484 .data(zeroData)
25485 .attr(layout.percentBarLayout.rightTick);
25486 this.animateToFunnelPercent(rightTick, data, layout.percentBarLayout.rightTick);
25487 // Text
25488 var text = graphicsContext.selectAll(visuals.FunnelChart.Selectors.percentBar.text.selector).data(data);
25489 this.animateToFunnelPercent(text.exit(), zeroData, layout.percentBarLayout.text)
25490 .remove();
25491 text.enter()
25492 .append('text')
25493 .classed(visuals.FunnelChart.Selectors.percentBar.text.class, true)
25494 .data(zeroData)
25495 .attr(layout.percentBarLayout.text);
25496 this.animateToFunnelPercent(text, data, layout.percentBarLayout.text)
25497 .text(function (fp) {
25498 return powerbi.formattingService.formatValue(fp.percent, visuals.valueFormatter.getLocalizedString("Percentage1"));
25499 });
25500 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(options.visualInitOptions);
25501 };
25502 return WebFunnelAnimator;
25503 }(visuals.BaseAnimator));
25504 visuals.WebFunnelAnimator = WebFunnelAnimator;
25505 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
25506})(powerbi || (powerbi = {}));
25507/*
25508* Power BI Visualizations
25509*
25510* Copyright (c) Microsoft Corporation
25511* All rights reserved.
25512* MIT License
25513*
25514* Permission is hereby granted, free of charge, to any person obtaining a copy
25515* of this software and associated documentation files (the ""Software""), to deal
25516* in the Software without restriction, including without limitation the rights
25517* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25518* copies of the Software, and to permit persons to whom the Software is
25519* furnished to do so, subject to the following conditions:
25520*
25521* The above copyright notice and this permission notice shall be included in
25522* all copies or substantial portions of the Software.
25523*
25524* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25525* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25526* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25527* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25528* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25529* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25530* THE SOFTWARE.
25531*/
25532var powerbi;
25533(function (powerbi) {
25534 var visuals;
25535 (function (visuals) {
25536 var WebTreemapAnimator = (function (_super) {
25537 __extends(WebTreemapAnimator, _super);
25538 function WebTreemapAnimator(options) {
25539 _super.call(this, options);
25540 }
25541 WebTreemapAnimator.prototype.animate = function (options) {
25542 var result = {
25543 failed: true,
25544 shapes: null,
25545 highlightShapes: null,
25546 majorLabels: null,
25547 minorLabels: null,
25548 };
25549 var viewModel = options.viewModel;
25550 var previousViewModel = this.previousViewModel;
25551 if (!previousViewModel) {
25552 }
25553 else if (viewModel.hasHighlights && !previousViewModel.hasHighlights) {
25554 result = this.animateNormalToHighlighted(options);
25555 }
25556 else if (viewModel.hasHighlights && previousViewModel.hasHighlights) {
25557 result = this.animateHighlightedToHighlighted(options);
25558 }
25559 else if (!viewModel.hasHighlights && previousViewModel.hasHighlights) {
25560 result = this.animateHighlightedToNormal(options);
25561 }
25562 this.previousViewModel = viewModel;
25563 return result;
25564 };
25565 WebTreemapAnimator.prototype.animateNormalToHighlighted = function (options) {
25566 var hasSelection = false;
25567 var hasHighlights = true;
25568 var shapes = this.animateDefaultShapes(options.shapeGraphicsContext, options.nodes, hasSelection, hasHighlights, options.layout);
25569 var highlightShapes = options.shapeGraphicsContext.selectAll('.' + visuals.Treemap.HighlightNodeClassName)
25570 .data(options.highlightNodes, function (d) { return d.key + "highlight"; });
25571 highlightShapes.enter().append('rect')
25572 .attr('class', options.layout.highlightShapeClass)
25573 .attr(options.layout.shapeLayout); // Start using the normal shape layout
25574 highlightShapes
25575 .style("fill", function (d) { return visuals.Treemap.getFill(d, true); })
25576 .style("fill-opacity", function (d) { return visuals.Treemap.getFillOpacity(d, hasSelection, hasHighlights, true); })
25577 .transition()
25578 .duration(this.animationDuration)
25579 .attr(options.layout.highlightShapeLayout); // Animate to the highlighted positions
25580 highlightShapes.exit().remove();
25581 var majorLabels = this.animateDefaultMajorLabels(options.labelGraphicsContext, options.majorLabeledNodes, options.labelSettings, options.layout);
25582 var minorLabels = this.animateDefaultMinorLabels(options.labelGraphicsContext, options.minorLabeledNodes, options.labelSettings, options.layout);
25583 return {
25584 failed: false,
25585 shapes: shapes,
25586 highlightShapes: highlightShapes,
25587 majorLabels: majorLabels,
25588 minorLabels: minorLabels,
25589 };
25590 };
25591 WebTreemapAnimator.prototype.animateHighlightedToHighlighted = function (options) {
25592 var hasSelection = false;
25593 var hasHighlights = true;
25594 var shapes = this.animateDefaultShapes(options.shapeGraphicsContext, options.nodes, hasSelection, hasHighlights, options.layout);
25595 options.shapeGraphicsContext.selectAll('.' + visuals.Treemap.HighlightNodeClassName)
25596 .data(options.highlightNodes, function (d) { return d.key + "highlight"; });
25597 var highlightShapes = this.animateDefaultHighlightShapes(options.shapeGraphicsContext, options.highlightNodes, hasSelection, hasHighlights, options.layout);
25598 var majorLabels = this.animateDefaultMajorLabels(options.labelGraphicsContext, options.majorLabeledNodes, options.labelSettings, options.layout);
25599 var minorLabels = this.animateDefaultMinorLabels(options.labelGraphicsContext, options.minorLabeledNodes, options.labelSettings, options.layout);
25600 return {
25601 failed: false,
25602 shapes: shapes,
25603 highlightShapes: highlightShapes,
25604 majorLabels: majorLabels,
25605 minorLabels: minorLabels,
25606 };
25607 };
25608 WebTreemapAnimator.prototype.animateHighlightedToNormal = function (options) {
25609 var hasSelection = options.interactivityService ? options.interactivityService.hasSelection() : false;
25610 var shapes = options.shapeGraphicsContext.selectAll('.' + visuals.Treemap.TreemapNodeClassName)
25611 .data(options.nodes, function (d) { return d.key; });
25612 shapes.enter().append('rect')
25613 .attr('class', options.layout.shapeClass);
25614 shapes
25615 .transition()
25616 .duration(this.animationDuration)
25617 .style("fill", function (d) { return visuals.Treemap.getFill(d, false); })
25618 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, d.selected, !d.selected); })
25619 .attr(options.layout.shapeLayout)
25620 .transition()
25621 .duration(0)
25622 .delay(this.animationDuration)
25623 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); });
25624 shapes.exit().remove();
25625 var highlightShapes = options.shapeGraphicsContext.selectAll('.' + visuals.Treemap.HighlightNodeClassName)
25626 .data(options.nodes, function (d) { return d.key + "highlight"; });
25627 highlightShapes.enter().append('rect')
25628 .attr('class', options.layout.highlightShapeClass);
25629 highlightShapes
25630 .style("fill", function (d) { return visuals.Treemap.getFill(d, true); })
25631 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, true, d.selected, !d.selected); })
25632 .transition()
25633 .duration(this.animationDuration)
25634 .attr(hasSelection ? options.layout.zeroShapeLayout : options.layout.shapeLayout) // Animate to the normal shape layout or zero shape layout depending on whether we have a selection or not
25635 .remove();
25636 highlightShapes.exit().remove();
25637 var majorLabels = this.animateDefaultMajorLabels(options.labelGraphicsContext, options.majorLabeledNodes, options.labelSettings, options.layout);
25638 var minorLabels = this.animateDefaultMinorLabels(options.labelGraphicsContext, options.minorLabeledNodes, options.labelSettings, options.layout);
25639 return {
25640 failed: false,
25641 shapes: shapes,
25642 highlightShapes: highlightShapes,
25643 majorLabels: majorLabels,
25644 minorLabels: minorLabels,
25645 };
25646 };
25647 WebTreemapAnimator.prototype.animateDefaultShapes = function (context, nodes, hasSelection, hasHighlights, layout) {
25648 var isHighlightShape = false;
25649 var shapes = context.selectAll('.' + visuals.Treemap.TreemapNodeClassName)
25650 .data(nodes, function (d) { return d.key; });
25651 shapes.enter().append('rect')
25652 .attr('class', layout.shapeClass);
25653 shapes
25654 .transition()
25655 .duration(this.animationDuration)
25656 .style("fill", function (d) { return visuals.Treemap.getFill(d, isHighlightShape); })
25657 .style("fill-opacity", function (d) { return visuals.Treemap.getFillOpacity(d, hasSelection, hasHighlights, isHighlightShape); })
25658 .attr(layout.shapeLayout);
25659 shapes.exit().remove();
25660 return shapes;
25661 };
25662 WebTreemapAnimator.prototype.animateDefaultHighlightShapes = function (context, nodes, hasSelection, hasHighlights, layout) {
25663 var isHighlightShape = true;
25664 var highlightShapes = context.selectAll('.' + visuals.Treemap.HighlightNodeClassName)
25665 .data(nodes, function (d) { return d.key + "highlight"; });
25666 highlightShapes.enter().append('rect')
25667 .attr('class', layout.highlightShapeClass);
25668 highlightShapes
25669 .transition()
25670 .duration(this.animationDuration)
25671 .style("fill", function (d) { return visuals.Treemap.getFill(d, isHighlightShape); })
25672 .style("fill-opacity", function (d) { return visuals.Treemap.getFillOpacity(d, hasSelection, hasHighlights, isHighlightShape); })
25673 .attr(layout.highlightShapeLayout);
25674 highlightShapes.exit().remove();
25675 return highlightShapes;
25676 };
25677 WebTreemapAnimator.prototype.animateDefaultMajorLabels = function (context, nodes, labelSettings, layout) {
25678 var labels = context
25679 .selectAll('.' + visuals.Treemap.MajorLabelClassName)
25680 .data(nodes, function (d) { return d.key; });
25681 labels.enter().append('text')
25682 .attr('class', layout.majorLabelClass);
25683 labels
25684 .text(layout.majorLabelText)
25685 .style('fill', function () { return labelSettings.labelColor; })
25686 .transition()
25687 .duration(this.animationDuration)
25688 .attr(layout.majorLabelLayout);
25689 labels.exit().remove();
25690 return labels;
25691 };
25692 WebTreemapAnimator.prototype.animateDefaultMinorLabels = function (context, nodes, labelSettings, layout) {
25693 var labels = context
25694 .selectAll('.' + visuals.Treemap.MinorLabelClassName)
25695 .data(nodes, function (d) { return d.key; });
25696 labels.enter().append('text')
25697 .attr('class', layout.minorLabelClass);
25698 labels
25699 .text(layout.minorLabelText)
25700 .style('fill', function () { return labelSettings.labelColor; })
25701 .transition()
25702 .duration(this.animationDuration)
25703 .attr(layout.minorLabelLayout);
25704 labels.exit().remove();
25705 return labels;
25706 };
25707 return WebTreemapAnimator;
25708 }(visuals.BaseAnimator));
25709 visuals.WebTreemapAnimator = WebTreemapAnimator;
25710 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
25711})(powerbi || (powerbi = {}));
25712/*
25713 * Power BI Visualizations
25714 *
25715 * Copyright (c) Microsoft Corporation
25716 * All rights reserved.
25717 * MIT License
25718 *
25719 * Permission is hereby granted, free of charge, to any person obtaining a copy
25720 * of this software and associated documentation files (the ""Software""), to deal
25721 * in the Software without restriction, including without limitation the rights
25722 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25723 * copies of the Software, and to permit persons to whom the Software is
25724 * furnished to do so, subject to the following conditions:
25725 *
25726 * The above copyright notice and this permission notice shall be included in
25727 * all copies or substantial portions of the Software.
25728 *
25729 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25730 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25731 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25732 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25733 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25734 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25735 * THE SOFTWARE.
25736 */
25737var powerbi;
25738(function (powerbi) {
25739 var visuals;
25740 (function (visuals) {
25741 /**
25742 * This is the baseline for some most common used object properties across visuals.
25743 * When adding new properties, please try to reuse the existing ones.
25744 */
25745 visuals.StandardObjectProperties = {
25746 axisEnd: {
25747 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_End'),
25748 description: powerbi.data.createDisplayNameGetter('Visual_Axis_EndDescription'),
25749 placeHolderText: powerbi.data.createDisplayNameGetter('Visual_Precision_Auto'),
25750 type: { numeric: true },
25751 suppressFormatPainterCopy: true,
25752 },
25753 axisScale: {
25754 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Scale'),
25755 type: { enumeration: visuals.axisScale.type }
25756 },
25757 axisStart: {
25758 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Start'),
25759 description: powerbi.data.createDisplayNameGetter('Visual_Axis_StartDescription'),
25760 placeHolderText: powerbi.data.createDisplayNameGetter('Visual_Precision_Auto'),
25761 type: { numeric: true },
25762 suppressFormatPainterCopy: true,
25763 },
25764 axisStyle: {
25765 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Style'),
25766 type: { enumeration: visuals.axisStyle.type }
25767 },
25768 axisType: {
25769 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Type'),
25770 type: { enumeration: visuals.axisType.type },
25771 },
25772 backColor: {
25773 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColor'),
25774 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColor_Desc'),
25775 type: { fill: { solid: { color: true } } }
25776 },
25777 dataColor: {
25778 displayName: powerbi.data.createDisplayNameGetter('Visual_LabelsFill'),
25779 description: powerbi.data.createDisplayNameGetter('Visual_LabelsFillDescription'),
25780 type: { fill: { solid: { color: true } } }
25781 },
25782 dataLabelColor: {
25783 displayName: powerbi.data.createDisplayNameGetter("Visual_Reference_Line_Data_Label_Color"),
25784 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Data_Label_Color_Description'),
25785 type: { fill: { solid: { color: true } } }
25786 },
25787 dataLabelDecimalPoints: {
25788 displayName: powerbi.data.createDisplayNameGetter("Visual_Reference_Line_Data_Decimal_Points"),
25789 placeHolderText: powerbi.data.createDisplayNameGetter('Visual_Precision_Auto'),
25790 type: { numeric: true }
25791 },
25792 dataLabelDisplayUnits: {
25793 displayName: powerbi.data.createDisplayNameGetter('Visual_DisplayUnits'),
25794 description: powerbi.data.createDisplayNameGetter('Visual_DisplayUnitsDescription'),
25795 type: { formatting: { labelDisplayUnits: true } },
25796 suppressFormatPainterCopy: true,
25797 },
25798 dataLabelHorizontalPosition: {
25799 displayName: powerbi.data.createDisplayNameGetter("Visual_Reference_Line_Data_Horizontal_Position"),
25800 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Data_Label_Horizontal_Position_Description'),
25801 type: { enumeration: visuals.referenceLineDataLabelHorizontalPosition.type }
25802 },
25803 dataLabelShow: {
25804 displayName: powerbi.data.createDisplayNameGetter("Visual_Reference_Line_Data_Label"),
25805 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Data_Label_Show_Description'),
25806 type: { bool: true }
25807 },
25808 dataLabelVerticalPosition: {
25809 displayName: powerbi.data.createDisplayNameGetter("Visual_Reference_Line_Data_Vertical_Position"),
25810 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Data_Label_Vertical_Position_Description'),
25811 type: { enumeration: visuals.referenceLineDataLabelVerticalPosition.type }
25812 },
25813 defaultColor: {
25814 displayName: powerbi.data.createDisplayNameGetter('Visual_DefaultColor'),
25815 type: { fill: { solid: { color: true } } }
25816 },
25817 fill: {
25818 displayName: powerbi.data.createDisplayNameGetter('Visual_Fill'),
25819 type: { fill: { solid: { color: true } } }
25820 },
25821 fontColor: {
25822 displayName: powerbi.data.createDisplayNameGetter('Visual_FontColor'),
25823 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColor_Desc'),
25824 type: { fill: { solid: { color: true } } }
25825 },
25826 fontSize: {
25827 displayName: powerbi.data.createDisplayNameGetter('Visual_TextSize'),
25828 type: { formatting: { fontSize: true } }
25829 },
25830 formatString: {
25831 type: { formatting: { formatString: true } },
25832 },
25833 image: {
25834 type: { image: {} },
25835 },
25836 labelColor: {
25837 displayName: powerbi.data.createDisplayNameGetter('Visual_LegendTitleColor'),
25838 type: { fill: { solid: { color: true } } }
25839 },
25840 labelDisplayUnits: {
25841 displayName: powerbi.data.createDisplayNameGetter('Visual_DisplayUnits'),
25842 description: powerbi.data.createDisplayNameGetter('Visual_DisplayUnitsDescription'),
25843 type: { formatting: { labelDisplayUnits: true } }
25844 },
25845 labelPrecision: {
25846 displayName: powerbi.data.createDisplayNameGetter('Visual_Precision'),
25847 description: powerbi.data.createDisplayNameGetter('Visual_PrecisionDescription'),
25848 placeHolderText: powerbi.data.createDisplayNameGetter('Visual_Precision_Auto'),
25849 type: { numeric: true }
25850 },
25851 legendPosition: {
25852 displayName: powerbi.data.createDisplayNameGetter('Visual_LegendPosition'),
25853 description: powerbi.data.createDisplayNameGetter('Visual_LegendPositionDescription'),
25854 type: { enumeration: visuals.legendPosition.type },
25855 },
25856 legendTitle: {
25857 displayName: powerbi.data.createDisplayNameGetter('Visual_LegendName'),
25858 description: powerbi.data.createDisplayNameGetter('Visual_LegendNameDescription'),
25859 type: { text: true },
25860 },
25861 lineColor: {
25862 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Color'),
25863 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Color_Description'),
25864 type: { fill: { solid: { color: true } } }
25865 },
25866 outline: {
25867 displayName: powerbi.data.createDisplayNameGetter('Visual_Outline'),
25868 type: { enumeration: visuals.outline.type }
25869 },
25870 outlineColor: {
25871 displayName: powerbi.data.createDisplayNameGetter('Visual_OutlineColor'),
25872 description: powerbi.data.createDisplayNameGetter('Visual_OutlineColor_Desc'),
25873 type: { fill: { solid: { color: true } } }
25874 },
25875 outlineWeight: {
25876 displayName: powerbi.data.createDisplayNameGetter('Visual_OutlineWeight'),
25877 description: powerbi.data.createDisplayNameGetter('Visual_OutlineWeight_Desc'),
25878 type: { numeric: true }
25879 },
25880 show: {
25881 displayName: powerbi.data.createDisplayNameGetter('Visual_Show'),
25882 type: { bool: true }
25883 },
25884 showAllDataPoints: {
25885 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint_Show_All'),
25886 type: { bool: true }
25887 },
25888 showLegendTitle: {
25889 displayName: powerbi.data.createDisplayNameGetter('Visual_LegendShowTitle'),
25890 description: powerbi.data.createDisplayNameGetter('Visual_LegendShowTitleDescription'),
25891 type: { bool: true }
25892 },
25893 referenceLinePosition: {
25894 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Arrange'),
25895 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Arrange_Description'),
25896 type: { enumeration: visuals.referenceLinePosition.type }
25897 },
25898 referenceLineStyle: {
25899 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Style'),
25900 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Style_Description'),
25901 type: { enumeration: visuals.lineStyle.type }
25902 },
25903 transparency: {
25904 displayName: powerbi.data.createDisplayNameGetter('Visual_Background_Transparency'),
25905 description: powerbi.data.createDisplayNameGetter('Visual_Background_TransparencyDescription'),
25906 type: { numeric: true }
25907 },
25908 yAxisPosition: {
25909 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis_Position'),
25910 description: powerbi.data.createDisplayNameGetter('Visual_YAxis_PositionDescription'),
25911 type: { enumeration: visuals.yAxisPosition.type },
25912 },
25913 };
25914 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
25915})(powerbi || (powerbi = {}));
25916/*
25917 * Power BI Visualizations
25918 *
25919 * Copyright (c) Microsoft Corporation
25920 * All rights reserved.
25921 * MIT License
25922 *
25923 * Permission is hereby granted, free of charge, to any person obtaining a copy
25924 * of this software and associated documentation files (the ""Software""), to deal
25925 * in the Software without restriction, including without limitation the rights
25926 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25927 * copies of the Software, and to permit persons to whom the Software is
25928 * furnished to do so, subject to the following conditions:
25929 *
25930 * The above copyright notice and this permission notice shall be included in
25931 * all copies or substantial portions of the Software.
25932 *
25933 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25934 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25935 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25936 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25937 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25938 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25939 * THE SOFTWARE.
25940 */
25941var powerbi;
25942(function (powerbi) {
25943 var visuals;
25944 (function (visuals) {
25945 visuals.animatedTextObjectDescs = {
25946 general: {
25947 properties: {
25948 formatString: visuals.StandardObjectProperties.formatString,
25949 },
25950 }
25951 };
25952 visuals.animatedNumberCapabilities = {
25953 objects: visuals.animatedTextObjectDescs,
25954 dataViewMappings: [{
25955 single: { role: "Values" }
25956 }],
25957 supportsSelection: false,
25958 };
25959 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
25960})(powerbi || (powerbi = {}));
25961/*
25962 * Power BI Visualizations
25963 *
25964 * Copyright (c) Microsoft Corporation
25965 * All rights reserved.
25966 * MIT License
25967 *
25968 * Permission is hereby granted, free of charge, to any person obtaining a copy
25969 * of this software and associated documentation files (the ""Software""), to deal
25970 * in the Software without restriction, including without limitation the rights
25971 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25972 * copies of the Software, and to permit persons to whom the Software is
25973 * furnished to do so, subject to the following conditions:
25974 *
25975 * The above copyright notice and this permission notice shall be included in
25976 * all copies or substantial portions of the Software.
25977 *
25978 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25979 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25980 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25981 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25982 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25983 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25984 * THE SOFTWARE.
25985 */
25986var powerbi;
25987(function (powerbi) {
25988 var visuals;
25989 (function (visuals) {
25990 visuals.basicShapeCapabilities = {
25991 objects: {
25992 line: {
25993 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_Line'),
25994 properties: {
25995 lineColor: {
25996 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_LineColor'),
25997 type: { fill: { solid: { color: true } } }
25998 },
25999 transparency: visuals.StandardObjectProperties.transparency,
26000 weight: {
26001 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_Weight'),
26002 type: { numeric: true }
26003 },
26004 roundEdge: {
26005 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_RoundEdges'),
26006 type: { numeric: true }
26007 }
26008 }
26009 },
26010 fill: {
26011 displayName: powerbi.data.createDisplayNameGetter('Visual_Fill'),
26012 properties: {
26013 show: visuals.StandardObjectProperties.show,
26014 fillColor: {
26015 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_FillColor'),
26016 type: { fill: { solid: { color: true } } }
26017 },
26018 transparency: visuals.StandardObjectProperties.transparency,
26019 }
26020 },
26021 rotation: {
26022 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_Rotate'),
26023 properties: {
26024 angle: {
26025 displayName: powerbi.data.createDisplayNameGetter('Visual_BasicShape_Rotate'),
26026 type: { numeric: true }
26027 }
26028 }
26029 },
26030 general: {
26031 properties: {
26032 shapeType: {
26033 type: { text: true },
26034 suppressFormatPainterCopy: true,
26035 }
26036 }
26037 }
26038 },
26039 suppressDefaultTitle: true,
26040 suppressDefaultPadding: true,
26041 canRotate: false,
26042 supportsSelection: false,
26043 };
26044 visuals.basicShapeProps = {
26045 general: {
26046 shapeType: { objectName: 'general', propertyName: 'shapeType' },
26047 },
26048 line: {
26049 transparency: { objectName: 'line', propertyName: 'transparency' },
26050 weight: { objectName: 'line', propertyName: 'weight' },
26051 roundEdge: { objectName: 'line', propertyName: 'roundEdge' },
26052 lineColor: { objectName: 'line', propertyName: 'lineColor' }
26053 },
26054 fill: {
26055 transparency: { objectName: 'fill', propertyName: 'transparency' },
26056 fillColor: { objectName: 'fill', propertyName: 'fillColor' },
26057 show: { objectName: 'fill', propertyName: 'show' }
26058 },
26059 rotation: {
26060 angle: { objectName: 'rotation', propertyName: 'angle' }
26061 }
26062 };
26063 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
26064})(powerbi || (powerbi = {}));
26065/*
26066 * Power BI Visualizations
26067 *
26068 * Copyright (c) Microsoft Corporation
26069 * All rights reserved.
26070 * MIT License
26071 *
26072 * Permission is hereby granted, free of charge, to any person obtaining a copy
26073 * of this software and associated documentation files (the ""Software""), to deal
26074 * in the Software without restriction, including without limitation the rights
26075 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26076 * copies of the Software, and to permit persons to whom the Software is
26077 * furnished to do so, subject to the following conditions:
26078 *
26079 * The above copyright notice and this permission notice shall be included in
26080 * all copies or substantial portions of the Software.
26081 *
26082 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26083 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26084 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26085 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26086 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26087 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26088 * THE SOFTWARE.
26089 */
26090var powerbi;
26091(function (powerbi) {
26092 var visuals;
26093 (function (visuals) {
26094 function getColumnChartCapabilities(transposeAxes) {
26095 if (transposeAxes === void 0) { transposeAxes = false; }
26096 return {
26097 dataRoles: [
26098 {
26099 name: 'Category',
26100 kind: powerbi.VisualDataRoleKind.Grouping,
26101 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Axis'),
26102 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_AxisDescription'),
26103 cartesianKind: 0 /* X */,
26104 }, {
26105 name: 'Series',
26106 kind: powerbi.VisualDataRoleKind.Grouping,
26107 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Legend'),
26108 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LegendDescription')
26109 }, {
26110 name: 'Y',
26111 kind: powerbi.VisualDataRoleKind.Measure,
26112 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Value'),
26113 requiredTypes: [{ numeric: true }, { integer: true }],
26114 cartesianKind: 1 /* Y */,
26115 }, {
26116 name: 'Gradient',
26117 kind: powerbi.VisualDataRoleKind.Measure,
26118 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Gradient'),
26119 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GradientDescription'),
26120 requiredTypes: [{ numeric: true }, { integer: true }],
26121 }
26122 ],
26123 objects: {
26124 general: {
26125 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
26126 properties: {
26127 formatString: visuals.StandardObjectProperties.formatString,
26128 },
26129 },
26130 legend: {
26131 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
26132 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
26133 properties: {
26134 show: visuals.StandardObjectProperties.show,
26135 position: visuals.StandardObjectProperties.legendPosition,
26136 showTitle: visuals.StandardObjectProperties.showLegendTitle,
26137 titleText: $.extend({}, visuals.StandardObjectProperties.legendTitle, {
26138 suppressFormatPainterCopy: true
26139 }),
26140 labelColor: visuals.StandardObjectProperties.labelColor,
26141 fontSize: visuals.StandardObjectProperties.fontSize,
26142 }
26143 },
26144 categoryAxis: {
26145 displayName: transposeAxes ? powerbi.data.createDisplayNameGetter('Visual_YAxis') : powerbi.data.createDisplayNameGetter('Visual_XAxis'),
26146 properties: {
26147 show: visuals.StandardObjectProperties.show,
26148 position: visuals.StandardObjectProperties.yAxisPosition,
26149 axisScale: visuals.StandardObjectProperties.axisScale,
26150 start: visuals.StandardObjectProperties.axisStart,
26151 end: visuals.StandardObjectProperties.axisEnd,
26152 axisType: visuals.StandardObjectProperties.axisType,
26153 showAxisTitle: {
26154 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
26155 description: transposeAxes ? powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription') : powerbi.data.createDisplayNameGetter('Visual_Axis_XTitleDescription'),
26156 type: { bool: true }
26157 },
26158 axisStyle: visuals.StandardObjectProperties.axisStyle,
26159 labelColor: visuals.StandardObjectProperties.labelColor,
26160 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
26161 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
26162 }
26163 },
26164 valueAxis: {
26165 displayName: transposeAxes ? powerbi.data.createDisplayNameGetter('Visual_XAxis') : powerbi.data.createDisplayNameGetter('Visual_YAxis'),
26166 properties: {
26167 show: visuals.StandardObjectProperties.show,
26168 position: visuals.StandardObjectProperties.yAxisPosition,
26169 axisScale: visuals.StandardObjectProperties.axisScale,
26170 start: visuals.StandardObjectProperties.axisStart,
26171 end: visuals.StandardObjectProperties.axisEnd,
26172 intersection: {
26173 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Intersection'),
26174 type: { numeric: true },
26175 placeHolderText: powerbi.data.createDisplayNameGetter('Visual_Precision_Auto'),
26176 },
26177 showAxisTitle: {
26178 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
26179 description: transposeAxes ? powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription') : powerbi.data.createDisplayNameGetter('Visual_Axis_XTitleDescription'),
26180 type: { bool: true }
26181 },
26182 axisStyle: visuals.StandardObjectProperties.axisStyle,
26183 labelColor: visuals.StandardObjectProperties.labelColor,
26184 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
26185 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
26186 }
26187 },
26188 y1AxisReferenceLine: {
26189 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line'),
26190 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Description'),
26191 properties: {
26192 show: visuals.StandardObjectProperties.show,
26193 value: {
26194 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value'),
26195 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value_Description'),
26196 type: { numeric: true }
26197 },
26198 lineColor: visuals.StandardObjectProperties.lineColor,
26199 transparency: {
26200 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency'),
26201 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency_Description'),
26202 type: { numeric: true }
26203 },
26204 style: visuals.StandardObjectProperties.referenceLineStyle,
26205 position: visuals.StandardObjectProperties.referenceLinePosition,
26206 dataLabelShow: visuals.StandardObjectProperties.dataLabelShow,
26207 dataLabelColor: visuals.StandardObjectProperties.dataLabelColor,
26208 dataLabelDecimalPoints: visuals.StandardObjectProperties.dataLabelDecimalPoints,
26209 dataLabelHorizontalPosition: visuals.StandardObjectProperties.dataLabelHorizontalPosition,
26210 dataLabelVerticalPosition: visuals.StandardObjectProperties.dataLabelVerticalPosition,
26211 dataLabelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
26212 },
26213 },
26214 dataPoint: {
26215 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
26216 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
26217 properties: {
26218 defaultColor: visuals.StandardObjectProperties.defaultColor,
26219 showAllDataPoints: visuals.StandardObjectProperties.showAllDataPoints,
26220 fill: visuals.StandardObjectProperties.fill,
26221 fillRule: {
26222 displayName: powerbi.data.createDisplayNameGetter('Visual_Gradient'),
26223 type: { fillRule: {} },
26224 rule: {
26225 inputRole: 'Gradient',
26226 output: {
26227 property: 'fill',
26228 selector: ['Category'],
26229 },
26230 },
26231 }
26232 }
26233 },
26234 trend: {
26235 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line'),
26236 properties: {
26237 show: {
26238 type: { bool: true }
26239 },
26240 lineColor: {
26241 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color'),
26242 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color_Description'),
26243 type: { fill: { solid: { color: true } } }
26244 },
26245 transparency: {
26246 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency'),
26247 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency_Description'),
26248 type: { numeric: true }
26249 },
26250 style: {
26251 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style'),
26252 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style_Description'),
26253 type: { enumeration: visuals.lineStyle.type }
26254 },
26255 combineSeries: {
26256 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series'),
26257 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series_Description'),
26258 type: { bool: true }
26259 },
26260 useHighlightValues: {
26261 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_UseHighlightValues'),
26262 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_UseHighlightValues_Description'),
26263 type: { bool: true }
26264 },
26265 }
26266 },
26267 labels: {
26268 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
26269 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
26270 properties: {
26271 show: visuals.StandardObjectProperties.show,
26272 showSeries: {
26273 displayName: powerbi.data.createDisplayNameGetter('Visual_Show'),
26274 type: { bool: true }
26275 },
26276 color: visuals.StandardObjectProperties.dataColor,
26277 labelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
26278 labelPrecision: $.extend({}, visuals.StandardObjectProperties.labelPrecision, {
26279 suppressFormatPainterCopy: true
26280 }),
26281 showAll: {
26282 displayName: powerbi.data.createDisplayNameGetter('Visual_LabelSeriesShowAll'),
26283 type: { bool: true }
26284 },
26285 fontSize: visuals.StandardObjectProperties.fontSize,
26286 },
26287 },
26288 plotArea: {
26289 displayName: powerbi.data.createDisplayNameGetter('Visual_Plot'),
26290 //description: data.createDisplayNameGetter('Visual_PlotDescription'),
26291 properties: {
26292 transparency: visuals.StandardObjectProperties.transparency,
26293 image: visuals.StandardObjectProperties.image,
26294 },
26295 },
26296 },
26297 dataViewMappings: [{
26298 conditions: [
26299 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'Gradient': { max: 0 } },
26300 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 }, 'Gradient': { max: 0 } },
26301 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'Y': { min: 0, max: 1 }, 'Gradient': { max: 1 } },
26302 ],
26303 categorical: {
26304 categories: {
26305 for: { in: 'Category' },
26306 dataReductionAlgorithm: { top: {} }
26307 },
26308 values: {
26309 group: {
26310 by: 'Series',
26311 select: [{ for: { in: 'Y' } }, { bind: { to: 'Gradient' } }],
26312 dataReductionAlgorithm: { top: {} }
26313 }
26314 },
26315 rowCount: { preferred: { min: 2 }, supported: { min: 0 } }
26316 },
26317 }, {
26318 conditions: [
26319 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'Gradient': { max: 0 } },
26320 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 }, 'Gradient': { max: 0 } },
26321 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'Y': { min: 0, max: 1 }, 'Gradient': { max: 1 } },
26322 ],
26323 requiredProperties: [{ objectName: 'trend', propertyName: 'show' }],
26324 usage: {
26325 regression: {
26326 combineSeries: { objectName: 'trend', propertyName: 'combineSeries' }
26327 },
26328 },
26329 categorical: {
26330 categories: {
26331 for: { in: 'regression.X' },
26332 },
26333 values: {
26334 group: {
26335 by: 'regression.Series',
26336 select: [{ for: { in: 'regression.Y' } }],
26337 },
26338 }
26339 }
26340 }],
26341 supportsHighlight: true,
26342 sorting: {
26343 default: {},
26344 },
26345 drilldown: {
26346 roles: ['Category']
26347 },
26348 };
26349 }
26350 visuals.getColumnChartCapabilities = getColumnChartCapabilities;
26351 visuals.columnChartProps = {
26352 dataPoint: {
26353 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
26354 fill: { objectName: 'dataPoint', propertyName: 'fill' },
26355 showAllDataPoints: { objectName: 'dataPoint', propertyName: 'showAllDataPoints' },
26356 },
26357 general: {
26358 formatString: { objectName: 'general', propertyName: 'formatString' },
26359 },
26360 categoryAxis: {
26361 axisType: { objectName: 'categoryAxis', propertyName: 'axisType' },
26362 },
26363 legend: {
26364 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
26365 },
26366 plotArea: {
26367 image: { objectName: 'plotArea', propertyName: 'image' },
26368 transparency: { objectName: 'plotArea', propertyName: 'transparency' },
26369 },
26370 };
26371 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
26372})(powerbi || (powerbi = {}));
26373/*
26374 * Power BI Visualizations
26375 *
26376 * Copyright (c) Microsoft Corporation
26377 * All rights reserved.
26378 * MIT License
26379 *
26380 * Permission is hereby granted, free of charge, to any person obtaining a copy
26381 * of this software and associated documentation files (the ""Software""), to deal
26382 * in the Software without restriction, including without limitation the rights
26383 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26384 * copies of the Software, and to permit persons to whom the Software is
26385 * furnished to do so, subject to the following conditions:
26386 *
26387 * The above copyright notice and this permission notice shall be included in
26388 * all copies or substantial portions of the Software.
26389 *
26390 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26391 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26392 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26393 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26394 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26395 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26396 * THE SOFTWARE.
26397 */
26398var powerbi;
26399(function (powerbi) {
26400 var visuals;
26401 (function (visuals) {
26402 visuals.comboChartCapabilities = {
26403 dataRoles: [
26404 {
26405 name: 'Category',
26406 kind: powerbi.VisualDataRoleKind.Grouping,
26407 displayName: powerbi.data.createDisplayNameGetter('Role_ComboChart_Category'),
26408 description: powerbi.data.createDisplayNameGetter('Role_ComboChart_CategoryDescription'),
26409 cartesianKind: 0 /* X */,
26410 }, {
26411 name: 'Series',
26412 kind: powerbi.VisualDataRoleKind.Grouping,
26413 displayName: powerbi.data.createDisplayNameGetter('Role_ComboChart_Series'),
26414 }, {
26415 name: 'Y',
26416 kind: powerbi.VisualDataRoleKind.Measure,
26417 displayName: powerbi.data.createDisplayNameGetter('Role_ComboChart_Y'),
26418 description: powerbi.data.createDisplayNameGetter('Role_ComboChart_YDescription'),
26419 requiredTypes: [{ numeric: true }, { integer: true }],
26420 cartesianKind: 1 /* Y */,
26421 }, {
26422 name: 'Y2',
26423 kind: powerbi.VisualDataRoleKind.Measure,
26424 displayName: powerbi.data.createDisplayNameGetter('Role_ComboChart_Y2'),
26425 description: powerbi.data.createDisplayNameGetter('Role_ComboChart_Y2Description'),
26426 requiredTypes: [{ numeric: true }, { integer: true }],
26427 cartesianKind: 1 /* Y */,
26428 },
26429 ],
26430 objects: {
26431 general: {
26432 properties: {
26433 formatString: visuals.StandardObjectProperties.formatString,
26434 visualType1: {
26435 type: { text: true }
26436 },
26437 visualType2: {
26438 type: { text: true }
26439 },
26440 },
26441 },
26442 legend: {
26443 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
26444 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
26445 properties: {
26446 show: visuals.StandardObjectProperties.show,
26447 position: visuals.StandardObjectProperties.legendPosition,
26448 showTitle: visuals.StandardObjectProperties.showLegendTitle,
26449 titleText: $.extend({}, visuals.StandardObjectProperties.legendTitle, {
26450 suppressFormatPainterCopy: true
26451 }),
26452 labelColor: visuals.StandardObjectProperties.labelColor,
26453 fontSize: visuals.StandardObjectProperties.fontSize,
26454 }
26455 },
26456 categoryAxis: {
26457 displayName: powerbi.data.createDisplayNameGetter('Visual_XAxis'),
26458 properties: {
26459 show: visuals.StandardObjectProperties.show,
26460 axisScale: visuals.StandardObjectProperties.axisScale,
26461 start: visuals.StandardObjectProperties.axisStart,
26462 end: visuals.StandardObjectProperties.axisEnd,
26463 axisType: visuals.StandardObjectProperties.axisType,
26464 showAxisTitle: {
26465 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
26466 description: powerbi.data.createDisplayNameGetter('Visual_Axis_XTitleDescription'),
26467 type: { bool: true }
26468 },
26469 axisStyle: visuals.StandardObjectProperties.axisStyle,
26470 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
26471 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
26472 }
26473 },
26474 valueAxis: {
26475 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis'),
26476 properties: {
26477 show: visuals.StandardObjectProperties.show,
26478 axisLabel: {
26479 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis_ColumnTitle'),
26480 type: { none: true },
26481 },
26482 position: visuals.StandardObjectProperties.yAxisPosition,
26483 axisScale: visuals.StandardObjectProperties.axisScale,
26484 start: visuals.StandardObjectProperties.axisStart,
26485 end: visuals.StandardObjectProperties.axisEnd,
26486 showAxisTitle: {
26487 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
26488 description: powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription'),
26489 type: { bool: true }
26490 },
26491 axisStyle: visuals.StandardObjectProperties.axisStyle,
26492 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
26493 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
26494 secShow: {
26495 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis_ShowSecondary'),
26496 type: { bool: true },
26497 },
26498 secAxisLabel: {
26499 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis_LineTitle'),
26500 type: { none: true },
26501 },
26502 secPosition: {
26503 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis_Position'),
26504 type: { enumeration: visuals.yAxisPosition.type },
26505 },
26506 secAxisScale: visuals.StandardObjectProperties.axisScale,
26507 secStart: {
26508 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Start'),
26509 description: powerbi.data.createDisplayNameGetter('Visual_Axis_StartDescription'),
26510 type: { numeric: true },
26511 },
26512 secEnd: {
26513 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_End'),
26514 description: powerbi.data.createDisplayNameGetter('Visual_Axis_EndDescription'),
26515 type: { numeric: true },
26516 },
26517 secShowAxisTitle: {
26518 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
26519 description: powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription'),
26520 type: { bool: true },
26521 },
26522 secAxisStyle: visuals.StandardObjectProperties.axisStyle,
26523 secLabelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
26524 secLabelPrecision: visuals.StandardObjectProperties.labelPrecision,
26525 }
26526 },
26527 dataPoint: {
26528 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
26529 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
26530 properties: {
26531 defaultColor: $.extend({}, visuals.StandardObjectProperties.defaultColor, {
26532 displayName: powerbi.data.createDisplayNameGetter('Visual_DefaultColumnColor'),
26533 }),
26534 showAllDataPoints: visuals.StandardObjectProperties.showAllDataPoints,
26535 fill: visuals.StandardObjectProperties.fill,
26536 fillRule: {
26537 displayName: powerbi.data.createDisplayNameGetter('Visual_Gradient'),
26538 type: { fillRule: {} },
26539 rule: {
26540 inputRole: 'Gradient',
26541 output: {
26542 property: 'fill',
26543 selector: ['Category'],
26544 },
26545 },
26546 }
26547 }
26548 },
26549 labels: {
26550 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
26551 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
26552 properties: {
26553 show: visuals.StandardObjectProperties.show,
26554 color: visuals.StandardObjectProperties.dataColor,
26555 labelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
26556 labelPrecision: $.extend({}, visuals.StandardObjectProperties.labelPrecision, {
26557 suppressFormatPainterCopy: true,
26558 }),
26559 fontSize: visuals.StandardObjectProperties.fontSize,
26560 },
26561 },
26562 plotArea: {
26563 displayName: powerbi.data.createDisplayNameGetter('Visual_Plot'),
26564 properties: {
26565 transparency: visuals.StandardObjectProperties.transparency,
26566 image: visuals.StandardObjectProperties.image,
26567 },
26568 },
26569 trend: {
26570 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line'),
26571 properties: {
26572 show: {
26573 type: { bool: true }
26574 },
26575 lineColor: {
26576 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color'),
26577 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color_Description'),
26578 type: { fill: { solid: { color: true } } }
26579 },
26580 transparency: {
26581 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency'),
26582 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency_Description'),
26583 type: { numeric: true }
26584 },
26585 style: {
26586 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style'),
26587 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style_Description'),
26588 type: { enumeration: visuals.lineStyle.type }
26589 },
26590 combineSeries: {
26591 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series'),
26592 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series_Description'),
26593 type: { bool: true }
26594 },
26595 useHighlightValues: {
26596 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_UseHighlightValues'),
26597 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_UseHighlightValues_Description'),
26598 type: { bool: true }
26599 },
26600 }
26601 },
26602 },
26603 dataViewMappings: [
26604 {
26605 conditions: [
26606 { 'Category': { max: 1 }, 'Series': { max: 0 } },
26607 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 } },
26608 ],
26609 categorical: {
26610 categories: {
26611 for: { in: 'Category' },
26612 dataReductionAlgorithm: { top: {} }
26613 },
26614 values: {
26615 group: {
26616 by: 'Series',
26617 select: [
26618 { for: { in: 'Y' } }
26619 ],
26620 dataReductionAlgorithm: { top: {} }
26621 }
26622 },
26623 rowCount: { preferred: { min: 2 }, supported: { min: 0 } }
26624 }
26625 }, {
26626 conditions: [
26627 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'Y2': { min: 1 } },
26628 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 }, 'Y2': { min: 1 } },
26629 ],
26630 categorical: {
26631 categories: {
26632 for: { in: 'Category' },
26633 dataReductionAlgorithm: { top: {} }
26634 },
26635 values: {
26636 select: [
26637 { for: { in: 'Y2' } }
26638 ],
26639 },
26640 rowCount: { preferred: { min: 2 }, supported: { min: 0 } }
26641 },
26642 }, {
26643 conditions: [
26644 { 'Category': { max: 1 }, 'Series': { max: 0 } },
26645 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 } },
26646 ],
26647 requiredProperties: [{ objectName: 'trend', propertyName: 'show' }],
26648 usage: {
26649 regression: {
26650 combineSeries: { objectName: 'trend', propertyName: 'combineSeries' }
26651 },
26652 },
26653 categorical: {
26654 categories: {
26655 for: { in: 'regression.X' }
26656 },
26657 values: {
26658 group: {
26659 by: 'regression.Series',
26660 select: [{ for: { in: 'regression.Y' } }],
26661 },
26662 },
26663 }
26664 },
26665 ],
26666 supportsHighlight: true,
26667 sorting: {
26668 default: {},
26669 },
26670 drilldown: {
26671 roles: ['Category']
26672 },
26673 };
26674 visuals.comboChartProps = {
26675 general: {
26676 formatString: { objectName: 'general', propertyName: 'formatString' },
26677 },
26678 valueAxis: {
26679 secShow: { objectName: 'valueAxis', propertyName: 'secShow' },
26680 },
26681 legend: {
26682 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
26683 },
26684 dataPoint: {
26685 showAllDataPoints: { objectName: 'dataPoint', propertyName: 'showAllDataPoints' },
26686 },
26687 };
26688 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
26689})(powerbi || (powerbi = {}));
26690/*
26691 * Power BI Visualizations
26692 *
26693 * Copyright (c) Microsoft Corporation
26694 * All rights reserved.
26695 * MIT License
26696 *
26697 * Permission is hereby granted, free of charge, to any person obtaining a copy
26698 * of this software and associated documentation files (the ""Software""), to deal
26699 * in the Software without restriction, including without limitation the rights
26700 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26701 * copies of the Software, and to permit persons to whom the Software is
26702 * furnished to do so, subject to the following conditions:
26703 *
26704 * The above copyright notice and this permission notice shall be included in
26705 * all copies or substantial portions of the Software.
26706 *
26707 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26708 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26709 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26710 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26711 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26712 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26713 * THE SOFTWARE.
26714 */
26715var powerbi;
26716(function (powerbi) {
26717 var visuals;
26718 (function (visuals) {
26719 visuals.donutChartCapabilities = {
26720 dataRoles: [
26721 {
26722 name: 'Category',
26723 kind: powerbi.VisualDataRoleKind.Grouping,
26724 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Legend'),
26725 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LegendDescription')
26726 }, {
26727 name: 'Series',
26728 kind: powerbi.VisualDataRoleKind.Grouping,
26729 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Details'),
26730 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_DetailsDonutChartDescription'),
26731 }, {
26732 name: 'Y',
26733 kind: powerbi.VisualDataRoleKind.Measure,
26734 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
26735 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ValuesDescription'),
26736 requiredTypes: [{ numeric: true }, { integer: true }],
26737 }
26738 ],
26739 objects: {
26740 general: {
26741 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
26742 properties: {
26743 formatString: visuals.StandardObjectProperties.formatString,
26744 },
26745 },
26746 legend: {
26747 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
26748 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
26749 properties: {
26750 show: visuals.StandardObjectProperties.show,
26751 position: visuals.StandardObjectProperties.legendPosition,
26752 showTitle: visuals.StandardObjectProperties.showLegendTitle,
26753 titleText: $.extend({}, visuals.StandardObjectProperties.legendTitle, {
26754 suppressFormatPainterCopy: true
26755 }),
26756 labelColor: visuals.StandardObjectProperties.labelColor,
26757 fontSize: visuals.StandardObjectProperties.fontSize,
26758 }
26759 },
26760 dataPoint: {
26761 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
26762 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
26763 properties: {
26764 defaultColor: visuals.StandardObjectProperties.defaultColor,
26765 fill: visuals.StandardObjectProperties.fill,
26766 }
26767 },
26768 labels: {
26769 displayName: powerbi.data.createDisplayNameGetter('Visual_DetailLabels'),
26770 properties: {
26771 show: visuals.StandardObjectProperties.show,
26772 color: visuals.StandardObjectProperties.dataColor,
26773 labelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
26774 labelPrecision: $.extend({}, visuals.StandardObjectProperties.labelPrecision, {
26775 suppressFormatPainterCopy: true,
26776 }),
26777 fontSize: $.extend({}, visuals.StandardObjectProperties.fontSize, {
26778 suppressFormatPainterCopy: true,
26779 }),
26780 labelStyle: {
26781 displayName: powerbi.data.createDisplayNameGetter('Visual_LabelStyle'),
26782 type: { enumeration: visuals.labelStyle.type }
26783 },
26784 },
26785 },
26786 },
26787 dataViewMappings: [{
26788 conditions: [
26789 { 'Category': { max: 1 }, 'Series': { max: 0 } },
26790 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 } }
26791 ],
26792 categorical: {
26793 categories: {
26794 for: { in: 'Category' },
26795 dataReductionAlgorithm: { top: {} }
26796 },
26797 values: {
26798 group: {
26799 by: 'Series',
26800 select: [{ bind: { to: 'Y' } }],
26801 dataReductionAlgorithm: { top: {} }
26802 }
26803 },
26804 rowCount: { preferred: { min: 2 }, supported: { min: 1 } }
26805 },
26806 }],
26807 sorting: {
26808 default: {},
26809 },
26810 supportsHighlight: true,
26811 drilldown: {
26812 roles: ['Category']
26813 },
26814 };
26815 visuals.donutChartProps = {
26816 general: {
26817 formatString: { objectName: 'general', propertyName: 'formatString' },
26818 },
26819 dataPoint: {
26820 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
26821 fill: { objectName: 'dataPoint', propertyName: 'fill' },
26822 },
26823 legend: {
26824 show: { objectName: 'legend', propertyName: 'show' },
26825 position: { objectName: 'legend', propertyName: 'position' },
26826 showTitle: { objectName: 'legend', propertyName: 'showTitle' },
26827 titleText: { objectName: 'legend', propertyName: 'titleText' },
26828 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
26829 },
26830 };
26831 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
26832})(powerbi || (powerbi = {}));
26833/*
26834 * Power BI Visualizations
26835 *
26836 * Copyright (c) Microsoft Corporation
26837 * All rights reserved.
26838 * MIT License
26839 *
26840 * Permission is hereby granted, free of charge, to any person obtaining a copy
26841 * of this software and associated documentation files (the ""Software""), to deal
26842 * in the Software without restriction, including without limitation the rights
26843 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26844 * copies of the Software, and to permit persons to whom the Software is
26845 * furnished to do so, subject to the following conditions:
26846 *
26847 * The above copyright notice and this permission notice shall be included in
26848 * all copies or substantial portions of the Software.
26849 *
26850 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26851 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26852 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26853 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26854 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26855 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26856 * THE SOFTWARE.
26857 */
26858var powerbi;
26859(function (powerbi) {
26860 var visuals;
26861 (function (visuals) {
26862 // I support a categorical (ordinal) X with measure Y for a single series
26863 visuals.dataDotChartCapabilities = {
26864 dataRoles: [
26865 {
26866 name: 'Category',
26867 kind: powerbi.VisualDataRoleKind.Grouping,
26868 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Axis'),
26869 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_AxisDescription')
26870 }, {
26871 name: 'Y',
26872 kind: powerbi.VisualDataRoleKind.Measure,
26873 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Value'),
26874 requiredTypes: [{ numeric: true }, { integer: true }]
26875 },
26876 ],
26877 objects: {
26878 general: {
26879 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
26880 properties: {
26881 formatString: visuals.StandardObjectProperties.formatString,
26882 },
26883 },
26884 },
26885 dataViewMappings: [{
26886 conditions: [
26887 { 'Category': { max: 1 }, 'Y': { max: 1 } }
26888 ],
26889 categorical: {
26890 categories: {
26891 for: { in: 'Category' },
26892 dataReductionAlgorithm: { top: {} }
26893 },
26894 values: {
26895 select: [{
26896 for: { in: 'Y' },
26897 dataReductionAlgorithm: { top: {} }
26898 }]
26899 },
26900 },
26901 }]
26902 };
26903 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
26904})(powerbi || (powerbi = {}));
26905/*
26906 * Power BI Visualizations
26907 *
26908 * Copyright (c) Microsoft Corporation
26909 * All rights reserved.
26910 * MIT License
26911 *
26912 * Permission is hereby granted, free of charge, to any person obtaining a copy
26913 * of this software and associated documentation files (the ""Software""), to deal
26914 * in the Software without restriction, including without limitation the rights
26915 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26916 * copies of the Software, and to permit persons to whom the Software is
26917 * furnished to do so, subject to the following conditions:
26918 *
26919 * The above copyright notice and this permission notice shall be included in
26920 * all copies or substantial portions of the Software.
26921 *
26922 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26923 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26924 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26925 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26926 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26927 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26928 * THE SOFTWARE.
26929 */
26930var powerbi;
26931(function (powerbi) {
26932 var visuals;
26933 (function (visuals) {
26934 visuals.filledMapCapabilities = {
26935 dataRoles: [
26936 {
26937 name: 'Category',
26938 kind: powerbi.VisualDataRoleKind.Grouping,
26939 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Location'),
26940 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LocationFilledMapDescription'),
26941 preferredTypes: [
26942 { geography: { address: true } },
26943 { geography: { city: true } },
26944 { geography: { continent: true } },
26945 { geography: { country: true } },
26946 { geography: { county: true } },
26947 { geography: { place: true } },
26948 { geography: { postalCode: true } },
26949 { geography: { region: true } },
26950 { geography: { stateOrProvince: true } },
26951 ],
26952 }, {
26953 name: 'Series',
26954 kind: powerbi.VisualDataRoleKind.Grouping,
26955 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Legend'),
26956 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LegendDescription')
26957 }, {
26958 name: 'X',
26959 kind: powerbi.VisualDataRoleKind.Measure,
26960 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Longitude'),
26961 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LongitudeFilledMapDescription'),
26962 preferredTypes: [
26963 { geography: { longitude: true } }
26964 ],
26965 }, {
26966 name: 'Y',
26967 kind: powerbi.VisualDataRoleKind.Measure,
26968 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Latitude'),
26969 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LatitudeFilledMapDescription'),
26970 preferredTypes: [
26971 { geography: { latitude: true } }
26972 ],
26973 }, {
26974 name: 'Size',
26975 kind: powerbi.VisualDataRoleKind.Measure,
26976 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Gradient'),
26977 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GradientDescription'),
26978 requiredTypes: [{ numeric: true }, { integer: true }],
26979 }
26980 ],
26981 objects: {
26982 general: {
26983 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
26984 properties: {
26985 formatString: visuals.StandardObjectProperties.formatString,
26986 },
26987 },
26988 legend: {
26989 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
26990 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
26991 properties: {
26992 show: visuals.StandardObjectProperties.show,
26993 position: visuals.StandardObjectProperties.legendPosition,
26994 showTitle: visuals.StandardObjectProperties.showLegendTitle,
26995 titleText: visuals.StandardObjectProperties.legendTitle,
26996 fontSize: visuals.StandardObjectProperties.fontSize,
26997 }
26998 },
26999 dataPoint: {
27000 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
27001 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
27002 properties: {
27003 defaultColor: visuals.StandardObjectProperties.defaultColor,
27004 showAllDataPoints: visuals.StandardObjectProperties.showAllDataPoints,
27005 fill: visuals.StandardObjectProperties.fill,
27006 fillRule: {
27007 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
27008 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ValuesDescription'),
27009 type: { fillRule: {} },
27010 rule: {
27011 inputRole: 'Size',
27012 output: {
27013 property: 'fill',
27014 selector: ['Category'],
27015 },
27016 },
27017 }
27018 }
27019 },
27020 labels: {
27021 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
27022 properties: {
27023 show: visuals.StandardObjectProperties.show,
27024 color: visuals.StandardObjectProperties.dataColor,
27025 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
27026 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
27027 },
27028 },
27029 categoryLabels: {
27030 displayName: powerbi.data.createDisplayNameGetter('Visual_CategoryLabels'),
27031 properties: {
27032 show: visuals.StandardObjectProperties.show,
27033 },
27034 }
27035 },
27036 dataViewMappings: [{
27037 conditions: [
27038 { 'Category': { max: 1 }, 'Series': { max: 1 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 1 } },
27039 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 1 } }
27040 ],
27041 categorical: {
27042 categories: {
27043 for: { in: 'Category' },
27044 dataReductionAlgorithm: { top: {} }
27045 },
27046 values: {
27047 group: {
27048 by: 'Series',
27049 select: [
27050 { bind: { to: 'X' } },
27051 { bind: { to: 'Y' } },
27052 { bind: { to: 'Size' } },
27053 ],
27054 dataReductionAlgorithm: { top: {} }
27055 }
27056 },
27057 rowCount: { preferred: { min: 2 } },
27058 dataVolume: 4,
27059 },
27060 }],
27061 sorting: {
27062 custom: {},
27063 },
27064 drilldown: {
27065 roles: ['Category']
27066 },
27067 };
27068 visuals.filledMapProps = {
27069 general: {
27070 formatString: { objectName: 'general', propertyName: 'formatString' },
27071 },
27072 dataPoint: {
27073 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
27074 fill: { objectName: 'dataPoint', propertyName: 'fill' },
27075 showAllDataPoints: { objectName: 'dataPoint', propertyName: 'showAllDataPoints' },
27076 },
27077 legend: {
27078 show: { objectName: 'legend', propertyName: 'show' },
27079 position: { objectName: 'legend', propertyName: 'position' },
27080 showTitle: { objectName: 'legend', propertyName: 'showTitle' },
27081 titleText: { objectName: 'legend', propertyName: 'titleText' },
27082 },
27083 labels: {
27084 show: { objectName: 'labels', propertyName: 'show' },
27085 color: { objectName: 'labels', propertyName: 'color' },
27086 labelDisplayUnits: { objectName: 'labels', propertyName: 'labelDisplayUnits' },
27087 labelPrecision: { objectName: 'labels', propertyName: 'labelPrecision' },
27088 },
27089 categoryLabels: {
27090 show: { objectName: 'categoryLabels', propertyName: 'show' },
27091 }
27092 };
27093 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27094})(powerbi || (powerbi = {}));
27095/*
27096 * Power BI Visualizations
27097 *
27098 * Copyright (c) Microsoft Corporation
27099 * All rights reserved.
27100 * MIT License
27101 *
27102 * Permission is hereby granted, free of charge, to any person obtaining a copy
27103 * of this software and associated documentation files (the ""Software""), to deal
27104 * in the Software without restriction, including without limitation the rights
27105 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27106 * copies of the Software, and to permit persons to whom the Software is
27107 * furnished to do so, subject to the following conditions:
27108 *
27109 * The above copyright notice and this permission notice shall be included in
27110 * all copies or substantial portions of the Software.
27111 *
27112 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27113 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27114 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27115 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27116 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27117 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27118 * THE SOFTWARE.
27119 */
27120var powerbi;
27121(function (powerbi) {
27122 var visuals;
27123 (function (visuals) {
27124 visuals.funnelChartCapabilities = {
27125 dataRoles: [
27126 {
27127 name: 'Category',
27128 kind: powerbi.VisualDataRoleKind.Grouping,
27129 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Group'),
27130 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GroupFunnelDescription')
27131 }, {
27132 name: 'Y',
27133 kind: powerbi.VisualDataRoleKind.Measure,
27134 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
27135 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ValuesDescription'),
27136 requiredTypes: [{ numeric: true }, { integer: true }],
27137 }, {
27138 name: 'Gradient',
27139 kind: powerbi.VisualDataRoleKind.Measure,
27140 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Gradient'),
27141 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GradientDescription'),
27142 requiredTypes: [{ numeric: true }, { integer: true }],
27143 }
27144 ],
27145 dataViewMappings: [{
27146 conditions: [
27147 // NOTE: Ordering of the roles prefers to add measures to Y before Gradient.
27148 { 'Category': { max: 0 }, 'Gradient': { max: 0 } },
27149 { 'Category': { max: 1 }, 'Y': { max: 1 }, 'Gradient': { max: 1 } },
27150 ],
27151 categorical: {
27152 categories: {
27153 for: { in: 'Category' },
27154 dataReductionAlgorithm: { top: {} }
27155 },
27156 values: {
27157 select: [{ for: { in: 'Y' } }, { bind: { to: 'Gradient' } }],
27158 dataReductionAlgorithm: { top: {} }
27159 },
27160 rowCount: { preferred: { min: 1 } }
27161 },
27162 }],
27163 objects: {
27164 general: {
27165 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
27166 properties: {
27167 formatString: visuals.StandardObjectProperties.formatString,
27168 },
27169 },
27170 dataPoint: {
27171 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
27172 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
27173 properties: {
27174 defaultColor: visuals.StandardObjectProperties.defaultColor,
27175 fill: visuals.StandardObjectProperties.fill,
27176 fillRule: {
27177 displayName: powerbi.data.createDisplayNameGetter('Visual_Gradient'),
27178 type: { fillRule: {} },
27179 rule: {
27180 inputRole: 'Gradient',
27181 output: {
27182 property: 'fill',
27183 selector: ['Category'],
27184 },
27185 },
27186 }
27187 }
27188 },
27189 labels: {
27190 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
27191 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
27192 properties: {
27193 show: visuals.StandardObjectProperties.show,
27194 color: visuals.StandardObjectProperties.dataColor,
27195 labelPosition: {
27196 displayName: powerbi.data.createDisplayNameGetter('Visual_Position'),
27197 type: { enumeration: visuals.labelPosition.type },
27198 suppressFormatPainterCopy: true,
27199 },
27200 labelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
27201 labelPrecision: $.extend({}, visuals.StandardObjectProperties.labelPrecision, {
27202 suppressFormatPainterCopy: true,
27203 }),
27204 fontSize: visuals.StandardObjectProperties.fontSize,
27205 }
27206 },
27207 percentBarLabel: {
27208 displayName: powerbi.data.createDisplayNameGetter('Visual_PercentBarLabel'),
27209 description: powerbi.data.createDisplayNameGetter('Visual_PercentBarLabelDescription'),
27210 properties: {
27211 show: visuals.StandardObjectProperties.show,
27212 color: visuals.StandardObjectProperties.dataColor,
27213 fontSize: visuals.StandardObjectProperties.fontSize,
27214 }
27215 },
27216 },
27217 supportsHighlight: true,
27218 sorting: {
27219 default: {},
27220 },
27221 drilldown: {
27222 roles: ['Category']
27223 },
27224 };
27225 visuals.funnelChartProps = {
27226 general: {
27227 formatString: { objectName: 'general', propertyName: 'formatString' },
27228 },
27229 dataPoint: {
27230 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
27231 fill: { objectName: 'dataPoint', propertyName: 'fill' },
27232 },
27233 };
27234 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27235})(powerbi || (powerbi = {}));
27236/*
27237 * Power BI Visualizations
27238 *
27239 * Copyright (c) Microsoft Corporation
27240 * All rights reserved.
27241 * MIT License
27242 *
27243 * Permission is hereby granted, free of charge, to any person obtaining a copy
27244 * of this software and associated documentation files (the ""Software""), to deal
27245 * in the Software without restriction, including without limitation the rights
27246 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27247 * copies of the Software, and to permit persons to whom the Software is
27248 * furnished to do so, subject to the following conditions:
27249 *
27250 * The above copyright notice and this permission notice shall be included in
27251 * all copies or substantial portions of the Software.
27252 *
27253 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27254 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27255 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27256 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27257 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27258 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27259 * THE SOFTWARE.
27260 */
27261var powerbi;
27262(function (powerbi) {
27263 var visuals;
27264 (function (visuals) {
27265 visuals.gaugeRoleNames = {
27266 y: 'Y',
27267 minValue: 'MinValue',
27268 maxValue: 'MaxValue',
27269 targetValue: 'TargetValue'
27270 };
27271 visuals.gaugeCapabilities = {
27272 dataRoles: [
27273 {
27274 name: visuals.gaugeRoleNames.y,
27275 kind: powerbi.VisualDataRoleKind.Measure,
27276 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Value'),
27277 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ValueDescription'),
27278 requiredTypes: [{ numeric: true }, { integer: true }],
27279 }, {
27280 name: visuals.gaugeRoleNames.minValue,
27281 kind: powerbi.VisualDataRoleKind.Measure,
27282 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_MinValue'),
27283 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_MinValueDescription'),
27284 requiredTypes: [{ numeric: true }, { integer: true }],
27285 }, {
27286 name: visuals.gaugeRoleNames.maxValue,
27287 kind: powerbi.VisualDataRoleKind.Measure,
27288 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_MaxValue'),
27289 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_MaxValueDescription'),
27290 requiredTypes: [{ numeric: true }, { integer: true }],
27291 }, {
27292 name: visuals.gaugeRoleNames.targetValue,
27293 kind: powerbi.VisualDataRoleKind.Measure,
27294 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_TargetValue'),
27295 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_TargetValueDescription'),
27296 requiredTypes: [{ numeric: true }, { integer: true }],
27297 }
27298 ],
27299 objects: {
27300 general: {
27301 properties: {
27302 formatString: visuals.StandardObjectProperties.formatString,
27303 },
27304 },
27305 axis: {
27306 displayName: powerbi.data.createDisplayNameGetter('Visual_Gauge_Axis'),
27307 properties: {
27308 min: {
27309 displayName: powerbi.data.createDisplayNameGetter('Visual_Gauge_Axis_Min'),
27310 type: { numeric: true }
27311 },
27312 max: {
27313 displayName: powerbi.data.createDisplayNameGetter('Visual_Gauge_Axis_Max'),
27314 type: { numeric: true }
27315 },
27316 target: {
27317 displayName: powerbi.data.createDisplayNameGetter('Visual_Gauge_Axis_Target'),
27318 type: { numeric: true }
27319 },
27320 },
27321 },
27322 labels: {
27323 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
27324 properties: {
27325 show: visuals.StandardObjectProperties.show,
27326 color: visuals.StandardObjectProperties.dataColor,
27327 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
27328 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
27329 fontSize: visuals.StandardObjectProperties.fontSize,
27330 },
27331 },
27332 calloutValue: {
27333 displayName: powerbi.data.createDisplayNameGetter('Visual_Gauge_CalloutValue'),
27334 properties: {
27335 show: visuals.StandardObjectProperties.show,
27336 color: visuals.StandardObjectProperties.dataColor,
27337 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
27338 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
27339 },
27340 },
27341 dataPoint: {
27342 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
27343 properties: {
27344 fill: visuals.StandardObjectProperties.fill,
27345 target: {
27346 // TODO find a better string
27347 displayName: powerbi.data.createDisplayNameGetter('Visual_Gauge_Axis_Target'),
27348 type: { fill: { solid: { color: true } } }
27349 }
27350 }
27351 }
27352 },
27353 dataViewMappings: [{
27354 conditions: [
27355 { 'Y': { max: 1 }, 'MinValue': { max: 1 }, 'MaxValue': { max: 1 }, 'TargetValue': { max: 1 } },
27356 ],
27357 categorical: {
27358 values: {
27359 select: [
27360 { bind: { to: 'Y' } },
27361 { bind: { to: 'MinValue' } },
27362 { bind: { to: 'MaxValue' } },
27363 { bind: { to: 'TargetValue' } },
27364 ]
27365 },
27366 },
27367 }],
27368 supportsSelection: false,
27369 };
27370 visuals.gaugeProps = {
27371 dataPoint: {
27372 fill: { objectName: 'dataPoint', propertyName: 'fill' },
27373 target: { objectName: 'dataPoint', propertyName: 'target' }
27374 }
27375 };
27376 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27377})(powerbi || (powerbi = {}));
27378/*
27379 * Power BI Visualizations
27380 *
27381 * Copyright (c) Microsoft Corporation
27382 * All rights reserved.
27383 * MIT License
27384 *
27385 * Permission is hereby granted, free of charge, to any person obtaining a copy
27386 * of this software and associated documentation files (the ""Software""), to deal
27387 * in the Software without restriction, including without limitation the rights
27388 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27389 * copies of the Software, and to permit persons to whom the Software is
27390 * furnished to do so, subject to the following conditions:
27391 *
27392 * The above copyright notice and this permission notice shall be included in
27393 * all copies or substantial portions of the Software.
27394 *
27395 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27396 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27397 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27398 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27399 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27400 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27401 * THE SOFTWARE.
27402 */
27403var powerbi;
27404(function (powerbi) {
27405 var visuals;
27406 (function (visuals) {
27407 visuals.imageVisualCapabilities = {
27408 objects: {
27409 general: {
27410 properties: {
27411 imageUrl: {
27412 type: { misc: { imageUrl: true } }
27413 }
27414 }
27415 },
27416 imageScaling: {
27417 displayName: powerbi.data.createDisplayNameGetter('Visual_Image_Scaling_Type'),
27418 properties: {
27419 imageScalingType: {
27420 displayName: powerbi.data.createDisplayNameGetter('Visual_Image_Scaling_Type'),
27421 type: { enumeration: visuals.imageScalingType.type }
27422 },
27423 }
27424 },
27425 },
27426 suppressDefaultTitle: true,
27427 supportsSelection: false,
27428 };
27429 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27430})(powerbi || (powerbi = {}));
27431/*
27432 * Power BI Visualizations
27433 *
27434 * Copyright (c) Microsoft Corporation
27435 * All rights reserved.
27436 * MIT License
27437 *
27438 * Permission is hereby granted, free of charge, to any person obtaining a copy
27439 * of this software and associated documentation files (the ""Software""), to deal
27440 * in the Software without restriction, including without limitation the rights
27441 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27442 * copies of the Software, and to permit persons to whom the Software is
27443 * furnished to do so, subject to the following conditions:
27444 *
27445 * The above copyright notice and this permission notice shall be included in
27446 * all copies or substantial portions of the Software.
27447 *
27448 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27449 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27450 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27451 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27452 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27453 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27454 * THE SOFTWARE.
27455 */
27456var powerbi;
27457(function (powerbi) {
27458 var visuals;
27459 (function (visuals) {
27460 visuals.scriptVisualCapabilities = {
27461 dataRoles: [{
27462 name: 'Values',
27463 kind: powerbi.VisualDataRoleKind.GroupingOrMeasure,
27464 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
27465 }],
27466 dataViewMappings: [{
27467 scriptResult: {
27468 dataInput: {
27469 table: {
27470 rows: {
27471 for: {
27472 in: 'Values'
27473 },
27474 dataReductionAlgorithm: {
27475 top: {}
27476 }
27477 },
27478 },
27479 },
27480 script: {
27481 source: {
27482 objectName: 'script',
27483 propertyName: 'source'
27484 },
27485 provider: {
27486 objectName: 'script',
27487 propertyName: 'provider'
27488 },
27489 }
27490 }
27491 }],
27492 objects: {
27493 script: {
27494 properties: {
27495 provider: {
27496 type: { text: true }
27497 },
27498 source: {
27499 type: { scripting: { source: true }
27500 }
27501 },
27502 }
27503 },
27504 },
27505 };
27506 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27507})(powerbi || (powerbi = {}));
27508/*
27509* Power BI Visualizations
27510*
27511* Copyright (c) Microsoft Corporation
27512* All rights reserved.
27513* MIT License
27514*
27515* Permission is hereby granted, free of charge, to any person obtaining a copy
27516* of this software and associated documentation files (the ""Software""), to deal
27517* in the Software without restriction, including without limitation the rights
27518* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27519* copies of the Software, and to permit persons to whom the Software is
27520* furnished to do so, subject to the following conditions:
27521*
27522* The above copyright notice and this permission notice shall be included in
27523* all copies or substantial portions of the Software.
27524*
27525* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27526* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27527* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27528* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27529* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27530* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27531* THE SOFTWARE.
27532*/
27533var powerbi;
27534(function (powerbi) {
27535 var visuals;
27536 (function (visuals) {
27537 var samples;
27538 (function (samples) {
27539 samples.consoleWriterCapabilities = {
27540 dataRoles: [
27541 {
27542 name: 'Category',
27543 kind: powerbi.VisualDataRoleKind.Grouping,
27544 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Axis'),
27545 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_AxisDescription')
27546 },
27547 {
27548 name: 'Y',
27549 kind: powerbi.VisualDataRoleKind.Measure,
27550 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Y'),
27551 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_YDescription')
27552 },
27553 ],
27554 dataViewMappings: [{
27555 categorical: {
27556 categories: {
27557 for: { in: 'Category' },
27558 },
27559 },
27560 }],
27561 };
27562 })(samples = visuals.samples || (visuals.samples = {}));
27563 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27564})(powerbi || (powerbi = {}));
27565/*
27566 * Power BI Visualizations
27567 *
27568 * Copyright (c) Microsoft Corporation
27569 * All rights reserved.
27570 * MIT License
27571 *
27572 * Permission is hereby granted, free of charge, to any person obtaining a copy
27573 * of this software and associated documentation files (the ""Software""), to deal
27574 * in the Software without restriction, including without limitation the rights
27575 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27576 * copies of the Software, and to permit persons to whom the Software is
27577 * furnished to do so, subject to the following conditions:
27578 *
27579 * The above copyright notice and this permission notice shall be included in
27580 * all copies or substantial portions of the Software.
27581 *
27582 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27583 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27584 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27585 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27586 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27587 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27588 * THE SOFTWARE.
27589 */
27590var powerbi;
27591(function (powerbi) {
27592 var visuals;
27593 (function (visuals) {
27594 var samples;
27595 (function (samples) {
27596 var ConsoleWriter = (function () {
27597 function ConsoleWriter() {
27598 }
27599 ConsoleWriter.converter = function (dataView) {
27600 window.console.log('converter');
27601 window.console.log(dataView);
27602 return {};
27603 };
27604 ConsoleWriter.prototype.init = function (options) {
27605 var div = d3.select(options.element.get(0)).append("div");
27606 div.append("h1").text("ConsoleWriter");
27607 div.append("p").text("This IVisual writes messages passed to it to the javscript console output. Check your console for the actual messages passed. For more information, click below");
27608 var anchor = div.append('a');
27609 anchor.attr('href', "http://microsoft.github.io/PowerBI-visuals/modules/powerbi.html")
27610 .text("Online help");
27611 window.console.log('init');
27612 window.console.log(options);
27613 };
27614 ConsoleWriter.prototype.onResizing = function (viewport) { };
27615 ConsoleWriter.prototype.update = function (options) {
27616 window.console.log('update');
27617 window.console.log(options);
27618 };
27619 return ConsoleWriter;
27620 }());
27621 samples.ConsoleWriter = ConsoleWriter;
27622 })(samples = visuals.samples || (visuals.samples = {}));
27623 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27624})(powerbi || (powerbi = {}));
27625/*
27626 * Power BI Visualizations
27627 *
27628 * Copyright (c) Microsoft Corporation
27629 * All rights reserved.
27630 * MIT License
27631 *
27632 * Permission is hereby granted, free of charge, to any person obtaining a copy
27633 * of this software and associated documentation files (the ""Software""), to deal
27634 * in the Software without restriction, including without limitation the rights
27635 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27636 * copies of the Software, and to permit persons to whom the Software is
27637 * furnished to do so, subject to the following conditions:
27638 *
27639 * The above copyright notice and this permission notice shall be included in
27640 * all copies or substantial portions of the Software.
27641 *
27642 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27643 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27644 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27645 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27646 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27647 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27648 * THE SOFTWARE.
27649 */
27650var powerbi;
27651(function (powerbi) {
27652 var visuals;
27653 (function (visuals) {
27654 visuals.lineChartCapabilities = {
27655 dataRoles: [
27656 {
27657 name: 'Category',
27658 kind: powerbi.VisualDataRoleKind.Grouping,
27659 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Axis'),
27660 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_AxisDescription'),
27661 cartesianKind: 0 /* X */,
27662 }, {
27663 name: 'Series',
27664 kind: powerbi.VisualDataRoleKind.Grouping,
27665 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Legend'),
27666 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LegendDescription')
27667 }, {
27668 name: 'Y',
27669 kind: powerbi.VisualDataRoleKind.Measure,
27670 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
27671 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ValuesDescription'),
27672 requiredTypes: [{ numeric: true }, { integer: true }],
27673 cartesianKind: 1 /* Y */,
27674 },
27675 ],
27676 objects: {
27677 general: {
27678 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
27679 properties: {
27680 formatString: visuals.StandardObjectProperties.formatString,
27681 },
27682 },
27683 legend: {
27684 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
27685 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
27686 properties: {
27687 show: visuals.StandardObjectProperties.show,
27688 position: visuals.StandardObjectProperties.legendPosition,
27689 showTitle: visuals.StandardObjectProperties.showLegendTitle,
27690 titleText: $.extend({}, visuals.StandardObjectProperties.legendTitle, {
27691 suppressFormatPainterCopy: true
27692 }),
27693 labelColor: visuals.StandardObjectProperties.labelColor,
27694 fontSize: visuals.StandardObjectProperties.fontSize,
27695 }
27696 },
27697 dataPoint: {
27698 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
27699 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
27700 properties: {
27701 defaultColor: visuals.StandardObjectProperties.defaultColor,
27702 fill: visuals.StandardObjectProperties.fill,
27703 }
27704 },
27705 trend: {
27706 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line'),
27707 properties: {
27708 show: visuals.StandardObjectProperties.show,
27709 lineColor: {
27710 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color'),
27711 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color_Description'),
27712 type: { fill: { solid: { color: true } } }
27713 },
27714 transparency: {
27715 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency'),
27716 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency_Description'),
27717 type: { numeric: true }
27718 },
27719 style: {
27720 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style'),
27721 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style_Description'),
27722 type: { enumeration: visuals.lineStyle.type }
27723 },
27724 combineSeries: {
27725 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series'),
27726 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series_Description'),
27727 type: { bool: true }
27728 },
27729 useHighlightValues: {
27730 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_UseHighlightValues'),
27731 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_UseHighlightValues_Description'),
27732 type: { bool: true }
27733 },
27734 }
27735 },
27736 categoryAxis: {
27737 displayName: powerbi.data.createDisplayNameGetter('Visual_XAxis'),
27738 properties: {
27739 show: visuals.StandardObjectProperties.show,
27740 axisScale: visuals.StandardObjectProperties.axisScale,
27741 start: visuals.StandardObjectProperties.axisStart,
27742 end: visuals.StandardObjectProperties.axisEnd,
27743 axisType: visuals.StandardObjectProperties.axisType,
27744 showAxisTitle: {
27745 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
27746 description: powerbi.data.createDisplayNameGetter('Visual_Axis_XTitleDescription'),
27747 type: { bool: true }
27748 },
27749 axisStyle: visuals.StandardObjectProperties.axisStyle,
27750 labelColor: visuals.StandardObjectProperties.labelColor,
27751 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
27752 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
27753 }
27754 },
27755 valueAxis: {
27756 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis'),
27757 properties: {
27758 show: visuals.StandardObjectProperties.show,
27759 position: visuals.StandardObjectProperties.yAxisPosition,
27760 axisScale: visuals.StandardObjectProperties.axisScale,
27761 start: visuals.StandardObjectProperties.axisStart,
27762 end: visuals.StandardObjectProperties.axisEnd,
27763 showAxisTitle: {
27764 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
27765 description: powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription'),
27766 type: { bool: true }
27767 },
27768 axisStyle: visuals.StandardObjectProperties.axisStyle,
27769 labelColor: visuals.StandardObjectProperties.labelColor,
27770 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
27771 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
27772 }
27773 },
27774 y1AxisReferenceLine: {
27775 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line'),
27776 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Description'),
27777 properties: {
27778 show: visuals.StandardObjectProperties.show,
27779 value: {
27780 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value'),
27781 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value_Description'),
27782 type: { numeric: true }
27783 },
27784 lineColor: visuals.StandardObjectProperties.lineColor,
27785 transparency: {
27786 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency'),
27787 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency_Description'),
27788 type: { numeric: true }
27789 },
27790 style: visuals.StandardObjectProperties.referenceLineStyle,
27791 position: visuals.StandardObjectProperties.referenceLinePosition,
27792 dataLabelShow: visuals.StandardObjectProperties.dataLabelShow,
27793 dataLabelColor: visuals.StandardObjectProperties.dataLabelColor,
27794 dataLabelDecimalPoints: visuals.StandardObjectProperties.dataLabelDecimalPoints,
27795 dataLabelHorizontalPosition: visuals.StandardObjectProperties.dataLabelHorizontalPosition,
27796 dataLabelVerticalPosition: visuals.StandardObjectProperties.dataLabelVerticalPosition,
27797 dataLabelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
27798 },
27799 },
27800 labels: {
27801 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
27802 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
27803 properties: {
27804 show: visuals.StandardObjectProperties.show,
27805 showSeries: {
27806 displayName: powerbi.data.createDisplayNameGetter('Visual_Show'),
27807 type: { bool: true }
27808 },
27809 color: visuals.StandardObjectProperties.dataColor,
27810 labelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
27811 labelPrecision: $.extend({}, visuals.StandardObjectProperties.labelPrecision, {
27812 suppressFormatPainterCopy: true,
27813 }),
27814 showAll: {
27815 displayName: powerbi.data.createDisplayNameGetter('Visual_LabelSeriesShowAll'),
27816 type: { bool: true }
27817 },
27818 fontSize: visuals.StandardObjectProperties.fontSize,
27819 labelDensity: {
27820 displayName: powerbi.data.createDisplayNameGetter('Visual_LabelDensity'),
27821 type: { formatting: { labelDensity: true } },
27822 },
27823 },
27824 },
27825 plotArea: {
27826 displayName: powerbi.data.createDisplayNameGetter('Visual_Plot'),
27827 //description: data.createDisplayNameGetter('Visual_PlotDescription'),
27828 properties: {
27829 transparency: visuals.StandardObjectProperties.transparency,
27830 image: visuals.StandardObjectProperties.image,
27831 },
27832 },
27833 },
27834 dataViewMappings: [{
27835 conditions: [
27836 { 'Category': { max: 1 }, 'Series': { max: 0 } },
27837 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 } }
27838 ],
27839 categorical: {
27840 categories: {
27841 for: { in: 'Category' },
27842 dataReductionAlgorithm: { top: {} }
27843 },
27844 values: {
27845 group: {
27846 by: 'Series',
27847 select: [{ for: { in: 'Y' } }],
27848 dataReductionAlgorithm: { top: {} }
27849 }
27850 },
27851 },
27852 }, {
27853 conditions: [
27854 { 'Category': { max: 1 }, 'Series': { max: 0 } },
27855 { 'Category': { max: 1 }, 'Series': { min: 1, max: 1 }, 'Y': { max: 1 } }
27856 ],
27857 requiredProperties: [{ objectName: 'trend', propertyName: 'show' }],
27858 usage: {
27859 regression: {
27860 combineSeries: { objectName: 'trend', propertyName: 'combineSeries' }
27861 },
27862 },
27863 categorical: {
27864 categories: {
27865 for: { in: 'regression.X' },
27866 },
27867 values: {
27868 group: {
27869 by: 'regression.Series',
27870 select: [{ for: { in: 'regression.Y' } }],
27871 },
27872 }
27873 }
27874 }],
27875 sorting: {
27876 default: {},
27877 },
27878 };
27879 visuals.lineChartProps = {
27880 general: {
27881 formatString: { objectName: 'general', propertyName: 'formatString' },
27882 },
27883 dataPoint: {
27884 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
27885 fill: { objectName: 'dataPoint', propertyName: 'fill' },
27886 },
27887 trend: {
27888 show: { objectName: 'trend', propertyName: 'show' },
27889 },
27890 categoryAxis: {
27891 axisType: { objectName: 'categoryAxis', propertyName: 'axisType' },
27892 },
27893 legend: {
27894 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
27895 },
27896 labels: {
27897 labelDensity: { objectName: 'labels', propertyName: 'labelDensity' },
27898 },
27899 plotArea: {
27900 image: { objectName: 'plotArea', propertyName: 'image' },
27901 transparency: { objectName: 'plotArea', propertyName: 'transparency' },
27902 },
27903 };
27904 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
27905})(powerbi || (powerbi = {}));
27906/*
27907 * Power BI Visualizations
27908 *
27909 * Copyright (c) Microsoft Corporation
27910 * All rights reserved.
27911 * MIT License
27912 *
27913 * Permission is hereby granted, free of charge, to any person obtaining a copy
27914 * of this software and associated documentation files (the ""Software""), to deal
27915 * in the Software without restriction, including without limitation the rights
27916 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27917 * copies of the Software, and to permit persons to whom the Software is
27918 * furnished to do so, subject to the following conditions:
27919 *
27920 * The above copyright notice and this permission notice shall be included in
27921 * all copies or substantial portions of the Software.
27922 *
27923 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27924 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27925 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27926 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27927 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27928 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27929 * THE SOFTWARE.
27930 */
27931var powerbi;
27932(function (powerbi) {
27933 var visuals;
27934 (function (visuals) {
27935 visuals.mapCapabilities = {
27936 dataRoles: [
27937 {
27938 name: 'Category',
27939 kind: powerbi.VisualDataRoleKind.Grouping,
27940 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Location'),
27941 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LocationMapDescription'),
27942 preferredTypes: [
27943 { geography: { address: true } },
27944 { geography: { city: true } },
27945 { geography: { continent: true } },
27946 { geography: { country: true } },
27947 { geography: { county: true } },
27948 { geography: { place: true } },
27949 { geography: { postalCode: true } },
27950 { geography: { region: true } },
27951 { geography: { stateOrProvince: true } },
27952 ],
27953 }, {
27954 name: 'Series',
27955 kind: powerbi.VisualDataRoleKind.Grouping,
27956 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Legend'),
27957 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LegendDescription')
27958 }, {
27959 name: 'X',
27960 kind: powerbi.VisualDataRoleKind.GroupingOrMeasure,
27961 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Longitude'),
27962 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LongitudeMapDescription'),
27963 preferredTypes: [
27964 { geography: { longitude: true } }
27965 ],
27966 }, {
27967 name: 'Y',
27968 kind: powerbi.VisualDataRoleKind.GroupingOrMeasure,
27969 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Latitude'),
27970 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LatitudeMapDescription'),
27971 preferredTypes: [
27972 { geography: { latitude: true } }
27973 ],
27974 }, {
27975 name: 'Size',
27976 kind: powerbi.VisualDataRoleKind.Measure,
27977 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Size'),
27978 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_SizeDescription'),
27979 requiredTypes: [{ numeric: true }, { integer: true }],
27980 }, {
27981 name: 'Gradient',
27982 kind: powerbi.VisualDataRoleKind.Measure,
27983 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Gradient'),
27984 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GradientDescription'),
27985 requiredTypes: [{ numeric: true }, { integer: true }],
27986 }
27987 ],
27988 objects: {
27989 general: {
27990 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
27991 properties: {
27992 formatString: visuals.StandardObjectProperties.formatString,
27993 },
27994 },
27995 legend: {
27996 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
27997 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
27998 properties: {
27999 show: visuals.StandardObjectProperties.show,
28000 position: visuals.StandardObjectProperties.legendPosition,
28001 showTitle: visuals.StandardObjectProperties.showLegendTitle,
28002 titleText: visuals.StandardObjectProperties.legendTitle,
28003 fontSize: visuals.StandardObjectProperties.fontSize,
28004 }
28005 },
28006 dataPoint: {
28007 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
28008 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
28009 properties: {
28010 defaultColor: visuals.StandardObjectProperties.defaultColor,
28011 showAllDataPoints: visuals.StandardObjectProperties.showAllDataPoints,
28012 fill: visuals.StandardObjectProperties.fill,
28013 fillRule: {
28014 displayName: powerbi.data.createDisplayNameGetter('Visual_Gradient'),
28015 type: { fillRule: {} },
28016 rule: {
28017 inputRole: 'Gradient',
28018 output: {
28019 property: 'fill',
28020 selector: ['Category'],
28021 },
28022 },
28023 }
28024 }
28025 },
28026 categoryLabels: {
28027 displayName: powerbi.data.createDisplayNameGetter('Visual_CategoryLabels'),
28028 description: powerbi.data.createDisplayNameGetter('Visual_CategoryLabelsDescription'),
28029 properties: {
28030 show: visuals.StandardObjectProperties.show,
28031 color: visuals.StandardObjectProperties.dataColor,
28032 fontSize: visuals.StandardObjectProperties.fontSize,
28033 },
28034 },
28035 },
28036 dataViewMappings: [{
28037 conditions: [
28038 { 'Category': { min: 1, max: 1 }, 'Series': { max: 1 }, 'X': { max: 1, kind: powerbi.VisualDataRoleKind.Measure }, 'Y': { max: 1, kind: powerbi.VisualDataRoleKind.Measure }, 'Size': { max: 1 }, 'Gradient': { max: 0 } },
28039 { 'Category': { min: 1, max: 1 }, 'Series': { max: 0 }, 'X': { max: 1, kind: powerbi.VisualDataRoleKind.Measure }, 'Y': { max: 1, kind: powerbi.VisualDataRoleKind.Measure }, 'Size': { max: 1 }, 'Gradient': { max: 1 } },
28040 ],
28041 categorical: {
28042 categories: {
28043 for: { in: 'Category' },
28044 dataReductionAlgorithm: { top: {} }
28045 },
28046 values: {
28047 group: {
28048 by: 'Series',
28049 select: [
28050 { bind: { to: 'X' } },
28051 { bind: { to: 'Y' } },
28052 { bind: { to: 'Size' } },
28053 { bind: { to: 'Gradient' } },
28054 ],
28055 dataReductionAlgorithm: { top: {} }
28056 }
28057 },
28058 rowCount: { preferred: { min: 2 } },
28059 dataVolume: 4,
28060 }
28061 }, {
28062 conditions: [
28063 { 'Category': { max: 0 }, 'Series': { max: 1 }, 'X': { max: 1, kind: powerbi.VisualDataRoleKind.Grouping }, 'Y': { max: 1, kind: powerbi.VisualDataRoleKind.Grouping }, 'Size': { max: 1 }, 'Gradient': { max: 0 } },
28064 { 'Category': { max: 0 }, 'Series': { max: 0 }, 'X': { max: 1, kind: powerbi.VisualDataRoleKind.Grouping }, 'Y': { max: 1, kind: powerbi.VisualDataRoleKind.Grouping }, 'Size': { max: 1 }, 'Gradient': { max: 1 } }
28065 ],
28066 categorical: {
28067 categories: {
28068 select: [
28069 { bind: { to: 'X' } },
28070 { bind: { to: 'Y' } },
28071 ],
28072 dataReductionAlgorithm: { top: {} }
28073 },
28074 values: {
28075 group: {
28076 by: 'Series',
28077 select: [
28078 { bind: { to: 'Size' } },
28079 { bind: { to: 'Gradient' } },
28080 ],
28081 dataReductionAlgorithm: { top: {} }
28082 }
28083 },
28084 rowCount: { preferred: { min: 2 } },
28085 dataVolume: 4,
28086 },
28087 }],
28088 sorting: {
28089 custom: {},
28090 },
28091 drilldown: {
28092 roles: ['Category']
28093 },
28094 };
28095 visuals.mapProps = {
28096 general: {
28097 formatString: { objectName: 'general', propertyName: 'formatString' },
28098 },
28099 dataPoint: {
28100 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
28101 fill: { objectName: 'dataPoint', propertyName: 'fill' },
28102 showAllDataPoints: { objectName: 'dataPoint', propertyName: 'showAllDataPoints' },
28103 },
28104 legend: {
28105 show: { objectName: 'legend', propertyName: 'show' },
28106 position: { objectName: 'legend', propertyName: 'position' },
28107 showTitle: { objectName: 'legend', propertyName: 'showTitle' },
28108 titleText: { objectName: 'legend', propertyName: 'titleText' },
28109 },
28110 };
28111 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
28112})(powerbi || (powerbi = {}));
28113/*
28114 * Power BI Visualizations
28115 *
28116 * Copyright (c) Microsoft Corporation
28117 * All rights reserved.
28118 * MIT License
28119 *
28120 * Permission is hereby granted, free of charge, to any person obtaining a copy
28121 * of this software and associated documentation files (the ""Software""), to deal
28122 * in the Software without restriction, including without limitation the rights
28123 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28124 * copies of the Software, and to permit persons to whom the Software is
28125 * furnished to do so, subject to the following conditions:
28126 *
28127 * The above copyright notice and this permission notice shall be included in
28128 * all copies or substantial portions of the Software.
28129 *
28130 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28131 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28132 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28133 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28134 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28135 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28136 * THE SOFTWARE.
28137 */
28138var powerbi;
28139(function (powerbi) {
28140 var visuals;
28141 (function (visuals) {
28142 visuals.multiRowCardCapabilities = {
28143 dataRoles: [
28144 {
28145 name: 'Values',
28146 kind: powerbi.VisualDataRoleKind.GroupingOrMeasure,
28147 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Fields'),
28148 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_FieldsDescription')
28149 }
28150 ],
28151 objects: {
28152 general: {
28153 properties: {
28154 formatString: visuals.StandardObjectProperties.formatString,
28155 },
28156 },
28157 cardTitle: {
28158 displayName: powerbi.data.createDisplayNameGetter('Visual_CardTitle'),
28159 description: powerbi.data.createDisplayNameGetter('Visual_CardTitleDescription'),
28160 properties: {
28161 color: visuals.StandardObjectProperties.dataColor,
28162 fontSize: visuals.StandardObjectProperties.fontSize,
28163 }
28164 },
28165 dataLabels: {
28166 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
28167 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
28168 properties: {
28169 color: visuals.StandardObjectProperties.dataColor,
28170 fontSize: visuals.StandardObjectProperties.fontSize,
28171 }
28172 },
28173 categoryLabels: {
28174 displayName: powerbi.data.createDisplayNameGetter('Visual_CategoryLabels'),
28175 description: powerbi.data.createDisplayNameGetter('Visual_CategoryLabelsDescription'),
28176 properties: {
28177 show: visuals.StandardObjectProperties.show,
28178 color: visuals.StandardObjectProperties.dataColor,
28179 fontSize: visuals.StandardObjectProperties.fontSize,
28180 }
28181 },
28182 card: {
28183 displayName: powerbi.data.createDisplayNameGetter('Card_ToolTip'),
28184 properties: {
28185 outline: {
28186 displayName: powerbi.data.createDisplayNameGetter('Visual_Outline'),
28187 type: { enumeration: visuals.outline.type }
28188 },
28189 outlineColor: {
28190 displayName: powerbi.data.createDisplayNameGetter('Visual_OutlineColor'),
28191 description: powerbi.data.createDisplayNameGetter('Visual_OutlineColor_Desc'),
28192 type: { fill: { solid: { color: true } } }
28193 },
28194 outlineWeight: {
28195 displayName: powerbi.data.createDisplayNameGetter('Visual_OutlineWeight'),
28196 description: powerbi.data.createDisplayNameGetter('Visual_OutlineWeight_Desc'),
28197 type: { numeric: true }
28198 },
28199 barShow: {
28200 displayName: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_BarShow'),
28201 description: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_BarShow_Desc'),
28202 type: { bool: true }
28203 },
28204 barColor: {
28205 displayName: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_BarColor'),
28206 type: { fill: { solid: { color: true } } }
28207 },
28208 barWeight: {
28209 displayName: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_BarWeight'),
28210 description: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_BarWeight_Desc'),
28211 type: { numeric: true }
28212 },
28213 cardPadding: {
28214 displayName: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_CardPadding'),
28215 description: powerbi.data.createDisplayNameGetter('Visual_MultiRowCard_CardBackground'),
28216 type: { numeric: true }
28217 },
28218 cardBackground: {
28219 displayName: powerbi.data.createDisplayNameGetter('Visual_Background'),
28220 type: { fill: { solid: { color: true } } }
28221 }
28222 }
28223 }
28224 },
28225 dataViewMappings: [{
28226 table: {
28227 rows: {
28228 for: { in: 'Values' },
28229 dataReductionAlgorithm: { window: {} }
28230 },
28231 rowCount: { preferred: { min: 1 } }
28232 },
28233 }],
28234 sorting: {
28235 default: {},
28236 },
28237 suppressDefaultTitle: true,
28238 supportsSelection: false,
28239 disableVisualDetails: true,
28240 };
28241 visuals.multiRowCardProps = {
28242 card: {
28243 outline: { objectName: 'card', propertyName: 'outline' },
28244 outlineColor: { objectName: 'card', propertyName: 'outlineColor' },
28245 outlineWeight: { objectName: 'card', propertyName: 'outlineWeight' },
28246 barShow: { objectName: 'card', propertyName: 'barShow' },
28247 barColor: { objectName: 'card', propertyName: 'barColor' },
28248 barWeight: { objectName: 'card', propertyName: 'barWeight' },
28249 cardPadding: { objectName: 'card', propertyName: 'cardPadding' },
28250 cardBackground: { objectName: 'card', propertyName: 'cardBackground' },
28251 }
28252 };
28253 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
28254})(powerbi || (powerbi = {}));
28255/*
28256 * Power BI Visualizations
28257 *
28258 * Copyright (c) Microsoft Corporation
28259 * All rights reserved.
28260 * MIT License
28261 *
28262 * Permission is hereby granted, free of charge, to any person obtaining a copy
28263 * of this software and associated documentation files (the ""Software""), to deal
28264 * in the Software without restriction, including without limitation the rights
28265 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28266 * copies of the Software, and to permit persons to whom the Software is
28267 * furnished to do so, subject to the following conditions:
28268 *
28269 * The above copyright notice and this permission notice shall be included in
28270 * all copies or substantial portions of the Software.
28271 *
28272 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28273 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28274 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28275 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28276 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28277 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28278 * THE SOFTWARE.
28279 */
28280var powerbi;
28281(function (powerbi) {
28282 var visuals;
28283 (function (visuals) {
28284 visuals.textboxCapabilities = {
28285 objects: {
28286 general: {
28287 properties: {
28288 paragraphs: {
28289 type: { paragraphs: {} },
28290 suppressFormatPainterCopy: true,
28291 }
28292 }
28293 }
28294 },
28295 suppressDefaultTitle: true,
28296 supportsSelection: false,
28297 };
28298 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
28299})(powerbi || (powerbi = {}));
28300/*
28301* Power BI Visualizations
28302*
28303* Copyright (c) Microsoft Corporation
28304* All rights reserved.
28305* MIT License
28306*
28307* Permission is hereby granted, free of charge, to any person obtaining a copy
28308* of this software and associated documentation files (the ""Software""), to deal
28309* in the Software without restriction, including without limitation the rights
28310* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28311* copies of the Software, and to permit persons to whom the Software is
28312* furnished to do so, subject to the following conditions:
28313*
28314* The above copyright notice and this permission notice shall be included in
28315* all copies or substantial portions of the Software.
28316*
28317* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28318* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28319* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28320* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28321* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28322* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28323* THE SOFTWARE.
28324*/
28325var powerbi;
28326(function (powerbi) {
28327 var visuals;
28328 (function (visuals) {
28329 visuals.cheerMeterCapabilities = {
28330 dataRoles: [
28331 {
28332 name: 'Category',
28333 kind: powerbi.VisualDataRoleKind.Grouping,
28334 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Axis'),
28335 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_AxisDescription')
28336 },
28337 {
28338 name: 'Y',
28339 kind: powerbi.VisualDataRoleKind.Measure,
28340 requiredTypes: [{ numeric: true }, { integer: true }],
28341 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Y'),
28342 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_YDescription')
28343 },
28344 ],
28345 dataViewMappings: [{
28346 categorical: {
28347 categories: {
28348 for: { in: 'Category' },
28349 },
28350 },
28351 }],
28352 dataPoint: {
28353 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
28354 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
28355 properties: {
28356 fill: visuals.StandardObjectProperties.fill,
28357 }
28358 },
28359 };
28360 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
28361})(powerbi || (powerbi = {}));
28362/*
28363 * Power BI Visualizations
28364 *
28365 * Copyright (c) Microsoft Corporation
28366 * All rights reserved.
28367 * MIT License
28368 *
28369 * Permission is hereby granted, free of charge, to any person obtaining a copy
28370 * of this software and associated documentation files (the ""Software""), to deal
28371 * in the Software without restriction, including without limitation the rights
28372 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28373 * copies of the Software, and to permit persons to whom the Software is
28374 * furnished to do so, subject to the following conditions:
28375 *
28376 * The above copyright notice and this permission notice shall be included in
28377 * all copies or substantial portions of the Software.
28378 *
28379 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28380 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28381 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28382 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28383 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28384 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28385 * THE SOFTWARE.
28386 */
28387var powerbi;
28388(function (powerbi) {
28389 var visuals;
28390 (function (visuals) {
28391 visuals.scatterChartCapabilities = {
28392 dataRoles: [
28393 {
28394 name: 'Category',
28395 kind: powerbi.VisualDataRoleKind.Grouping,
28396 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Details'),
28397 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_DetailsScatterChartDescription'),
28398 }, {
28399 name: 'Series',
28400 kind: powerbi.VisualDataRoleKind.Grouping,
28401 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Legend'),
28402 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_LegendDescription')
28403 }, {
28404 name: 'X',
28405 kind: powerbi.VisualDataRoleKind.Measure,
28406 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_X'),
28407 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_XScatterChartDescription'),
28408 requiredTypes: [{ numeric: true }, { integer: true }],
28409 cartesianKind: 0 /* X */,
28410 }, {
28411 name: 'Y',
28412 kind: powerbi.VisualDataRoleKind.Measure,
28413 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Y'),
28414 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_YScatterChartDescription'),
28415 requiredTypes: [{ numeric: true }, { integer: true }],
28416 cartesianKind: 1 /* Y */,
28417 }, {
28418 name: 'Size',
28419 kind: powerbi.VisualDataRoleKind.Measure,
28420 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Size'),
28421 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_SizeDescription'),
28422 requiredTypes: [{ numeric: true }, { integer: true }],
28423 }, {
28424 name: 'Gradient',
28425 kind: powerbi.VisualDataRoleKind.Measure,
28426 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Gradient'),
28427 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GradientDescription'),
28428 requiredTypes: [{ numeric: true }, { integer: true }],
28429 }, {
28430 name: 'Play',
28431 kind: powerbi.VisualDataRoleKind.Grouping,
28432 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Play'),
28433 }
28434 ],
28435 objects: {
28436 dataPoint: {
28437 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
28438 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
28439 properties: {
28440 defaultColor: visuals.StandardObjectProperties.defaultColor,
28441 showAllDataPoints: visuals.StandardObjectProperties.showAllDataPoints,
28442 fill: visuals.StandardObjectProperties.fill,
28443 fillRule: {
28444 displayName: powerbi.data.createDisplayNameGetter('Visual_Gradient'),
28445 type: { fillRule: {} },
28446 rule: {
28447 inputRole: 'Gradient',
28448 output: {
28449 property: 'fill',
28450 selector: ['Category'],
28451 },
28452 },
28453 }
28454 }
28455 },
28456 general: {
28457 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
28458 properties: {
28459 formatString: visuals.StandardObjectProperties.formatString,
28460 },
28461 },
28462 trend: {
28463 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line'),
28464 properties: {
28465 show: visuals.StandardObjectProperties.show,
28466 lineColor: {
28467 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color'),
28468 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Color_Description'),
28469 type: { fill: { solid: { color: true } } }
28470 },
28471 transparency: {
28472 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency'),
28473 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Transparency_Description'),
28474 type: { numeric: true }
28475 },
28476 style: {
28477 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style'),
28478 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Style_Description'),
28479 type: { enumeration: visuals.lineStyle.type }
28480 },
28481 combineSeries: {
28482 displayName: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series'),
28483 description: powerbi.data.createDisplayNameGetter('Visual_Trend_Line_Combine_Series_Description'),
28484 type: { bool: true }
28485 },
28486 }
28487 },
28488 categoryAxis: {
28489 displayName: powerbi.data.createDisplayNameGetter('Visual_XAxis'),
28490 properties: {
28491 show: visuals.StandardObjectProperties.show,
28492 axisScale: visuals.StandardObjectProperties.axisScale,
28493 start: visuals.StandardObjectProperties.axisStart,
28494 end: visuals.StandardObjectProperties.axisEnd,
28495 showAxisTitle: {
28496 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
28497 description: powerbi.data.createDisplayNameGetter('Visual_Axis_XTitleDescription'),
28498 type: { bool: true }
28499 },
28500 axisStyle: visuals.StandardObjectProperties.axisStyle,
28501 labelColor: visuals.StandardObjectProperties.labelColor,
28502 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
28503 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
28504 }
28505 },
28506 valueAxis: {
28507 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis'),
28508 properties: {
28509 show: visuals.StandardObjectProperties.show,
28510 position: visuals.StandardObjectProperties.yAxisPosition,
28511 axisScale: visuals.StandardObjectProperties.axisScale,
28512 start: visuals.StandardObjectProperties.axisStart,
28513 end: visuals.StandardObjectProperties.axisEnd,
28514 showAxisTitle: {
28515 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
28516 description: powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription'),
28517 type: { bool: true }
28518 },
28519 axisStyle: visuals.StandardObjectProperties.axisStyle,
28520 labelColor: visuals.StandardObjectProperties.labelColor,
28521 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
28522 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
28523 }
28524 },
28525 xAxisReferenceLine: {
28526 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_X'),
28527 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Description'),
28528 properties: {
28529 show: visuals.StandardObjectProperties.show,
28530 value: {
28531 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value'),
28532 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value_Description'),
28533 type: { numeric: true }
28534 },
28535 lineColor: visuals.StandardObjectProperties.lineColor,
28536 transparency: {
28537 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency'),
28538 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency_Description'),
28539 type: { numeric: true }
28540 },
28541 style: visuals.StandardObjectProperties.referenceLineStyle,
28542 position: visuals.StandardObjectProperties.referenceLinePosition,
28543 dataLabelShow: visuals.StandardObjectProperties.dataLabelShow,
28544 dataLabelColor: visuals.StandardObjectProperties.dataLabelColor,
28545 dataLabelDecimalPoints: visuals.StandardObjectProperties.dataLabelDecimalPoints,
28546 dataLabelHorizontalPosition: visuals.StandardObjectProperties.dataLabelHorizontalPosition,
28547 dataLabelVerticalPosition: visuals.StandardObjectProperties.dataLabelVerticalPosition,
28548 dataLabelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
28549 },
28550 },
28551 y1AxisReferenceLine: {
28552 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Y'),
28553 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Description'),
28554 properties: {
28555 show: visuals.StandardObjectProperties.show,
28556 value: {
28557 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value'),
28558 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value_Description'),
28559 type: { numeric: true }
28560 },
28561 lineColor: visuals.StandardObjectProperties.lineColor,
28562 transparency: {
28563 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency'),
28564 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency_Description'),
28565 type: { numeric: true }
28566 },
28567 style: visuals.StandardObjectProperties.referenceLineStyle,
28568 position: visuals.StandardObjectProperties.referenceLinePosition,
28569 dataLabelShow: visuals.StandardObjectProperties.dataLabelShow,
28570 dataLabelColor: visuals.StandardObjectProperties.dataLabelColor,
28571 dataLabelDecimalPoints: visuals.StandardObjectProperties.dataLabelDecimalPoints,
28572 dataLabelHorizontalPosition: visuals.StandardObjectProperties.dataLabelHorizontalPosition,
28573 dataLabelVerticalPosition: visuals.StandardObjectProperties.dataLabelVerticalPosition,
28574 dataLabelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
28575 },
28576 },
28577 legend: {
28578 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
28579 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
28580 properties: {
28581 show: visuals.StandardObjectProperties.show,
28582 position: visuals.StandardObjectProperties.legendPosition,
28583 showTitle: visuals.StandardObjectProperties.showLegendTitle,
28584 titleText: $.extend({}, visuals.StandardObjectProperties.legendTitle, {
28585 suppressFormatPainterCopy: true
28586 }),
28587 labelColor: visuals.StandardObjectProperties.labelColor,
28588 fontSize: visuals.StandardObjectProperties.fontSize,
28589 }
28590 },
28591 categoryLabels: {
28592 displayName: powerbi.data.createDisplayNameGetter('Visual_CategoryLabels'),
28593 description: powerbi.data.createDisplayNameGetter('Visual_CategoryLabelsDescription'),
28594 properties: {
28595 show: visuals.StandardObjectProperties.show,
28596 color: visuals.StandardObjectProperties.dataColor,
28597 fontSize: visuals.StandardObjectProperties.fontSize,
28598 },
28599 },
28600 colorBorder: {
28601 displayName: powerbi.data.createDisplayNameGetter('Visual_ColorBorder'),
28602 properties: {
28603 show: visuals.StandardObjectProperties.show,
28604 },
28605 },
28606 fillPoint: {
28607 displayName: powerbi.data.createDisplayNameGetter('Visual_FillPoint'),
28608 properties: {
28609 show: visuals.StandardObjectProperties.show,
28610 },
28611 },
28612 colorByCategory: {
28613 displayName: powerbi.data.createDisplayNameGetter('Visual_ColorByCategory'),
28614 properties: {
28615 show: visuals.StandardObjectProperties.show,
28616 }
28617 },
28618 currentFrameIndex: {
28619 properties: {
28620 index: {
28621 type: { numeric: true },
28622 }
28623 }
28624 },
28625 plotArea: {
28626 displayName: powerbi.data.createDisplayNameGetter('Visual_Plot'),
28627 //description: data.createDisplayNameGetter('Visual_PlotDescription'),
28628 properties: {
28629 transparency: visuals.StandardObjectProperties.transparency,
28630 image: visuals.StandardObjectProperties.image,
28631 },
28632 },
28633 },
28634 dataViewMappings: [{
28635 conditions: [
28636 { 'Category': { max: 1 }, 'Series': { max: 1 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 1 }, 'Gradient': { max: 0 }, 'Play': { max: 0 } },
28637 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 1 }, 'Gradient': { max: 1 }, 'Play': { max: 0 } },
28638 ],
28639 categorical: {
28640 categories: {
28641 for: { in: 'Category' },
28642 },
28643 values: {
28644 group: {
28645 by: 'Series',
28646 select: [
28647 { bind: { to: 'X' } },
28648 { bind: { to: 'Y' } },
28649 { bind: { to: 'Size' } },
28650 { bind: { to: 'Gradient' } },
28651 ],
28652 }
28653 },
28654 rowCount: { preferred: { min: 2 } },
28655 dataReductionAlgorithm: { sample: {} },
28656 dataVolume: 4,
28657 }
28658 }, {
28659 conditions: [
28660 { 'Category': { max: 1 }, 'Series': { max: 1 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 1 }, 'Gradient': { max: 0 }, 'Play': { min: 1, max: 1 } },
28661 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 1 }, 'Gradient': { max: 1 }, 'Play': { min: 1, max: 1 } },
28662 ],
28663 // Long term: consider adding the 'name' concept and have this be a reference to the other dataViewMapping above.
28664 // Then we'd also move the splitting logic of Matrix->Categorical[] into DataViewTransform, and other visuals would benefit.
28665 matrix: {
28666 rows: {
28667 select: [
28668 { bind: { to: 'Play' } },
28669 { bind: { to: 'Category' } },
28670 ],
28671 /* Explicitly override the server data reduction to make it appropriate for matrix/play. */
28672 dataReductionAlgorithm: { bottom: { count: 5000 } }
28673 },
28674 columns: {
28675 for: { in: 'Series' },
28676 /* Explicitly override the server data reduction to make it appropriate for matrix/play. */
28677 dataReductionAlgorithm: { top: { count: 60 } }
28678 },
28679 values: {
28680 select: [
28681 { bind: { to: 'X' } },
28682 { bind: { to: 'Y' } },
28683 { bind: { to: 'Size' } },
28684 ]
28685 }
28686 }
28687 }, {
28688 conditions: [
28689 { 'Category': { max: 1 }, 'Series': { max: 1 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 0 }, 'Gradient': { max: 0 }, 'Play': { max: 0 } },
28690 { 'Category': { max: 1 }, 'Series': { max: 0 }, 'X': { max: 1 }, 'Y': { max: 1 }, 'Size': { max: 0 }, 'Gradient': { max: 1 }, 'Play': { max: 0 } },
28691 ],
28692 requiredProperties: [{ objectName: 'trend', propertyName: 'show' }],
28693 usage: {
28694 regression: {
28695 combineSeries: { objectName: 'trend', propertyName: 'combineSeries' }
28696 },
28697 },
28698 categorical: {
28699 categories: {
28700 for: { in: 'regression.X' }
28701 },
28702 values: {
28703 group: {
28704 by: 'regression.Series',
28705 select: [{ for: { in: 'regression.Y' } }],
28706 },
28707 },
28708 dataReductionAlgorithm: { sample: {} },
28709 dataVolume: 4,
28710 }
28711 }],
28712 sorting: {
28713 custom: {},
28714 implicit: {
28715 clauses: [{ role: 'Play', direction: 1 /* Ascending */ }] //typically a datetime field, sort asc
28716 },
28717 },
28718 drilldown: {
28719 roles: ['Category']
28720 },
28721 };
28722 visuals.scatterChartProps = {
28723 general: {
28724 formatString: { objectName: 'general', propertyName: 'formatString' },
28725 },
28726 dataPoint: {
28727 defaultColor: { objectName: 'dataPoint', propertyName: 'defaultColor' },
28728 fill: { objectName: 'dataPoint', propertyName: 'fill' },
28729 },
28730 trend: {
28731 show: { objectName: 'trend', propertyName: 'show' },
28732 },
28733 colorBorder: {
28734 show: { objectName: 'colorBorder', propertyName: 'show' },
28735 },
28736 fillPoint: {
28737 show: { objectName: 'fillPoint', propertyName: 'show' },
28738 },
28739 colorByCategory: {
28740 show: { objectName: 'colorByCategory', propertyName: 'show' },
28741 },
28742 currentFrameIndex: {
28743 index: { objectName: 'currentFrameIndex', propertyName: 'index' },
28744 },
28745 legend: {
28746 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
28747 },
28748 plotArea: {
28749 image: { objectName: 'plotArea', propertyName: 'image' },
28750 transparency: { objectName: 'plotArea', propertyName: 'transparency' },
28751 },
28752 };
28753 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
28754})(powerbi || (powerbi = {}));
28755/*
28756 * Power BI Visualizations
28757 *
28758 * Copyright (c) Microsoft Corporation
28759 * All rights reserved.
28760 * MIT License
28761 *
28762 * Permission is hereby granted, free of charge, to any person obtaining a copy
28763 * of this software and associated documentation files (the ""Software""), to deal
28764 * in the Software without restriction, including without limitation the rights
28765 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28766 * copies of the Software, and to permit persons to whom the Software is
28767 * furnished to do so, subject to the following conditions:
28768 *
28769 * The above copyright notice and this permission notice shall be included in
28770 * all copies or substantial portions of the Software.
28771 *
28772 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28773 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28774 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28775 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28776 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28777 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28778 * THE SOFTWARE.
28779 */
28780var powerbi;
28781(function (powerbi) {
28782 var visuals;
28783 (function (visuals) {
28784 visuals.slicerCapabilities = {
28785 dataRoles: [
28786 {
28787 name: 'Values',
28788 kind: powerbi.VisualDataRoleKind.Grouping,
28789 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Field'),
28790 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_FieldDescription')
28791 }
28792 ],
28793 objects: {
28794 general: {
28795 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
28796 properties: {
28797 filter: {
28798 type: { filter: {} },
28799 },
28800 defaultValue: {
28801 type: { expression: { defaultValue: true } },
28802 },
28803 formatString: visuals.StandardObjectProperties.formatString,
28804 outlineColor: visuals.StandardObjectProperties.outlineColor,
28805 outlineWeight: visuals.StandardObjectProperties.outlineWeight,
28806 orientation: {
28807 displayName: powerbi.data.createDisplayNameGetter('Slicer_Orientation'),
28808 type: { enumeration: visuals.slicerOrientation.type }
28809 },
28810 count: {
28811 type: { integer: true }
28812 },
28813 },
28814 },
28815 selection: {
28816 displayName: powerbi.data.createDisplayNameGetter('Visual_SelectionControls'),
28817 properties: {
28818 selectAllCheckboxEnabled: {
28819 displayName: powerbi.data.createDisplayNameGetter('Visual_SelectAll'),
28820 type: { bool: true }
28821 },
28822 singleSelect: {
28823 displayName: powerbi.data.createDisplayNameGetter('Visual_SingleSelect'),
28824 type: { bool: true }
28825 }
28826 },
28827 },
28828 header: {
28829 displayName: powerbi.data.createDisplayNameGetter('Visual_Header'),
28830 properties: {
28831 show: visuals.StandardObjectProperties.show,
28832 fontColor: visuals.StandardObjectProperties.fontColor,
28833 background: {
28834 displayName: powerbi.data.createDisplayNameGetter('Visual_Background'),
28835 type: { fill: { solid: { color: true } } }
28836 },
28837 outline: visuals.StandardObjectProperties.outline,
28838 textSize: {
28839 displayName: powerbi.data.createDisplayNameGetter('Visual_TextSize'),
28840 type: { numeric: true }
28841 },
28842 }
28843 },
28844 items: {
28845 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Items'),
28846 properties: {
28847 fontColor: visuals.StandardObjectProperties.fontColor,
28848 background: {
28849 displayName: powerbi.data.createDisplayNameGetter('Visual_Background'),
28850 type: { fill: { solid: { color: true } } }
28851 },
28852 outline: visuals.StandardObjectProperties.outline,
28853 textSize: {
28854 displayName: powerbi.data.createDisplayNameGetter('Visual_TextSize'),
28855 type: { numeric: true }
28856 },
28857 }
28858 }
28859 },
28860 dataViewMappings: [{
28861 conditions: [{ 'Values': { max: 1 } }],
28862 categorical: {
28863 categories: {
28864 for: { in: 'Values' },
28865 dataReductionAlgorithm: { window: {} }
28866 },
28867 includeEmptyGroups: true,
28868 }
28869 }],
28870 sorting: {
28871 default: {},
28872 },
28873 suppressDefaultTitle: true,
28874 disableVisualDetails: true,
28875 };
28876 // TODO: Generate these from above, defining twice just introduces potential for error
28877 visuals.slicerProps = {
28878 general: {
28879 outlineColor: { objectName: 'general', propertyName: 'outlineColor' },
28880 outlineWeight: { objectName: 'general', propertyName: 'outlineWeight' },
28881 orientation: { objectName: 'general', propertyName: 'orientation' },
28882 count: { objectName: 'general', propertyName: 'count' },
28883 },
28884 selection: {
28885 selectAllCheckboxEnabled: { objectName: 'selection', propertyName: 'selectAllCheckboxEnabled' },
28886 singleSelect: { objectName: 'selection', propertyName: 'singleSelect' }
28887 },
28888 header: {
28889 show: { objectName: 'header', propertyName: 'show' },
28890 fontColor: { objectName: 'header', propertyName: 'fontColor' },
28891 background: { objectName: 'header', propertyName: 'background' },
28892 outline: { objectName: 'header', propertyName: 'outline' },
28893 textSize: { objectName: 'header', propertyName: 'textSize' },
28894 },
28895 items: {
28896 fontColor: { objectName: 'items', propertyName: 'fontColor' },
28897 background: { objectName: 'items', propertyName: 'background' },
28898 outline: { objectName: 'items', propertyName: 'outline' },
28899 textSize: { objectName: 'items', propertyName: 'textSize' },
28900 },
28901 selectedPropertyIdentifier: { objectName: 'general', propertyName: 'selected' },
28902 filterPropertyIdentifier: { objectName: 'general', propertyName: 'filter' },
28903 formatString: { objectName: 'general', propertyName: 'formatString' },
28904 defaultValue: { objectName: 'general', propertyName: 'defaultValue' },
28905 };
28906 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
28907})(powerbi || (powerbi = {}));
28908/*
28909 * Power BI Visualizations
28910 *
28911 * Copyright (c) Microsoft Corporation
28912 * All rights reserved.
28913 * MIT License
28914 *
28915 * Permission is hereby granted, free of charge, to any person obtaining a copy
28916 * of this software and associated documentation files (the ""Software""), to deal
28917 * in the Software without restriction, including without limitation the rights
28918 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28919 * copies of the Software, and to permit persons to whom the Software is
28920 * furnished to do so, subject to the following conditions:
28921 *
28922 * The above copyright notice and this permission notice shall be included in
28923 * all copies or substantial portions of the Software.
28924 *
28925 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28926 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28927 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28928 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28929 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28930 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28931 * THE SOFTWARE.
28932 */
28933var powerbi;
28934(function (powerbi) {
28935 var visuals;
28936 (function (visuals) {
28937 visuals.tableCapabilities = {
28938 dataRoles: [{
28939 name: 'Values',
28940 kind: powerbi.VisualDataRoleKind.GroupingOrMeasure,
28941 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
28942 }],
28943 objects: {
28944 general: {
28945 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
28946 properties: {
28947 formatString: visuals.StandardObjectProperties.formatString,
28948 columnWidth: {
28949 type: { numeric: true }
28950 },
28951 totals: {
28952 type: { bool: true },
28953 displayName: powerbi.data.createDisplayNameGetter('Visual_Totals'),
28954 suppressFormatPainterCopy: true,
28955 },
28956 autoSizeColumnWidth: {
28957 type: { bool: true },
28958 displayName: powerbi.data.createDisplayNameGetter('Visual_Adjust_Column_Width'),
28959 suppressFormatPainterCopy: true,
28960 },
28961 textSize: {
28962 displayName: powerbi.data.createDisplayNameGetter('Visual_TextSize'),
28963 type: { numeric: true }
28964 },
28965 },
28966 },
28967 grid: {
28968 displayName: powerbi.data.createDisplayNameGetter('Visual_Grid'),
28969 properties: {
28970 outlineColor: visuals.StandardObjectProperties.outlineColor,
28971 outlineWeight: visuals.StandardObjectProperties.outlineWeight,
28972 gridVertical: {
28973 displayName: powerbi.data.createDisplayNameGetter('Visual_GridVertical'),
28974 description: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Desc'),
28975 type: { bool: true }
28976 },
28977 gridVerticalColor: {
28978 displayName: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Color'),
28979 description: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Color_Desc'),
28980 type: { fill: { solid: { color: true } } }
28981 },
28982 gridVerticalWeight: {
28983 displayName: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Weight'),
28984 description: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Weight_Desc'),
28985 type: { numeric: true }
28986 },
28987 gridHorizontal: {
28988 displayName: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal'),
28989 description: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Desc'),
28990 type: { bool: true }
28991 },
28992 gridHorizontalColor: {
28993 displayName: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Color'),
28994 description: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Color_Desc'),
28995 type: { fill: { solid: { color: true } } }
28996 },
28997 gridHorizontalWeight: {
28998 displayName: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Weight'),
28999 description: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Weight_Desc'),
29000 type: { numeric: true }
29001 },
29002 rowPadding: {
29003 displayName: powerbi.data.createDisplayNameGetter('Visual_RowPadding'),
29004 description: powerbi.data.createDisplayNameGetter('Visual_RowPadding_Desc'),
29005 type: { numeric: true }
29006 },
29007 imageHeight: {
29008 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_ImageHeight'),
29009 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_ImageHeight_Desc'),
29010 type: { numeric: true }
29011 },
29012 }
29013 },
29014 columnHeaders: {
29015 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_ColumnHeaders'),
29016 properties: {
29017 outline: visuals.StandardObjectProperties.outline,
29018 fontColor: visuals.StandardObjectProperties.fontColor,
29019 backColor: visuals.StandardObjectProperties.backColor,
29020 }
29021 },
29022 values: {
29023 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_Values'),
29024 properties: {
29025 outline: visuals.StandardObjectProperties.outline,
29026 // backColor overrides backColorPrimary and Secondary (e.g., in the case of conditional formatting)
29027 backColor: {
29028 type: { fill: { solid: { color: true } } }
29029 },
29030 fontColorPrimary: {
29031 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorPrimary'),
29032 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorPrimary_Desc'),
29033 type: { fill: { solid: { color: true } } }
29034 },
29035 backColorPrimary: {
29036 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorPrimary'),
29037 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorPrimary_Desc'),
29038 type: { fill: { solid: { color: true } } }
29039 },
29040 fontColorSecondary: {
29041 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorSecondary'),
29042 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorSecondary_Desc'),
29043 type: { fill: { solid: { color: true } } }
29044 },
29045 backColorSecondary: {
29046 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorSecondary'),
29047 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorSecondary_Desc'),
29048 type: { fill: { solid: { color: true } } }
29049 },
29050 urlIcon: {
29051 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_UrlIcon'),
29052 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_UrlIcon_Desc'),
29053 type: { bool: true }
29054 },
29055 }
29056 },
29057 total: {
29058 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_TotalGrand'),
29059 properties: {
29060 outline: visuals.StandardObjectProperties.outline,
29061 fontColor: visuals.StandardObjectProperties.fontColor,
29062 backColor: visuals.StandardObjectProperties.backColor,
29063 }
29064 },
29065 },
29066 dataViewMappings: [{
29067 table: {
29068 rows: {
29069 for: { in: 'Values' },
29070 dataReductionAlgorithm: { window: { count: 500 } }
29071 },
29072 rowCount: { preferred: { min: 1 } }
29073 },
29074 }],
29075 sorting: {
29076 custom: {},
29077 },
29078 suppressDefaultTitle: true,
29079 supportsSelection: false,
29080 disableVisualDetails: true,
29081 };
29082 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29083})(powerbi || (powerbi = {}));
29084/*
29085 * Power BI Visualizations
29086 *
29087 * Copyright (c) Microsoft Corporation
29088 * All rights reserved.
29089 * MIT License
29090 *
29091 * Permission is hereby granted, free of charge, to any person obtaining a copy
29092 * of this software and associated documentation files (the ""Software""), to deal
29093 * in the Software without restriction, including without limitation the rights
29094 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29095 * copies of the Software, and to permit persons to whom the Software is
29096 * furnished to do so, subject to the following conditions:
29097 *
29098 * The above copyright notice and this permission notice shall be included in
29099 * all copies or substantial portions of the Software.
29100 *
29101 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29102 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29103 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29104 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29105 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29106 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29107 * THE SOFTWARE.
29108 */
29109var powerbi;
29110(function (powerbi) {
29111 var visuals;
29112 (function (visuals) {
29113 visuals.matrixRoleNames = {
29114 rows: 'Rows',
29115 columns: 'Columns',
29116 values: 'Values',
29117 };
29118 visuals.matrixCapabilities = {
29119 dataRoles: [
29120 {
29121 name: visuals.matrixRoleNames.rows,
29122 kind: powerbi.VisualDataRoleKind.Grouping,
29123 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Rows'),
29124 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_RowsDescription')
29125 }, {
29126 name: visuals.matrixRoleNames.columns,
29127 kind: powerbi.VisualDataRoleKind.Grouping,
29128 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Columns'),
29129 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ColumnsDescription')
29130 }, {
29131 name: visuals.matrixRoleNames.values,
29132 kind: powerbi.VisualDataRoleKind.Measure,
29133 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values')
29134 }
29135 ],
29136 objects: {
29137 general: {
29138 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
29139 properties: {
29140 formatString: visuals.StandardObjectProperties.formatString,
29141 columnWidth: {
29142 type: { numeric: true }
29143 },
29144 rowSubtotals: {
29145 type: { bool: true },
29146 displayName: powerbi.data.createDisplayNameGetter('Visual_TotalRow'),
29147 suppressFormatPainterCopy: true,
29148 },
29149 columnSubtotals: {
29150 type: { bool: true },
29151 displayName: powerbi.data.createDisplayNameGetter('Visual_TotalColumn'),
29152 suppressFormatPainterCopy: true,
29153 },
29154 autoSizeColumnWidth: {
29155 type: { bool: true },
29156 displayName: powerbi.data.createDisplayNameGetter('Visual_Adjust_Column_Width'),
29157 suppressFormatPainterCopy: true,
29158 },
29159 textSize: {
29160 displayName: powerbi.data.createDisplayNameGetter('Visual_TextSize'),
29161 type: { numeric: true }
29162 },
29163 },
29164 },
29165 grid: {
29166 displayName: powerbi.data.createDisplayNameGetter('Visual_Grid'),
29167 properties: {
29168 outlineColor: visuals.StandardObjectProperties.outlineColor,
29169 outlineWeight: visuals.StandardObjectProperties.outlineWeight,
29170 gridVertical: {
29171 displayName: powerbi.data.createDisplayNameGetter('Visual_GridVertical'),
29172 description: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Desc'),
29173 type: { bool: true }
29174 },
29175 gridVerticalColor: {
29176 displayName: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Color'),
29177 description: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Color_Desc'),
29178 type: { fill: { solid: { color: true } } }
29179 },
29180 gridVerticalWeight: {
29181 displayName: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Weight'),
29182 description: powerbi.data.createDisplayNameGetter('Visual_GridVertical_Weight_Desc'),
29183 type: { numeric: true }
29184 },
29185 gridHorizontal: {
29186 displayName: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal'),
29187 description: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Desc'),
29188 type: { bool: true }
29189 },
29190 gridHorizontalColor: {
29191 displayName: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Color'),
29192 description: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Color_Desc'),
29193 type: { fill: { solid: { color: true } } }
29194 },
29195 gridHorizontalWeight: {
29196 displayName: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Weight'),
29197 description: powerbi.data.createDisplayNameGetter('Visual_GridHorizontal_Weight_Desc'),
29198 type: { numeric: true }
29199 },
29200 rowPadding: {
29201 displayName: powerbi.data.createDisplayNameGetter('Visual_RowPadding'),
29202 description: powerbi.data.createDisplayNameGetter('Visual_RowPadding_Desc'),
29203 type: { numeric: true }
29204 },
29205 imageHeight: {
29206 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_ImageHeight'),
29207 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_ImageHeight_Desc'),
29208 type: { numeric: true }
29209 },
29210 },
29211 },
29212 columnHeaders: {
29213 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_ColumnHeaders'),
29214 properties: {
29215 outline: visuals.StandardObjectProperties.outline,
29216 fontColor: visuals.StandardObjectProperties.fontColor,
29217 backColor: visuals.StandardObjectProperties.backColor,
29218 }
29219 },
29220 rowHeaders: {
29221 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_RowHeaders'),
29222 properties: {
29223 outline: visuals.StandardObjectProperties.outline,
29224 fontColor: visuals.StandardObjectProperties.fontColor,
29225 backColor: visuals.StandardObjectProperties.backColor,
29226 }
29227 },
29228 values: {
29229 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_Values'),
29230 properties: {
29231 outline: visuals.StandardObjectProperties.outline,
29232 fontColorPrimary: {
29233 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorPrimary'),
29234 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorPrimary_Desc'),
29235 type: { fill: { solid: { color: true } } }
29236 },
29237 backColorPrimary: {
29238 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorPrimary'),
29239 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorPrimary_Desc'),
29240 type: { fill: { solid: { color: true } } }
29241 },
29242 fontColorSecondary: {
29243 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorSecondary'),
29244 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_FontColorSecondary_Desc'),
29245 type: { fill: { solid: { color: true } } }
29246 },
29247 backColorSecondary: {
29248 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorSecondary'),
29249 description: powerbi.data.createDisplayNameGetter('Visual_Tablix_BackColorSecondary_Desc'),
29250 type: { fill: { solid: { color: true } } }
29251 },
29252 }
29253 },
29254 subTotals: {
29255 displayName: powerbi.data.createDisplayNameGetter('Visual_Tablix_TotalSub'),
29256 properties: {
29257 outline: visuals.StandardObjectProperties.outline,
29258 fontColor: visuals.StandardObjectProperties.fontColor,
29259 backColor: visuals.StandardObjectProperties.backColor,
29260 }
29261 },
29262 },
29263 dataViewMappings: [{
29264 conditions: [
29265 { 'Rows': { max: 0 }, 'Columns': { max: 0 }, 'Values': { min: 1 } },
29266 { 'Rows': { min: 1 }, 'Columns': { min: 0 }, 'Values': { min: 0 } },
29267 { 'Rows': { min: 0 }, 'Columns': { min: 1 }, 'Values': { min: 0 } }
29268 ],
29269 matrix: {
29270 rows: {
29271 for: { in: 'Rows' },
29272 /* Explicitly override the server data reduction to make it appropriate for matrix. */
29273 dataReductionAlgorithm: { window: { count: 500 } }
29274 },
29275 columns: {
29276 for: { in: 'Columns' },
29277 /* Explicitly override the server data reduction to make it appropriate for matrix. */
29278 dataReductionAlgorithm: { top: { count: 100 } }
29279 },
29280 values: {
29281 for: { in: 'Values' }
29282 }
29283 }
29284 }],
29285 filterMappings: {
29286 measureFilter: {
29287 targetRoles: [visuals.matrixRoleNames.rows]
29288 }
29289 },
29290 sorting: {
29291 custom: {},
29292 },
29293 suppressDefaultTitle: true,
29294 supportsSelection: false,
29295 disableVisualDetails: true,
29296 };
29297 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29298})(powerbi || (powerbi = {}));
29299/*
29300 * Power BI Visualizations
29301 *
29302 * Copyright (c) Microsoft Corporation
29303 * All rights reserved.
29304 * MIT License
29305 *
29306 * Permission is hereby granted, free of charge, to any person obtaining a copy
29307 * of this software and associated documentation files (the ""Software""), to deal
29308 * in the Software without restriction, including without limitation the rights
29309 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29310 * copies of the Software, and to permit persons to whom the Software is
29311 * furnished to do so, subject to the following conditions:
29312 *
29313 * The above copyright notice and this permission notice shall be included in
29314 * all copies or substantial portions of the Software.
29315 *
29316 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29317 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29318 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29319 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29320 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29321 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29322 * THE SOFTWARE.
29323 */
29324var powerbi;
29325(function (powerbi) {
29326 var visuals;
29327 (function (visuals) {
29328 visuals.treemapCapabilities = {
29329 dataRoles: [
29330 {
29331 name: 'Group',
29332 kind: powerbi.VisualDataRoleKind.Grouping,
29333 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Group'),
29334 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GroupTreemapDescription')
29335 }, {
29336 name: 'Details',
29337 kind: powerbi.VisualDataRoleKind.Grouping,
29338 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Details'),
29339 }, {
29340 name: 'Values',
29341 kind: powerbi.VisualDataRoleKind.Measure,
29342 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Values'),
29343 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_ValuesDescription'),
29344 requiredTypes: [{ numeric: true }, { integer: true }],
29345 }, {
29346 name: 'Gradient',
29347 kind: powerbi.VisualDataRoleKind.Measure,
29348 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Gradient'),
29349 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_GradientDescription'),
29350 requiredTypes: [{ numeric: true }, { integer: true }],
29351 }
29352 ],
29353 objects: {
29354 general: {
29355 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
29356 properties: {
29357 formatString: visuals.StandardObjectProperties.formatString,
29358 },
29359 },
29360 legend: {
29361 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
29362 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
29363 properties: {
29364 show: visuals.StandardObjectProperties.show,
29365 position: visuals.StandardObjectProperties.legendPosition,
29366 showTitle: visuals.StandardObjectProperties.showLegendTitle,
29367 titleText: visuals.StandardObjectProperties.legendTitle,
29368 labelColor: visuals.StandardObjectProperties.labelColor,
29369 fontSize: visuals.StandardObjectProperties.fontSize,
29370 }
29371 },
29372 dataPoint: {
29373 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
29374 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
29375 properties: {
29376 fill: {
29377 type: { fill: { solid: { color: true } } }
29378 },
29379 fillRule: {
29380 displayName: powerbi.data.createDisplayNameGetter('Visual_Gradient'),
29381 type: { fillRule: {} },
29382 rule: {
29383 inputRole: 'Gradient',
29384 output: {
29385 property: 'fill',
29386 selector: ['Group'],
29387 }
29388 }
29389 }
29390 }
29391 },
29392 labels: {
29393 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
29394 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
29395 properties: {
29396 show: visuals.StandardObjectProperties.show,
29397 color: visuals.StandardObjectProperties.dataColor,
29398 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
29399 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
29400 }
29401 },
29402 categoryLabels: {
29403 displayName: powerbi.data.createDisplayNameGetter('Visual_CategoryLabels'),
29404 description: powerbi.data.createDisplayNameGetter('Visual_CategoryLabelsDescription'),
29405 properties: {
29406 show: visuals.StandardObjectProperties.show,
29407 },
29408 },
29409 },
29410 dataViewMappings: [{
29411 conditions: [
29412 { 'Group': { max: 1 }, 'Details': { max: 0 }, 'Gradient': { max: 1 } },
29413 { 'Group': { max: 1 }, 'Details': { min: 1, max: 1 }, 'Values': { max: 1 }, 'Gradient': { max: 0 } }
29414 ],
29415 categorical: {
29416 categories: {
29417 for: { in: 'Group' },
29418 dataReductionAlgorithm: { top: {} }
29419 },
29420 values: {
29421 group: {
29422 by: 'Details',
29423 select: [{ bind: { to: 'Values' } }, { bind: { to: 'Gradient' } }],
29424 dataReductionAlgorithm: { top: {} }
29425 }
29426 },
29427 rowCount: { preferred: { min: 2 } }
29428 }
29429 }],
29430 supportsHighlight: true,
29431 sorting: {
29432 custom: {},
29433 implicit: {
29434 clauses: [{ role: 'Values', direction: 2 /* Descending */ }]
29435 },
29436 },
29437 drilldown: {
29438 roles: ['Group']
29439 },
29440 };
29441 visuals.treemapProps = {
29442 general: {
29443 formatString: { objectName: 'general', propertyName: 'formatString' },
29444 },
29445 dataPoint: {
29446 fill: { objectName: 'dataPoint', propertyName: 'fill' },
29447 },
29448 legend: {
29449 show: { objectName: 'legend', propertyName: 'show' },
29450 position: { objectName: 'legend', propertyName: 'position' },
29451 showTitle: { objectName: 'legend', propertyName: 'showTitle' },
29452 titleText: { objectName: 'legend', propertyName: 'titleText' },
29453 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
29454 },
29455 labels: {
29456 show: { objectName: 'labels', propertyName: 'show' },
29457 color: { objectName: 'labels', propertyName: 'color' },
29458 labelDisplayUnits: { objectName: 'labels', propertyName: 'labelDisplayUnits' },
29459 labelPrecision: { objectName: 'labels', propertyName: 'labelPrecision' },
29460 },
29461 categoryLabels: {
29462 show: { objectName: 'categoryLabels', propertyName: 'show' },
29463 },
29464 };
29465 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29466})(powerbi || (powerbi = {}));
29467/*
29468 * Power BI Visualizations
29469 *
29470 * Copyright (c) Microsoft Corporation
29471 * All rights reserved.
29472 * MIT License
29473 *
29474 * Permission is hereby granted, free of charge, to any person obtaining a copy
29475 * of this software and associated documentation files (the ""Software""), to deal
29476 * in the Software without restriction, including without limitation the rights
29477 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29478 * copies of the Software, and to permit persons to whom the Software is
29479 * furnished to do so, subject to the following conditions:
29480 *
29481 * The above copyright notice and this permission notice shall be included in
29482 * all copies or substantial portions of the Software.
29483 *
29484 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29485 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29486 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29487 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29488 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29489 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29490 * THE SOFTWARE.
29491 */
29492var powerbi;
29493(function (powerbi) {
29494 var visuals;
29495 (function (visuals) {
29496 visuals.cardCapabilities = {
29497 dataRoles: [
29498 {
29499 name: 'Values',
29500 kind: powerbi.VisualDataRoleKind.Measure,
29501 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Fields'),
29502 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_FieldsDescription'),
29503 }
29504 ],
29505 objects: {
29506 general: {
29507 properties: {
29508 formatString: visuals.StandardObjectProperties.formatString,
29509 },
29510 },
29511 labels: {
29512 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointLabel'),
29513 properties: {
29514 color: visuals.StandardObjectProperties.dataColor,
29515 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
29516 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
29517 // NOTE: Consider adding a ValueType for fontSize.
29518 fontSize: visuals.StandardObjectProperties.fontSize,
29519 },
29520 },
29521 categoryLabels: {
29522 displayName: powerbi.data.createDisplayNameGetter('Visual_CategoryLabel'),
29523 properties: {
29524 show: visuals.StandardObjectProperties.show,
29525 color: visuals.StandardObjectProperties.dataColor,
29526 // NOTE: Consider adding a ValueType for fontSize.
29527 fontSize: visuals.StandardObjectProperties.fontSize,
29528 },
29529 },
29530 wordWrap: {
29531 displayName: powerbi.data.createDisplayNameGetter('Visual_WordWrap'),
29532 properties: {
29533 show: visuals.StandardObjectProperties.show,
29534 },
29535 },
29536 },
29537 dataViewMappings: [{
29538 conditions: [
29539 { 'Values': { max: 1 } }
29540 ],
29541 single: { role: "Values" }
29542 }],
29543 suppressDefaultTitle: true,
29544 supportsSelection: false,
29545 };
29546 visuals.cardProps = {
29547 categoryLabels: {
29548 show: { objectName: 'categoryLabels', propertyName: 'show' },
29549 color: { objectName: 'categoryLabels', propertyName: 'color' },
29550 fontSize: { objectName: 'categoryLabels', propertyName: 'fontSize' },
29551 },
29552 labels: {
29553 color: { objectName: 'labels', propertyName: 'color' },
29554 labelPrecision: { objectName: 'labels', propertyName: 'labelPrecision' },
29555 labelDisplayUnits: { objectName: 'labels', propertyName: 'labelDisplayUnits' },
29556 fontSize: { objectName: 'labels', propertyName: 'fontSize' },
29557 },
29558 wordWrap: {
29559 show: { objectName: 'wordWrap', propertyName: 'show' },
29560 },
29561 };
29562 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29563})(powerbi || (powerbi = {}));
29564/*
29565 * Power BI Visualizations
29566 *
29567 * Copyright (c) Microsoft Corporation
29568 * All rights reserved.
29569 * MIT License
29570 *
29571 * Permission is hereby granted, free of charge, to any person obtaining a copy
29572 * of this software and associated documentation files (the ""Software""), to deal
29573 * in the Software without restriction, including without limitation the rights
29574 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29575 * copies of the Software, and to permit persons to whom the Software is
29576 * furnished to do so, subject to the following conditions:
29577 *
29578 * The above copyright notice and this permission notice shall be included in
29579 * all copies or substantial portions of the Software.
29580 *
29581 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29582 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29583 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29584 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29585 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29586 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29587 * THE SOFTWARE.
29588 */
29589var powerbi;
29590(function (powerbi) {
29591 var visuals;
29592 (function (visuals) {
29593 visuals.waterfallChartCapabilities = {
29594 dataRoles: [
29595 {
29596 name: 'Category',
29597 kind: powerbi.VisualDataRoleKind.Grouping,
29598 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Category'),
29599 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_CategoryWaterfallDescription')
29600 }, {
29601 name: 'Y',
29602 kind: powerbi.VisualDataRoleKind.Measure,
29603 requiredTypes: [{ numeric: true }, { integer: true }],
29604 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_Y'),
29605 }
29606 ],
29607 objects: {
29608 general: {
29609 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
29610 properties: {
29611 formatString: visuals.StandardObjectProperties.formatString,
29612 },
29613 },
29614 legend: {
29615 displayName: powerbi.data.createDisplayNameGetter('Visual_Legend'),
29616 description: powerbi.data.createDisplayNameGetter('Visual_LegendDescription'),
29617 properties: {
29618 show: visuals.StandardObjectProperties.show,
29619 position: visuals.StandardObjectProperties.legendPosition,
29620 showTitle: visuals.StandardObjectProperties.showLegendTitle,
29621 titleText: $.extend({}, visuals.StandardObjectProperties.legendTitle, {
29622 suppressFormatPainterCopy: true,
29623 }),
29624 labelColor: visuals.StandardObjectProperties.labelColor,
29625 fontSize: visuals.StandardObjectProperties.fontSize,
29626 }
29627 },
29628 labels: {
29629 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabels'),
29630 description: powerbi.data.createDisplayNameGetter('Visual_DataPointsLabelsDescription'),
29631 properties: {
29632 show: visuals.StandardObjectProperties.show,
29633 color: visuals.StandardObjectProperties.dataColor,
29634 labelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
29635 labelPrecision: $.extend({}, visuals.StandardObjectProperties.labelPrecision, {
29636 suppressFormatPainterCopy: true,
29637 }),
29638 fontSize: visuals.StandardObjectProperties.fontSize,
29639 }
29640 },
29641 sentimentColors: {
29642 displayName: powerbi.data.createDisplayNameGetter('Waterfall_SentimentColors'),
29643 properties: {
29644 increaseFill: {
29645 displayName: powerbi.data.createDisplayNameGetter('Waterfall_IncreaseLabel'),
29646 type: { fill: { solid: { color: true } } }
29647 },
29648 decreaseFill: {
29649 displayName: powerbi.data.createDisplayNameGetter('Waterfall_DecreaseLabel'),
29650 type: { fill: { solid: { color: true } } }
29651 },
29652 totalFill: {
29653 displayName: powerbi.data.createDisplayNameGetter('Waterfall_TotalLabel'),
29654 type: { fill: { solid: { color: true } } }
29655 }
29656 },
29657 },
29658 categoryAxis: {
29659 displayName: powerbi.data.createDisplayNameGetter('Visual_XAxis'),
29660 properties: {
29661 show: visuals.StandardObjectProperties.show,
29662 showAxisTitle: {
29663 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
29664 description: powerbi.data.createDisplayNameGetter('Visual_Axis_XTitleDescription'),
29665 type: { bool: true }
29666 },
29667 axisStyle: visuals.StandardObjectProperties.axisStyle,
29668 labelColor: visuals.StandardObjectProperties.labelColor,
29669 }
29670 },
29671 valueAxis: {
29672 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis'),
29673 properties: {
29674 show: visuals.StandardObjectProperties.show,
29675 position: visuals.StandardObjectProperties.yAxisPosition,
29676 start: visuals.StandardObjectProperties.axisStart,
29677 end: visuals.StandardObjectProperties.axisEnd,
29678 showAxisTitle: {
29679 displayName: powerbi.data.createDisplayNameGetter('Visual_Axis_Title'),
29680 description: powerbi.data.createDisplayNameGetter('Visual_Axis_YTitleDescription'),
29681 type: { bool: true }
29682 },
29683 axisStyle: visuals.StandardObjectProperties.axisStyle,
29684 labelColor: visuals.StandardObjectProperties.labelColor,
29685 labelDisplayUnits: visuals.StandardObjectProperties.labelDisplayUnits,
29686 labelPrecision: visuals.StandardObjectProperties.labelPrecision,
29687 }
29688 },
29689 y1AxisReferenceLine: {
29690 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line'),
29691 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Description'),
29692 properties: {
29693 show: visuals.StandardObjectProperties.show,
29694 value: {
29695 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value'),
29696 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Value_Description'),
29697 type: { numeric: true }
29698 },
29699 lineColor: visuals.StandardObjectProperties.lineColor,
29700 transparency: {
29701 displayName: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency'),
29702 description: powerbi.data.createDisplayNameGetter('Visual_Reference_Line_Transparency_Description'),
29703 type: { numeric: true }
29704 },
29705 style: visuals.StandardObjectProperties.referenceLineStyle,
29706 position: visuals.StandardObjectProperties.referenceLinePosition,
29707 dataLabelShow: visuals.StandardObjectProperties.dataLabelShow,
29708 dataLabelColor: visuals.StandardObjectProperties.dataLabelColor,
29709 dataLabelDecimalPoints: visuals.StandardObjectProperties.dataLabelDecimalPoints,
29710 dataLabelHorizontalPosition: visuals.StandardObjectProperties.dataLabelHorizontalPosition,
29711 dataLabelVerticalPosition: visuals.StandardObjectProperties.dataLabelVerticalPosition,
29712 dataLabelDisplayUnits: visuals.StandardObjectProperties.dataLabelDisplayUnits,
29713 },
29714 },
29715 plotArea: {
29716 displayName: powerbi.data.createDisplayNameGetter('Visual_Plot'),
29717 properties: {
29718 transparency: visuals.StandardObjectProperties.transparency,
29719 image: visuals.StandardObjectProperties.image,
29720 },
29721 },
29722 },
29723 dataViewMappings: [{
29724 conditions: [
29725 { 'Category': { max: 1 }, 'Y': { max: 1 } },
29726 ],
29727 categorical: {
29728 categories: {
29729 for: { in: 'Category' },
29730 dataReductionAlgorithm: { top: {} }
29731 },
29732 values: {
29733 select: [{ bind: { to: 'Y' } }]
29734 },
29735 },
29736 }],
29737 drilldown: {
29738 roles: ['Category']
29739 },
29740 };
29741 visuals.waterfallChartProps = {
29742 general: {
29743 formatString: { objectName: 'general', propertyName: 'formatString' },
29744 },
29745 sentimentColors: {
29746 increaseFill: { objectName: 'sentimentColors', propertyName: 'increaseFill' },
29747 decreaseFill: { objectName: 'sentimentColors', propertyName: 'decreaseFill' },
29748 totalFill: { objectName: 'sentimentColors', propertyName: 'totalFill' },
29749 },
29750 legend: {
29751 labelColor: { objectName: 'legend', propertyName: 'labelColor' },
29752 },
29753 };
29754 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29755})(powerbi || (powerbi = {}));
29756/*
29757 * Power BI Visualizations
29758 *
29759 * Copyright (c) Microsoft Corporation
29760 * All rights reserved.
29761 * MIT License
29762 *
29763 * Permission is hereby granted, free of charge, to any person obtaining a copy
29764 * of this software and associated documentation files (the ""Software""), to deal
29765 * in the Software without restriction, including without limitation the rights
29766 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29767 * copies of the Software, and to permit persons to whom the Software is
29768 * furnished to do so, subject to the following conditions:
29769 *
29770 * The above copyright notice and this permission notice shall be included in
29771 * all copies or substantial portions of the Software.
29772 *
29773 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29774 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29775 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29776 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29777 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29778 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29779 * THE SOFTWARE.
29780 */
29781var powerbi;
29782(function (powerbi) {
29783 var visuals;
29784 (function (visuals) {
29785 visuals.KPIStatusWithHistoryCapabilities = {
29786 dataRoles: [
29787 {
29788 name: 'Indicator',
29789 kind: powerbi.VisualDataRoleKind.Measure,
29790 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Indicator'),
29791 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_IndicatorDescription')
29792 }, {
29793 name: 'TrendLine',
29794 kind: powerbi.VisualDataRoleKind.Grouping,
29795 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_TrendLine'),
29796 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Trendline_Description')
29797 }, {
29798 name: 'Goal',
29799 kind: powerbi.VisualDataRoleKind.Measure,
29800 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Goal'),
29801 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_GoalDescription')
29802 }],
29803 dataViewMappings: [{
29804 conditions: [
29805 { 'Indicator': { max: 1 }, 'TrendLine': { max: 1 }, 'Goal': { max: 2 } },
29806 ],
29807 categorical: {
29808 categories: {
29809 for: { in: 'TrendLine' },
29810 dataReductionAlgorithm: { top: {} }
29811 },
29812 values: {
29813 select: [
29814 { bind: { to: 'Indicator' } },
29815 { bind: { to: 'Goal' } }
29816 ]
29817 }
29818 },
29819 }],
29820 objects: {
29821 general: {
29822 properties: {
29823 formatString: visuals.StandardObjectProperties.formatString,
29824 },
29825 },
29826 indicator: {
29827 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Indicator'),
29828 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_IndicatorDescription'),
29829 properties: {
29830 indicatorDisplayUnits: {
29831 displayName: powerbi.data.createDisplayNameGetter('Visual_DisplayUnits'),
29832 description: powerbi.data.createDisplayNameGetter('Visual_DisplayUnitsDescription'),
29833 type: { formatting: { labelDisplayUnits: true } }
29834 },
29835 indicatorPrecision: {
29836 displayName: powerbi.data.createDisplayNameGetter('Visual_Precision'),
29837 description: powerbi.data.createDisplayNameGetter('Visual_PrecisionDescription'),
29838 placeHolderText: powerbi.data.createDisplayNameGetter('Visual_Precision_Auto'),
29839 type: { numeric: true }
29840 },
29841 kpiFormat: {
29842 displayName: powerbi.data.createDisplayNameGetter('TaskPane_Format'),
29843 type: { text: true },
29844 }
29845 }
29846 },
29847 trendline: {
29848 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_TrendLine'),
29849 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Trendline_Description'),
29850 properties: {
29851 show: visuals.StandardObjectProperties.show,
29852 }
29853 },
29854 goals: {
29855 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Goals'),
29856 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Goals'),
29857 properties: {
29858 showGoal: {
29859 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Show_Goal'),
29860 type: { bool: true }
29861 },
29862 showDistance: {
29863 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Show_Distance'),
29864 type: { bool: true }
29865 },
29866 }
29867 },
29868 status: {
29869 displayName: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Status'),
29870 description: powerbi.data.createDisplayNameGetter('Role_DisplayName_KPI_Status'),
29871 properties: {
29872 direction: {
29873 displayName: powerbi.data.createDisplayNameGetter('Visual_KPI_Direction'),
29874 type: { enumeration: visuals.kpiDirection.type }
29875 }
29876 }
29877 }
29878 },
29879 };
29880 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29881})(powerbi || (powerbi = {}));
29882/*
29883 * Power BI Visualizations
29884 *
29885 * Copyright (c) Microsoft Corporation
29886 * All rights reserved.
29887 * MIT License
29888 *
29889 * Permission is hereby granted, free of charge, to any person obtaining a copy
29890 * of this software and associated documentation files (the ""Software""), to deal
29891 * in the Software without restriction, including without limitation the rights
29892 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29893 * copies of the Software, and to permit persons to whom the Software is
29894 * furnished to do so, subject to the following conditions:
29895 *
29896 * The above copyright notice and this permission notice shall be included in
29897 * all copies or substantial portions of the Software.
29898 *
29899 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29900 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29901 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29902 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29903 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29904 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29905 * THE SOFTWARE.
29906 */
29907var powerbi;
29908(function (powerbi) {
29909 var visuals;
29910 (function (visuals) {
29911 var capabilities;
29912 (function (capabilities) {
29913 // This file registers the built-in capabilities
29914 // Please use this file to register the capabilities in the plugins.ts/pluginsNotForOSS.ts
29915 capabilities.animatedNumber = powerbi.visuals.animatedNumberCapabilities;
29916 capabilities.areaChart = powerbi.visuals.lineChartCapabilities;
29917 capabilities.barChart = powerbi.visuals.getColumnChartCapabilities(true);
29918 capabilities.card = powerbi.visuals.cardCapabilities;
29919 capabilities.multiRowCard = powerbi.visuals.multiRowCardCapabilities;
29920 capabilities.clusteredBarChart = powerbi.visuals.getColumnChartCapabilities(true);
29921 capabilities.clusteredColumnChart = powerbi.visuals.getColumnChartCapabilities();
29922 capabilities.columnChart = powerbi.visuals.getColumnChartCapabilities();
29923 capabilities.comboChart = powerbi.visuals.comboChartCapabilities;
29924 capabilities.dataDotChart = powerbi.visuals.dataDotChartCapabilities;
29925 capabilities.dataDotClusteredColumnComboChart = powerbi.visuals.comboChartCapabilities;
29926 capabilities.dataDotStackedColumnComboChart = powerbi.visuals.comboChartCapabilities;
29927 capabilities.donutChart = powerbi.visuals.donutChartCapabilities;
29928 capabilities.funnel = powerbi.visuals.funnelChartCapabilities;
29929 capabilities.gauge = powerbi.visuals.gaugeCapabilities;
29930 capabilities.hundredPercentStackedBarChart = powerbi.visuals.getColumnChartCapabilities(true);
29931 capabilities.hundredPercentStackedColumnChart = powerbi.visuals.getColumnChartCapabilities();
29932 capabilities.image = powerbi.visuals.imageVisualCapabilities;
29933 capabilities.lineChart = powerbi.visuals.lineChartCapabilities;
29934 capabilities.lineStackedColumnComboChart = powerbi.visuals.comboChartCapabilities;
29935 capabilities.lineClusteredColumnComboChart = powerbi.visuals.comboChartCapabilities;
29936 capabilities.map = powerbi.visuals.mapCapabilities;
29937 capabilities.filledMap = powerbi.visuals.filledMapCapabilities;
29938 capabilities.treemap = powerbi.visuals.treemapCapabilities;
29939 capabilities.pieChart = powerbi.visuals.donutChartCapabilities;
29940 capabilities.scatterChart = powerbi.visuals.scatterChartCapabilities;
29941 capabilities.table = powerbi.visuals.tableCapabilities;
29942 capabilities.matrix = powerbi.visuals.matrixCapabilities;
29943 capabilities.slicer = powerbi.visuals.slicerCapabilities;
29944 capabilities.textbox = powerbi.visuals.textboxCapabilities;
29945 capabilities.waterfallChart = powerbi.visuals.waterfallChartCapabilities;
29946 capabilities.cheerMeter = powerbi.visuals.cheerMeterCapabilities;
29947 capabilities.scriptVisual = powerbi.visuals.scriptVisualCapabilities;
29948 capabilities.kpi = powerbi.visuals.KPIStatusWithHistoryCapabilities;
29949 })(capabilities = visuals.capabilities || (visuals.capabilities = {}));
29950 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
29951})(powerbi || (powerbi = {}));
29952/*
29953 * Power BI Visualizations
29954 *
29955 * Copyright (c) Microsoft Corporation
29956 * All rights reserved.
29957 * MIT License
29958 *
29959 * Permission is hereby granted, free of charge, to any person obtaining a copy
29960 * of this software and associated documentation files (the ""Software""), to deal
29961 * in the Software without restriction, including without limitation the rights
29962 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29963 * copies of the Software, and to permit persons to whom the Software is
29964 * furnished to do so, subject to the following conditions:
29965 *
29966 * The above copyright notice and this permission notice shall be included in
29967 * all copies or substantial portions of the Software.
29968 *
29969 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29970 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29971 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29972 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29973 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29974 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29975 * THE SOFTWARE.
29976 */
29977var powerbi;
29978(function (powerbi) {
29979 var visuals;
29980 (function (visuals) {
29981 var ColumnChartWebBehavior = (function () {
29982 function ColumnChartWebBehavior() {
29983 }
29984 ColumnChartWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
29985 this.options = options;
29986 var eventGroup = options.eventGroup;
29987 eventGroup.on('click', function () {
29988 var d = ColumnChartWebBehavior.getDatumForLastInputEvent();
29989 selectionHandler.handleSelection(d, d3.event.ctrlKey);
29990 });
29991 eventGroup.on('contextmenu', function () {
29992 if (d3.event.ctrlKey)
29993 return;
29994 d3.event.preventDefault();
29995 var d = ColumnChartWebBehavior.getDatumForLastInputEvent();
29996 var position = visuals.InteractivityUtils.getPositionOfLastInputEvent();
29997 selectionHandler.handleContextMenu(d, position);
29998 });
29999 };
30000 ColumnChartWebBehavior.prototype.renderSelection = function (hasSelection) {
30001 var options = this.options;
30002 options.bars.style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, !d.highlight && hasSelection, !d.selected && options.hasHighlights); });
30003 };
30004 ColumnChartWebBehavior.getDatumForLastInputEvent = function () {
30005 var target = d3.event.target;
30006 return d3.select(target).datum();
30007 };
30008 return ColumnChartWebBehavior;
30009 }());
30010 visuals.ColumnChartWebBehavior = ColumnChartWebBehavior;
30011 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30012})(powerbi || (powerbi = {}));
30013/*
30014 * Power BI Visualizations
30015 *
30016 * Copyright (c) Microsoft Corporation
30017 * All rights reserved.
30018 * MIT License
30019 *
30020 * Permission is hereby granted, free of charge, to any person obtaining a copy
30021 * of this software and associated documentation files (the ""Software""), to deal
30022 * in the Software without restriction, including without limitation the rights
30023 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30024 * copies of the Software, and to permit persons to whom the Software is
30025 * furnished to do so, subject to the following conditions:
30026 *
30027 * The above copyright notice and this permission notice shall be included in
30028 * all copies or substantial portions of the Software.
30029 *
30030 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30031 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30032 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30033 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30034 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30035 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30036 * THE SOFTWARE.
30037 */
30038var powerbi;
30039(function (powerbi) {
30040 var visuals;
30041 (function (visuals) {
30042 var DataDotChartWebBehavior = (function () {
30043 function DataDotChartWebBehavior() {
30044 }
30045 DataDotChartWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30046 var dots = this.dots = options.dots;
30047 var dotLabels = options.dotLabels;
30048 visuals.InteractivityUtils.registerStandardInteractivityHandlers(dots, selectionHandler);
30049 if (dotLabels) {
30050 visuals.InteractivityUtils.registerStandardInteractivityHandlers(dotLabels, selectionHandler);
30051 }
30052 };
30053 DataDotChartWebBehavior.prototype.renderSelection = function (hasSelection) {
30054 this.dots.style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, false); });
30055 };
30056 return DataDotChartWebBehavior;
30057 }());
30058 visuals.DataDotChartWebBehavior = DataDotChartWebBehavior;
30059 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30060})(powerbi || (powerbi = {}));
30061/*
30062 * Power BI Visualizations
30063 *
30064 * Copyright (c) Microsoft Corporation
30065 * All rights reserved.
30066 * MIT License
30067 *
30068 * Permission is hereby granted, free of charge, to any person obtaining a copy
30069 * of this software and associated documentation files (the ""Software""), to deal
30070 * in the Software without restriction, including without limitation the rights
30071 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30072 * copies of the Software, and to permit persons to whom the Software is
30073 * furnished to do so, subject to the following conditions:
30074 *
30075 * The above copyright notice and this permission notice shall be included in
30076 * all copies or substantial portions of the Software.
30077 *
30078 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30079 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30080 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30081 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30082 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30083 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30084 * THE SOFTWARE.
30085 */
30086var powerbi;
30087(function (powerbi) {
30088 var visuals;
30089 (function (visuals) {
30090 var DonutChartWebBehavior = (function () {
30091 function DonutChartWebBehavior() {
30092 }
30093 DonutChartWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30094 var slices = this.slices = options.slices;
30095 var highlightSlices = this.highlightSlices = options.highlightSlices;
30096 var clearCatcher = options.clearCatcher;
30097 this.hasHighlights = options.hasHighlights;
30098 var clickHandler = function (d) {
30099 selectionHandler.handleSelection(d.data, d3.event.ctrlKey);
30100 };
30101 var contextMenuHandler = function (d) {
30102 if (d3.event.ctrlKey)
30103 return;
30104 var position = visuals.InteractivityUtils.getPositionOfLastInputEvent();
30105 selectionHandler.handleContextMenu(d.data, position);
30106 d3.event.preventDefault();
30107 };
30108 slices.on('click', clickHandler);
30109 slices.on('contextmenu', contextMenuHandler);
30110 highlightSlices.on('click', clickHandler);
30111 highlightSlices.on('contextmenu', contextMenuHandler);
30112 clearCatcher.on('click', function () {
30113 selectionHandler.handleClearSelection();
30114 });
30115 };
30116 DonutChartWebBehavior.prototype.renderSelection = function (hasSelection) {
30117 var hasHighlights = this.hasHighlights;
30118 this.slices.style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, hasHighlights && !d.data.selected); });
30119 this.highlightSlices.style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, true, false, hasHighlights); });
30120 };
30121 return DonutChartWebBehavior;
30122 }());
30123 visuals.DonutChartWebBehavior = DonutChartWebBehavior;
30124 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30125})(powerbi || (powerbi = {}));
30126/*
30127 * Power BI Visualizations
30128 *
30129 * Copyright (c) Microsoft Corporation
30130 * All rights reserved.
30131 * MIT License
30132 *
30133 * Permission is hereby granted, free of charge, to any person obtaining a copy
30134 * of this software and associated documentation files (the ""Software""), to deal
30135 * in the Software without restriction, including without limitation the rights
30136 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30137 * copies of the Software, and to permit persons to whom the Software is
30138 * furnished to do so, subject to the following conditions:
30139 *
30140 * The above copyright notice and this permission notice shall be included in
30141 * all copies or substantial portions of the Software.
30142 *
30143 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30144 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30145 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30146 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30147 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30148 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30149 * THE SOFTWARE.
30150 */
30151var powerbi;
30152(function (powerbi) {
30153 var visuals;
30154 (function (visuals) {
30155 var FunnelWebBehavior = (function () {
30156 function FunnelWebBehavior() {
30157 }
30158 FunnelWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30159 var bars = this.bars = options.bars;
30160 var interactors = this.interactors = options.interactors;
30161 var clearCatcher = options.clearCatcher;
30162 this.hasHighlights = options.hasHighlights;
30163 visuals.InteractivityUtils.registerStandardInteractivityHandlers(bars, selectionHandler);
30164 visuals.InteractivityUtils.registerStandardInteractivityHandlers(interactors, selectionHandler);
30165 clearCatcher.on('click', function () {
30166 selectionHandler.handleClearSelection();
30167 });
30168 };
30169 FunnelWebBehavior.prototype.renderSelection = function (hasSelection) {
30170 var hasHighlights = this.hasHighlights;
30171 this.bars.style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, !d.highlight && hasSelection, !d.selected && hasHighlights); });
30172 };
30173 return FunnelWebBehavior;
30174 }());
30175 visuals.FunnelWebBehavior = FunnelWebBehavior;
30176 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30177})(powerbi || (powerbi = {}));
30178/*
30179 * Power BI Visualizations
30180 *
30181 * Copyright (c) Microsoft Corporation
30182 * All rights reserved.
30183 * MIT License
30184 *
30185 * Permission is hereby granted, free of charge, to any person obtaining a copy
30186 * of this software and associated documentation files (the ""Software""), to deal
30187 * in the Software without restriction, including without limitation the rights
30188 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30189 * copies of the Software, and to permit persons to whom the Software is
30190 * furnished to do so, subject to the following conditions:
30191 *
30192 * The above copyright notice and this permission notice shall be included in
30193 * all copies or substantial portions of the Software.
30194 *
30195 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30196 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30197 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30198 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30199 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30200 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30201 * THE SOFTWARE.
30202 */
30203/*
30204 * Power BI Visualizations
30205 *
30206 * Copyright (c) Microsoft Corporation
30207 * All rights reserved.
30208 * MIT License
30209 *
30210 * Permission is hereby granted, free of charge, to any person obtaining a copy
30211 * of this software and associated documentation files (the ""Software""), to deal
30212 * in the Software without restriction, including without limitation the rights
30213 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30214 * copies of the Software, and to permit persons to whom the Software is
30215 * furnished to do so, subject to the following conditions:
30216 *
30217 * The above copyright notice and this permission notice shall be included in
30218 * all copies or substantial portions of the Software.
30219 *
30220 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30221 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30222 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30223 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30224 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30225 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30226 * THE SOFTWARE.
30227 */
30228var powerbi;
30229(function (powerbi) {
30230 var visuals;
30231 (function (visuals) {
30232 var LineChartWebBehavior = (function () {
30233 function LineChartWebBehavior() {
30234 }
30235 LineChartWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30236 this.lines = options.lines;
30237 var interactivityLines = options.interactivityLines;
30238 var dots = this.dots = options.dots;
30239 var areas = this.areas = options.areas;
30240 var tooltipOverlay = this.tooltipOverlay = options.tooltipOverlay;
30241 visuals.InteractivityUtils.registerStandardInteractivityHandlers(interactivityLines, selectionHandler);
30242 visuals.InteractivityUtils.registerStandardInteractivityHandlers(dots, selectionHandler);
30243 if (areas) {
30244 visuals.InteractivityUtils.registerStandardInteractivityHandlers(areas, selectionHandler);
30245 }
30246 if (tooltipOverlay)
30247 tooltipOverlay.on('click', function () { return selectionHandler.handleClearSelection(); });
30248 };
30249 LineChartWebBehavior.prototype.renderSelection = function (hasSelection) {
30250 this.lines.style("stroke-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); });
30251 this.dots.style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); });
30252 if (this.areas)
30253 this.areas.style("fill-opacity", function (d) { return (hasSelection && !d.selected) ? visuals.LineChart.DimmedAreaFillOpacity : visuals.LineChart.AreaFillOpacity; });
30254 };
30255 return LineChartWebBehavior;
30256 }());
30257 visuals.LineChartWebBehavior = LineChartWebBehavior;
30258 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30259})(powerbi || (powerbi = {}));
30260/*
30261 * Power BI Visualizations
30262 *
30263 * Copyright (c) Microsoft Corporation
30264 * All rights reserved.
30265 * MIT License
30266 *
30267 * Permission is hereby granted, free of charge, to any person obtaining a copy
30268 * of this software and associated documentation files (the ""Software""), to deal
30269 * in the Software without restriction, including without limitation the rights
30270 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30271 * copies of the Software, and to permit persons to whom the Software is
30272 * furnished to do so, subject to the following conditions:
30273 *
30274 * The above copyright notice and this permission notice shall be included in
30275 * all copies or substantial portions of the Software.
30276 *
30277 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30278 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30279 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30280 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30281 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30282 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30283 * THE SOFTWARE.
30284 */
30285var powerbi;
30286(function (powerbi) {
30287 var visuals;
30288 (function (visuals) {
30289 var MapBehavior = (function () {
30290 function MapBehavior() {
30291 this.mapPointerEventsDisabled = false;
30292 this.mapPointerTimeoutSet = false;
30293 this.viewChangedSinceLastClearMouseDown = false;
30294 this.receivedZoomOrPanEvent = false;
30295 }
30296 MapBehavior.prototype.bindEvents = function (options, selectionHandler) {
30297 var _this = this;
30298 var bubbles = this.bubbles = options.bubbles;
30299 var slices = this.slices = options.slices;
30300 var shapes = this.shapes = options.shapes;
30301 var clearCatcher = options.clearCatcher;
30302 var clickHandler = function () {
30303 var target = d3.event.target;
30304 var d = d3.select(target).datum();
30305 if (bubbles)
30306 bubbles.style("pointer-events", "all");
30307 if (shapes)
30308 shapes.style("pointer-events", "all");
30309 selectionHandler.handleSelection(d, d3.event.ctrlKey);
30310 };
30311 if (!this.mapPointerEventsDisabled) {
30312 if (bubbles)
30313 bubbles.style("pointer-events", "all");
30314 if (slices)
30315 slices.style("pointer-events", "all");
30316 if (shapes)
30317 shapes.style("pointer-events", "all");
30318 }
30319 if (bubbles) {
30320 options.bubbleEventGroup.on('click', clickHandler);
30321 options.bubbleEventGroup.on('mousewheel', function () {
30322 if (!_this.mapPointerEventsDisabled)
30323 bubbles.style("pointer-events", "none");
30324 _this.mapPointerEventsDisabled = true;
30325 if (!_this.mapPointerTimeoutSet) {
30326 _this.mapPointerTimeoutSet = true;
30327 setTimeout(function () {
30328 if (bubbles)
30329 bubbles.style("pointer-events", "all");
30330 _this.mapPointerEventsDisabled = false;
30331 _this.mapPointerTimeoutSet = false;
30332 }, 200);
30333 }
30334 });
30335 visuals.InteractivityUtils.registerGroupContextMenuHandler(options.bubbleEventGroup, selectionHandler);
30336 }
30337 if (slices) {
30338 options.sliceEventGroup.on('click', function () {
30339 slices.style("pointer-events", "all");
30340 _this.mapPointerEventsDisabled = false;
30341 var target = d3.event.target;
30342 var d = d3.select(target).datum();
30343 selectionHandler.handleSelection(d.data, d3.event.ctrlKey);
30344 });
30345 options.sliceEventGroup.on('mousewheel', function () {
30346 if (!_this.mapPointerEventsDisabled)
30347 slices.style("pointer-events", "none");
30348 _this.mapPointerEventsDisabled = true;
30349 if (!_this.mapPointerTimeoutSet) {
30350 _this.mapPointerTimeoutSet = true;
30351 setTimeout(function () {
30352 if (slices)
30353 slices.style("pointer-events", "all");
30354 _this.mapPointerEventsDisabled = false;
30355 _this.mapPointerTimeoutSet = false;
30356 }, 200);
30357 }
30358 });
30359 options.sliceEventGroup.on('contextmenu', function () {
30360 if (d3.event.ctrlKey)
30361 return;
30362 d3.event.preventDefault();
30363 var position = visuals.InteractivityUtils.getPositionOfLastInputEvent();
30364 var target = d3.event.target;
30365 var d = d3.select(target).datum();
30366 selectionHandler.handleContextMenu(d.data, position);
30367 });
30368 }
30369 if (shapes) {
30370 options.shapeEventGroup.on('click', clickHandler);
30371 options.shapeEventGroup.on('mousewheel', function () {
30372 if (!_this.mapPointerEventsDisabled) {
30373 shapes.style("pointer-events", "none");
30374 }
30375 _this.mapPointerEventsDisabled = true;
30376 if (!_this.mapPointerTimeoutSet) {
30377 _this.mapPointerTimeoutSet = true;
30378 setTimeout(function () {
30379 if (shapes)
30380 shapes.style("pointer-events", "all");
30381 _this.mapPointerEventsDisabled = false;
30382 _this.mapPointerTimeoutSet = false;
30383 }, 200);
30384 }
30385 });
30386 visuals.InteractivityUtils.registerGroupContextMenuHandler(options.shapeEventGroup, selectionHandler);
30387 }
30388 clearCatcher.on('mouseup', function () {
30389 if (!_this.viewChangedSinceLastClearMouseDown) {
30390 selectionHandler.handleClearSelection();
30391 _this.receivedZoomOrPanEvent = true;
30392 }
30393 });
30394 clearCatcher.on('mousedown', function () {
30395 _this.viewChangedSinceLastClearMouseDown = false;
30396 });
30397 clearCatcher.on('mousewheel', function () {
30398 _this.receivedZoomOrPanEvent = true;
30399 });
30400 };
30401 MapBehavior.prototype.renderSelection = function (hasSelection) {
30402 if (this.bubbles) {
30403 this.bubbles
30404 .style({
30405 'fill-opacity': function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); },
30406 'stroke-opacity': function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); },
30407 });
30408 }
30409 if (this.slices) {
30410 this.slices
30411 .style({
30412 "fill-opacity": function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, false); },
30413 "stroke-opacity": function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, false); },
30414 });
30415 }
30416 if (this.shapes) {
30417 this.shapes
30418 .style({
30419 "fill-opacity": function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); },
30420 "stroke-opacity": function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); },
30421 });
30422 }
30423 };
30424 MapBehavior.prototype.viewChanged = function () {
30425 this.viewChangedSinceLastClearMouseDown = true;
30426 };
30427 MapBehavior.prototype.resetZoomPan = function () {
30428 this.receivedZoomOrPanEvent = false;
30429 };
30430 MapBehavior.prototype.hasReceivedZoomOrPanEvent = function () {
30431 return this.receivedZoomOrPanEvent;
30432 };
30433 return MapBehavior;
30434 }());
30435 visuals.MapBehavior = MapBehavior;
30436 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30437})(powerbi || (powerbi = {}));
30438/*
30439 * Power BI Visualizations
30440 *
30441 * Copyright (c) Microsoft Corporation
30442 * All rights reserved.
30443 * MIT License
30444 *
30445 * Permission is hereby granted, free of charge, to any person obtaining a copy
30446 * of this software and associated documentation files (the ""Software""), to deal
30447 * in the Software without restriction, including without limitation the rights
30448 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30449 * copies of the Software, and to permit persons to whom the Software is
30450 * furnished to do so, subject to the following conditions:
30451 *
30452 * The above copyright notice and this permission notice shall be included in
30453 * all copies or substantial portions of the Software.
30454 *
30455 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30456 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30457 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30458 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30459 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30460 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30461 * THE SOFTWARE.
30462 */
30463var powerbi;
30464(function (powerbi) {
30465 var visuals;
30466 (function (visuals) {
30467 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
30468 var ScatterChartWebBehavior = (function () {
30469 function ScatterChartWebBehavior() {
30470 }
30471 ScatterChartWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30472 var bubbles = this.bubbles = options.dataPointsSelection;
30473 var data = options.data;
30474 var eventGroup = options.eventGroup;
30475 // If we are removing play-axis, remove the trace lines as well
30476 // TODO: revisit this design, I think ideally this is done when rendering scatter.
30477 if (this.playOptions
30478 && this.playOptions.traceLineRenderer
30479 && (!options.playOptions || !options.playOptions.traceLineRenderer)) {
30480 this.playOptions.traceLineRenderer.remove();
30481 }
30482 this.playOptions = options.playOptions;
30483 this.shouldEnableFill = (!data.sizeRange || !data.sizeRange.min) && data.fillPoint;
30484 this.colorBorder = data.colorBorder;
30485 if (eventGroup) {
30486 visuals.InteractivityUtils.registerGroupInteractivityHandlers(eventGroup, selectionHandler);
30487 }
30488 else {
30489 visuals.InteractivityUtils.registerStandardInteractivityHandlers(bubbles, selectionHandler);
30490 }
30491 };
30492 ScatterChartWebBehavior.prototype.renderSelection = function (hasSelection) {
30493 var shouldEnableFill = this.shouldEnableFill;
30494 var colorBorder = this.colorBorder;
30495 this.bubbles.style("fill-opacity", function (d) { return visuals.ScatterChart.getMarkerFillOpacity(d.size != null, shouldEnableFill, hasSelection, d.selected); });
30496 this.bubbles.style("stroke-opacity", function (d) { return visuals.ScatterChart.getMarkerStrokeOpacity(d.size != null, colorBorder, hasSelection, d.selected); });
30497 if (this.playOptions && this.bubbles) {
30498 var selectedPoints = this.bubbles.filter(function (d) { return d.selected; }).data();
30499 var traceLineRenderer = this.playOptions.traceLineRenderer;
30500 if (selectedPoints && selectedPoints.length > 0 && traceLineRenderer != null) {
30501 traceLineRenderer.render(selectedPoints, true);
30502 }
30503 else {
30504 traceLineRenderer.remove();
30505 }
30506 }
30507 };
30508 return ScatterChartWebBehavior;
30509 }());
30510 visuals.ScatterChartWebBehavior = ScatterChartWebBehavior;
30511 var ScatterChartMobileBehavior = (function () {
30512 function ScatterChartMobileBehavior() {
30513 }
30514 ScatterChartMobileBehavior.prototype.bindEvents = function (options, selectionHandler) {
30515 this.setOptions(options);
30516 if (!options.visualInitOptions || !options.visualInitOptions.interactivity.isInteractiveLegend) {
30517 // Don't bind events if we are not in interactiveLegend mode
30518 // This case happend when on mobile we show the whole dashboard in still not on focus
30519 return;
30520 }
30521 this.makeDataPointsSelectable(options.dataPointsSelection);
30522 this.makeRootSelectable(options.root);
30523 this.makeDragable(options.root);
30524 this.disableDefaultTouchInteractions(options.root);
30525 this.selectRoot();
30526 };
30527 ScatterChartMobileBehavior.prototype.renderSelection = function (HasSelection) { };
30528 ScatterChartMobileBehavior.prototype.setSelectionHandler = function (selectionHandler) { };
30529 ScatterChartMobileBehavior.prototype.makeDataPointsSelectable = function () {
30530 var _this = this;
30531 var selection = [];
30532 for (var _i = 0; _i < arguments.length; _i++) {
30533 selection[_i - 0] = arguments[_i];
30534 }
30535 for (var i = 0, len = selection.length; i < len; i++) {
30536 var sel = selection[i];
30537 sel.on('click', function (d, i) {
30538 _this.select(i);
30539 });
30540 }
30541 };
30542 ScatterChartMobileBehavior.prototype.makeRootSelectable = function (selection) {
30543 var _this = this;
30544 selection.on('click', function (d, i) {
30545 _this.selectRoot();
30546 });
30547 };
30548 ScatterChartMobileBehavior.prototype.makeDragable = function () {
30549 var _this = this;
30550 var selection = [];
30551 for (var _i = 0; _i < arguments.length; _i++) {
30552 selection[_i - 0] = arguments[_i];
30553 }
30554 for (var i = 0, len = selection.length; i < len; i++) {
30555 var sel = selection[i];
30556 var drag = d3.behavior.drag()
30557 .on('drag', function (d) { _this.drag(0 /* Drag */); })
30558 .on('dragend', function (d) { _this.drag(1 /* DragEnd */); });
30559 sel.call(drag);
30560 }
30561 };
30562 ScatterChartMobileBehavior.prototype.disableDefaultTouchInteractions = function (selection) {
30563 selection.style('touch-action', 'none');
30564 };
30565 ScatterChartMobileBehavior.prototype.setOptions = function (options) {
30566 this.data = options.data;
30567 this.mainGraphicsContext = options.plotContext;
30568 this.xAxisProperties = options.xAxisProperties;
30569 this.yAxisProperties = options.yAxisProperties;
30570 this.host = options.host;
30571 };
30572 ScatterChartMobileBehavior.prototype.select = function (index) {
30573 this.selectDotByIndex(index);
30574 };
30575 ScatterChartMobileBehavior.prototype.selectRoot = function () {
30576 var marker = jsCommon.PerformanceUtil.create('selectRoot');
30577 this.onClick();
30578 marker.end();
30579 };
30580 ScatterChartMobileBehavior.prototype.drag = function (t) {
30581 switch (t) {
30582 case 0 /* Drag */:
30583 this.onDrag();
30584 break;
30585 case 1 /* DragEnd */:
30586 this.onClick();
30587 break;
30588 default:
30589 debug.assertFail('Unknown Drag Type');
30590 }
30591 };
30592 ScatterChartMobileBehavior.prototype.onDrag = function () {
30593 //find the current x and y position
30594 var xy = this.getMouseCoordinates();
30595 //move the crosshair to the current position
30596 this.moveCrosshairToXY(xy.x, xy.y);
30597 //update the style and the legend of the dots
30598 var selectedIndex = this.findClosestDotIndex(xy.x, xy.y);
30599 this.selectDot(selectedIndex);
30600 this.updateLegend(selectedIndex);
30601 };
30602 ScatterChartMobileBehavior.prototype.onClick = function () {
30603 //find the current x and y position
30604 var xy = this.getMouseCoordinates();
30605 var selectedIndex = this.findClosestDotIndex(xy.x, xy.y);
30606 if (selectedIndex !== -1)
30607 this.selectDotByIndex(selectedIndex);
30608 };
30609 ScatterChartMobileBehavior.prototype.getMouseCoordinates = function () {
30610 var mainGfxContext = this.mainGraphicsContext;
30611 // select (0,0) in cartesian coordinates
30612 var x = 0;
30613 var y = parseInt(mainGfxContext.attr('height'), 10);
30614 y = y || 0;
30615 try {
30616 var mouse = d3.mouse(mainGfxContext.node());
30617 x = mouse[0];
30618 y = mouse[1];
30619 }
30620 catch (e) {
30621 }
30622 return { x: x, y: y, };
30623 };
30624 ScatterChartMobileBehavior.prototype.selectDotByIndex = function (index) {
30625 this.selectDot(index);
30626 this.moveCrosshairToIndexDot(index);
30627 this.updateLegend(index);
30628 };
30629 ScatterChartMobileBehavior.prototype.selectDot = function (dotIndex) {
30630 var _this = this;
30631 var root = this.mainGraphicsContext;
30632 root.selectAll(ScatterChartMobileBehavior.ScatterChartCircleTagName + ScatterChartMobileBehavior.DotClassSelector).classed({ selected: false, notSelected: true });
30633 root.selectAll(ScatterChartMobileBehavior.ScatterChartCircleTagName + ScatterChartMobileBehavior.DotClassSelector).filter(function (d, i) {
30634 var dataPoints = _this.data.dataPoints;
30635 debug.assert(dataPoints.length > dotIndex, "dataPoints length:" + dataPoints.length + "is smaller than index:" + dotIndex);
30636 var currentPoint = dataPoints[dotIndex];
30637 return (d.x === currentPoint.x) && (d.y === currentPoint.y);
30638 }).classed({ selected: true, notSelected: false });
30639 };
30640 ScatterChartMobileBehavior.prototype.moveCrosshairToIndexDot = function (index) {
30641 var dataPoints = this.data.dataPoints;
30642 var root = this.mainGraphicsContext;
30643 debug.assert(dataPoints.length > index, "dataPoints length:" + dataPoints.length + "is smaller than index:" + index);
30644 var x = this.xAxisProperties.scale(dataPoints[index].x);
30645 var y = this.yAxisProperties.scale(dataPoints[index].y);
30646 if (this.crosshair == null) {
30647 var width = +root.attr('width');
30648 var height = +root.attr('height');
30649 this.crosshair = this.drawCrosshair(root, x, y, width, height);
30650 this.crosshairHorizontal = this.crosshair.select(ScatterChartMobileBehavior.Horizontal.selector);
30651 this.crosshairVertical = this.crosshair.select(ScatterChartMobileBehavior.Vertical.selector);
30652 }
30653 else {
30654 this.moveCrosshairToXY(x, y);
30655 }
30656 };
30657 ScatterChartMobileBehavior.prototype.moveCrosshairToXY = function (x, y) {
30658 this.crosshairHorizontal.attr({ y1: y, y2: y });
30659 this.crosshairVertical.attr({ x1: x, x2: x });
30660 };
30661 ScatterChartMobileBehavior.prototype.drawCrosshair = function (addTo, x, y, width, height) {
30662 var crosshair = addTo.append("g");
30663 crosshair.classed(ScatterChartMobileBehavior.CrosshairClassName, true);
30664 crosshair.append('line').classed(ScatterChartMobileBehavior.Horizontal.class, true).attr({ x1: 0, x2: width, y1: y, y2: y });
30665 crosshair.append('line').classed(ScatterChartMobileBehavior.Vertical.class, true).attr({ x1: x, x2: x, y1: height, y2: 0 });
30666 return crosshair;
30667 };
30668 ScatterChartMobileBehavior.prototype.findClosestDotIndex = function (x, y) {
30669 var selectedIndex = -1;
30670 var minDistance = Number.MAX_VALUE;
30671 var dataPoints = this.data.dataPoints;
30672 var xAxisPropertiesScale = this.xAxisProperties.scale;
30673 var yAxisPropertiesScale = this.yAxisProperties.scale;
30674 for (var i in dataPoints) {
30675 var currentPoint = dataPoints[i];
30676 var circleX = xAxisPropertiesScale(currentPoint.x);
30677 var circleY = yAxisPropertiesScale(currentPoint.y);
30678 var horizontalDistance = circleX - x;
30679 var verticalDistance = circleY - y;
30680 var distanceSqrd = (horizontalDistance * horizontalDistance) + (verticalDistance * verticalDistance);
30681 if (minDistance === Number.MAX_VALUE) {
30682 selectedIndex = i;
30683 minDistance = distanceSqrd;
30684 }
30685 else if (minDistance && minDistance > distanceSqrd) {
30686 selectedIndex = i;
30687 minDistance = distanceSqrd;
30688 }
30689 }
30690 return selectedIndex;
30691 };
30692 ScatterChartMobileBehavior.prototype.updateLegend = function (dotIndex) {
30693 if (this.lastDotIndex == null || this.lastDotIndex !== dotIndex) {
30694 var legendItems = this.createLegendDataPoints(dotIndex);
30695 this.host.updateLegend(legendItems);
30696 this.lastDotIndex = dotIndex;
30697 }
30698 };
30699 ScatterChartMobileBehavior.prototype.createLegendDataPoints = function (dotIndex) {
30700 var formatStringProp = visuals.scatterChartProps.general.formatString;
30701 var legendItems = [];
30702 var data = this.data;
30703 debug.assert(data.dataPoints.length > dotIndex, "dataPoints length:" + data.dataPoints.length + "is smaller than index:" + dotIndex);
30704 var point = data.dataPoints[dotIndex];
30705 //set the title of the legend to be the category or radius or group or blank
30706 var blank = visuals.valueFormatter.format(null);
30707 var title = blank;
30708 var legendData = data.legendData;
30709 debug.assertValue(legendData, "legendData");
30710 debug.assertValue(legendData.dataPoints, "legendData");
30711 var legendDataPoints = legendData.dataPoints;
30712 var category = point.formattedCategory.getValue();
30713 if (category !== blank) {
30714 title = category;
30715 }
30716 else if (point.radius.sizeMeasure != null) {
30717 title = visuals.valueFormatter.format(point.radius.sizeMeasure.source.groupName);
30718 }
30719 else if (legendDataPoints.length >= dotIndex && legendDataPoints[dotIndex].label !== blank) {
30720 title = legendDataPoints[dotIndex].label;
30721 }
30722 if (data.xCol != null) {
30723 legendItems.push({
30724 category: title,
30725 color: point.fill,
30726 identity: visuals.SelectionIdBuilder.builder().withMeasure(data.xCol.queryName).createSelectionId(),
30727 selected: point.selected,
30728 icon: visuals.LegendIcon.Box,
30729 label: visuals.valueFormatter.format(this.data.axesLabels.x),
30730 measure: visuals.valueFormatter.format(point.x, visuals.valueFormatter.getFormatString(data.xCol, formatStringProp)),
30731 iconOnlyOnLabel: true,
30732 });
30733 }
30734 if (data.yCol != null) {
30735 legendItems.push({
30736 category: title,
30737 color: point.fill,
30738 identity: visuals.SelectionIdBuilder.builder().withMeasure(data.yCol.queryName).createSelectionId(),
30739 selected: point.selected,
30740 icon: visuals.LegendIcon.Box,
30741 label: visuals.valueFormatter.format(data.axesLabels.y),
30742 measure: visuals.valueFormatter.format(point.y, visuals.valueFormatter.getFormatString(data.yCol, formatStringProp)),
30743 iconOnlyOnLabel: true,
30744 });
30745 }
30746 if (data.size != null) {
30747 legendItems.push({
30748 category: title,
30749 color: point.fill,
30750 identity: visuals.SelectionIdBuilder.builder().withMeasure(data.size.queryName).createSelectionId(),
30751 selected: point.selected,
30752 icon: visuals.LegendIcon.Box,
30753 label: visuals.valueFormatter.format(data.size.displayName),
30754 measure: visuals.valueFormatter.format(point.radius.sizeMeasure.values[point.radius.index], visuals.valueFormatter.getFormatString(data.size, formatStringProp)),
30755 iconOnlyOnLabel: true
30756 });
30757 }
30758 return { dataPoints: legendItems };
30759 };
30760 ScatterChartMobileBehavior.CrosshairClassName = 'crosshair';
30761 ScatterChartMobileBehavior.ScatterChartCircleTagName = 'circle';
30762 ScatterChartMobileBehavior.DotClassName = 'dot';
30763 ScatterChartMobileBehavior.DotClassSelector = '.' + ScatterChartMobileBehavior.DotClassName;
30764 ScatterChartMobileBehavior.Horizontal = createClassAndSelector('horizontal');
30765 ScatterChartMobileBehavior.Vertical = createClassAndSelector('vertical');
30766 return ScatterChartMobileBehavior;
30767 }());
30768 visuals.ScatterChartMobileBehavior = ScatterChartMobileBehavior;
30769 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30770})(powerbi || (powerbi = {}));
30771/*
30772 * Power BI Visualizations
30773 *
30774 * Copyright (c) Microsoft Corporation
30775 * All rights reserved.
30776 * MIT License
30777 *
30778 * Permission is hereby granted, free of charge, to any person obtaining a copy
30779 * of this software and associated documentation files (the ""Software""), to deal
30780 * in the Software without restriction, including without limitation the rights
30781 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30782 * copies of the Software, and to permit persons to whom the Software is
30783 * furnished to do so, subject to the following conditions:
30784 *
30785 * The above copyright notice and this permission notice shall be included in
30786 * all copies or substantial portions of the Software.
30787 *
30788 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30789 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30790 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30791 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30792 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30793 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30794 * THE SOFTWARE.
30795 */
30796var powerbi;
30797(function (powerbi) {
30798 var visuals;
30799 (function (visuals) {
30800 var HorizontalSlicerWebBehavior = (function () {
30801 function HorizontalSlicerWebBehavior() {
30802 }
30803 HorizontalSlicerWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30804 this.itemLabels = options.itemLabels;
30805 this.dataPoints = options.dataPoints;
30806 this.interactivityService = options.interactivityService;
30807 this.slicerSettings = options.settings;
30808 visuals.SlicerWebBehavior.bindSlicerEvents(options.slicerContainer, this.itemLabels, options.clear, selectionHandler, this.slicerSettings, this.interactivityService);
30809 };
30810 HorizontalSlicerWebBehavior.prototype.renderSelection = function (hasSelection) {
30811 visuals.SlicerWebBehavior.setSelectionOnSlicerItems(this.itemLabels, this.itemLabels, hasSelection, this.interactivityService, this.slicerSettings);
30812 };
30813 return HorizontalSlicerWebBehavior;
30814 }());
30815 visuals.HorizontalSlicerWebBehavior = HorizontalSlicerWebBehavior;
30816 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30817})(powerbi || (powerbi = {}));
30818/*
30819 * Power BI Visualizations
30820 *
30821 * Copyright (c) Microsoft Corporation
30822 * All rights reserved.
30823 * MIT License
30824 *
30825 * Permission is hereby granted, free of charge, to any person obtaining a copy
30826 * of this software and associated documentation files (the ""Software""), to deal
30827 * in the Software without restriction, including without limitation the rights
30828 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30829 * copies of the Software, and to permit persons to whom the Software is
30830 * furnished to do so, subject to the following conditions:
30831 *
30832 * The above copyright notice and this permission notice shall be included in
30833 * all copies or substantial portions of the Software.
30834 *
30835 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30836 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30837 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30838 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30839 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30840 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30841 * THE SOFTWARE.
30842 */
30843var powerbi;
30844(function (powerbi) {
30845 var visuals;
30846 (function (visuals) {
30847 var VerticalSlicerWebBehavior = (function () {
30848 function VerticalSlicerWebBehavior() {
30849 }
30850 VerticalSlicerWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30851 var slicers = options.itemContainers;
30852 this.itemLabels = options.itemLabels;
30853 this.itemInputs = options.itemInputs;
30854 this.dataPoints = options.dataPoints;
30855 this.interactivityService = options.interactivityService;
30856 this.settings = options.settings;
30857 visuals.SlicerWebBehavior.bindSlicerEvents(options.slicerContainer, slicers, options.clear, selectionHandler, this.settings, this.interactivityService);
30858 };
30859 VerticalSlicerWebBehavior.prototype.renderSelection = function (hasSelection) {
30860 visuals.SlicerWebBehavior.setSelectionOnSlicerItems(this.itemInputs, this.itemLabels, hasSelection, this.interactivityService, this.settings);
30861 };
30862 return VerticalSlicerWebBehavior;
30863 }());
30864 visuals.VerticalSlicerWebBehavior = VerticalSlicerWebBehavior;
30865 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
30866})(powerbi || (powerbi = {}));
30867/*
30868 * Power BI Visualizations
30869 *
30870 * Copyright (c) Microsoft Corporation
30871 * All rights reserved.
30872 * MIT License
30873 *
30874 * Permission is hereby granted, free of charge, to any person obtaining a copy
30875 * of this software and associated documentation files (the ""Software""), to deal
30876 * in the Software without restriction, including without limitation the rights
30877 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30878 * copies of the Software, and to permit persons to whom the Software is
30879 * furnished to do so, subject to the following conditions:
30880 *
30881 * The above copyright notice and this permission notice shall be included in
30882 * all copies or substantial portions of the Software.
30883 *
30884 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30885 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30886 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30887 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30888 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30889 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30890 * THE SOFTWARE.
30891 */
30892var powerbi;
30893(function (powerbi) {
30894 var visuals;
30895 (function (visuals) {
30896 var SlicerWebBehavior = (function () {
30897 function SlicerWebBehavior() {
30898 }
30899 SlicerWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
30900 this.behavior = this.createWebBehavior(options);
30901 this.behavior.bindEvents(options.behaviorOptions, selectionHandler);
30902 };
30903 SlicerWebBehavior.prototype.renderSelection = function (hasSelection) {
30904 this.behavior.renderSelection(hasSelection);
30905 };
30906 SlicerWebBehavior.bindSlicerEvents = function (slicerContainer, slicers, slicerClear, selectionHandler, slicerSettings, interactivityService) {
30907 SlicerWebBehavior.bindSlicerItemSelectionEvent(slicers, selectionHandler, slicerSettings, interactivityService);
30908 SlicerWebBehavior.bindSlicerClearEvent(slicerClear, selectionHandler);
30909 SlicerWebBehavior.styleSlicerContainer(slicerContainer, interactivityService);
30910 };
30911 SlicerWebBehavior.setSelectionOnSlicerItems = function (selectableItems, itemLabel, hasSelection, interactivityService, slicerSettings) {
30912 if (!hasSelection && !interactivityService.isSelectionModeInverted()) {
30913 selectableItems.filter('.selected').classed('selected', false);
30914 selectableItems.filter('.partiallySelected').classed('partiallySelected', false);
30915 var input = selectableItems.selectAll('input');
30916 if (input) {
30917 input.property('checked', false);
30918 }
30919 itemLabel.style('color', slicerSettings.slicerText.color);
30920 }
30921 else {
30922 SlicerWebBehavior.styleSlicerItems(selectableItems, hasSelection, interactivityService.isSelectionModeInverted());
30923 }
30924 };
30925 SlicerWebBehavior.styleSlicerItems = function (slicerItems, hasSelection, isSelectionInverted) {
30926 slicerItems.each(function (d) {
30927 var slicerItem = this;
30928 var shouldCheck = false;
30929 if (d.isSelectAllDataPoint) {
30930 if (hasSelection) {
30931 slicerItem.classList.add('partiallySelected');
30932 shouldCheck = false;
30933 }
30934 else {
30935 slicerItem.classList.remove('partiallySelected');
30936 shouldCheck = isSelectionInverted;
30937 }
30938 }
30939 else {
30940 shouldCheck = jsCommon.LogicExtensions.XOR(d.selected, isSelectionInverted);
30941 }
30942 if (shouldCheck)
30943 slicerItem.classList.add('selected');
30944 else
30945 slicerItem.classList.remove('selected');
30946 // Set input selected state to match selection
30947 var input = slicerItem.getElementsByTagName('input')[0];
30948 if (input)
30949 input.checked = shouldCheck;
30950 });
30951 };
30952 SlicerWebBehavior.bindSlicerItemSelectionEvent = function (slicers, selectionHandler, slicerSettings, interactivityService) {
30953 SlicerWebBehavior.isTouch = false;
30954 slicers.on("touchstart", function (d) {
30955 SlicerWebBehavior.isTouch = true;
30956 });
30957 slicers.on("pointerdown", function (d) {
30958 var e = d3.event;
30959 if (e && e.pointerType === "touch") {
30960 SlicerWebBehavior.isTouch = true;
30961 }
30962 });
30963 slicers.on("click", function (d) {
30964 d3.event.preventDefault();
30965 if (d.isSelectAllDataPoint) {
30966 selectionHandler.toggleSelectionModeInversion();
30967 }
30968 else {
30969 selectionHandler.handleSelection(d, SlicerWebBehavior.isTouch || SlicerWebBehavior.isMultiSelect(d3.event, slicerSettings, interactivityService));
30970 }
30971 selectionHandler.persistSelectionFilter(visuals.slicerProps.filterPropertyIdentifier);
30972 SlicerWebBehavior.isTouch = false;
30973 });
30974 };
30975 SlicerWebBehavior.bindSlicerClearEvent = function (slicerClear, selectionHandler) {
30976 if (slicerClear) {
30977 slicerClear.on("click", function (d) {
30978 selectionHandler.handleClearSelection();
30979 selectionHandler.persistSelectionFilter(visuals.slicerProps.filterPropertyIdentifier);
30980 });
30981 }
30982 };
30983 SlicerWebBehavior.styleSlicerContainer = function (slicerContainer, interactivityService) {
30984 var hasSelection = (interactivityService.hasSelection() && interactivityService.isDefaultValueEnabled() === undefined)
30985 || interactivityService.isDefaultValueEnabled() === false;
30986 slicerContainer.classed('hasSelection', hasSelection);
30987 };
30988 SlicerWebBehavior.isMultiSelect = function (event, settings, interactivityService) {
30989 // If selection is inverted, assume we're always in multi-select mode;
30990 // Also, Ctrl can be used to multi-select even in single-select mode.
30991 return interactivityService.isSelectionModeInverted()
30992 || !settings.selection.singleSelect
30993 || event.ctrlKey;
30994 };
30995 SlicerWebBehavior.prototype.createWebBehavior = function (options) {
30996 var behavior;
30997 var orientation = options.orientation;
30998 switch (orientation) {
30999 case 1 /* Horizontal */:
31000 behavior = new visuals.HorizontalSlicerWebBehavior();
31001 break;
31002 case 0 /* Vertical */:
31003 default:
31004 behavior = new visuals.VerticalSlicerWebBehavior();
31005 break;
31006 }
31007 return behavior;
31008 };
31009 return SlicerWebBehavior;
31010 }());
31011 visuals.SlicerWebBehavior = SlicerWebBehavior;
31012 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
31013})(powerbi || (powerbi = {}));
31014/*
31015 * Power BI Visualizations
31016 *
31017 * Copyright (c) Microsoft Corporation
31018 * All rights reserved.
31019 * MIT License
31020 *
31021 * Permission is hereby granted, free of charge, to any person obtaining a copy
31022 * of this software and associated documentation files (the ""Software""), to deal
31023 * in the Software without restriction, including without limitation the rights
31024 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31025 * copies of the Software, and to permit persons to whom the Software is
31026 * furnished to do so, subject to the following conditions:
31027 *
31028 * The above copyright notice and this permission notice shall be included in
31029 * all copies or substantial portions of the Software.
31030 *
31031 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31032 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31033 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31034 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31035 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31036 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31037 * THE SOFTWARE.
31038 */
31039var powerbi;
31040(function (powerbi) {
31041 var visuals;
31042 (function (visuals) {
31043 var LegendBehavior = (function () {
31044 function LegendBehavior() {
31045 }
31046 LegendBehavior.prototype.bindEvents = function (options, selectionHandler) {
31047 var legendItems = options.legendItems;
31048 this.legendIcons = options.legendIcons;
31049 var clearCatcher = options.clearCatcher;
31050 visuals.InteractivityUtils.registerStandardSelectionHandler(legendItems, selectionHandler);
31051 clearCatcher.on('click', function () {
31052 selectionHandler.handleClearSelection();
31053 });
31054 };
31055 LegendBehavior.prototype.renderSelection = function (hasSelection) {
31056 if (hasSelection) {
31057 this.legendIcons.style({
31058 'fill': function (d) {
31059 if (!d.selected)
31060 return LegendBehavior.dimmedLegendColor;
31061 else
31062 return d.color;
31063 }
31064 });
31065 }
31066 else {
31067 this.legendIcons.style({
31068 'fill': function (d) {
31069 return d.color;
31070 }
31071 });
31072 }
31073 };
31074 LegendBehavior.dimmedLegendColor = '#A6A6A6';
31075 return LegendBehavior;
31076 }());
31077 visuals.LegendBehavior = LegendBehavior;
31078 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
31079})(powerbi || (powerbi = {}));
31080/*
31081 * Power BI Visualizations
31082 *
31083 * Copyright (c) Microsoft Corporation
31084 * All rights reserved.
31085 * MIT License
31086 *
31087 * Permission is hereby granted, free of charge, to any person obtaining a copy
31088 * of this software and associated documentation files (the ""Software""), to deal
31089 * in the Software without restriction, including without limitation the rights
31090 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31091 * copies of the Software, and to permit persons to whom the Software is
31092 * furnished to do so, subject to the following conditions:
31093 *
31094 * The above copyright notice and this permission notice shall be included in
31095 * all copies or substantial portions of the Software.
31096 *
31097 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31098 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31099 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31100 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31101 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31102 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31103 * THE SOFTWARE.
31104 */
31105var powerbi;
31106(function (powerbi) {
31107 var visuals;
31108 (function (visuals) {
31109 var TreemapWebBehavior = (function () {
31110 function TreemapWebBehavior() {
31111 }
31112 TreemapWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
31113 var shapes = this.shapes = options.shapes;
31114 var highlightShapes = this.highlightShapes = options.highlightShapes;
31115 var majorLabels = options.majorLabels;
31116 var minorLabels = options.minorLabels;
31117 this.hasHighlights = options.hasHighlights;
31118 visuals.InteractivityUtils.registerStandardInteractivityHandlers(shapes, selectionHandler);
31119 visuals.InteractivityUtils.registerStandardInteractivityHandlers(highlightShapes, selectionHandler);
31120 if (majorLabels) {
31121 visuals.InteractivityUtils.registerStandardInteractivityHandlers(majorLabels, selectionHandler);
31122 }
31123 if (minorLabels) {
31124 visuals.InteractivityUtils.registerStandardInteractivityHandlers(minorLabels, selectionHandler);
31125 }
31126 };
31127 TreemapWebBehavior.prototype.renderSelection = function (hasSelection) {
31128 var hasHighlights = this.hasHighlights;
31129 this.shapes
31130 .style("fill", function (d) { return visuals.Treemap.getFill(d, /* isHighlightRect */ false); })
31131 .style("fill-opacity", function (d) { return visuals.Treemap.getFillOpacity(d, hasSelection, !d.selected && hasHighlights, /* isHighlightRect */ false); });
31132 this.highlightShapes
31133 .style("fill", function (d) { return visuals.Treemap.getFill(d, /* isHighlightRect */ true); })
31134 .style("fill-opacity", function (d) { return visuals.Treemap.getFillOpacity(d, hasSelection, !d.selected && hasHighlights, /* isHighlightRect */ true); });
31135 };
31136 return TreemapWebBehavior;
31137 }());
31138 visuals.TreemapWebBehavior = TreemapWebBehavior;
31139 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
31140})(powerbi || (powerbi = {}));
31141/*
31142 * Power BI Visualizations
31143 *
31144 * Copyright (c) Microsoft Corporation
31145 * All rights reserved.
31146 * MIT License
31147 *
31148 * Permission is hereby granted, free of charge, to any person obtaining a copy
31149 * of this software and associated documentation files (the ""Software""), to deal
31150 * in the Software without restriction, including without limitation the rights
31151 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31152 * copies of the Software, and to permit persons to whom the Software is
31153 * furnished to do so, subject to the following conditions:
31154 *
31155 * The above copyright notice and this permission notice shall be included in
31156 * all copies or substantial portions of the Software.
31157 *
31158 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31159 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31160 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31161 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31162 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31163 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31164 * THE SOFTWARE.
31165 */
31166var powerbi;
31167(function (powerbi) {
31168 var visuals;
31169 (function (visuals) {
31170 var WaterfallChartWebBehavior = (function () {
31171 function WaterfallChartWebBehavior() {
31172 }
31173 WaterfallChartWebBehavior.prototype.bindEvents = function (options, selectionHandler) {
31174 var bars = this.bars = options.bars;
31175 bars.on('click', function (d) {
31176 if (!d.isTotal) {
31177 selectionHandler.handleSelection(d, d3.event.ctrlKey);
31178 }
31179 });
31180 bars.on('contextmenu', function (d) {
31181 if (d3.event.ctrlKey)
31182 return;
31183 d3.event.preventDefault();
31184 if (!d.isTotal) {
31185 var position = visuals.InteractivityUtils.getPositionOfLastInputEvent();
31186 selectionHandler.handleContextMenu(d, position);
31187 }
31188 });
31189 };
31190 WaterfallChartWebBehavior.prototype.renderSelection = function (hasSelection) {
31191 this.bars.style("fill-opacity", function (d) { return d.isTotal ? visuals.ColumnUtil.DefaultOpacity : visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, false); });
31192 };
31193 return WaterfallChartWebBehavior;
31194 }());
31195 visuals.WaterfallChartWebBehavior = WaterfallChartWebBehavior;
31196 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
31197})(powerbi || (powerbi = {}));
31198/*
31199 * Power BI Visualizations
31200 *
31201 * Copyright (c) Microsoft Corporation
31202 * All rights reserved.
31203 * MIT License
31204 *
31205 * Permission is hereby granted, free of charge, to any person obtaining a copy
31206 * of this software and associated documentation files (the ""Software""), to deal
31207 * in the Software without restriction, including without limitation the rights
31208 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31209 * copies of the Software, and to permit persons to whom the Software is
31210 * furnished to do so, subject to the following conditions:
31211 *
31212 * The above copyright notice and this permission notice shall be included in
31213 * all copies or substantial portions of the Software.
31214 *
31215 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31216 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31217 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31218 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31219 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31220 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31221 * THE SOFTWARE.
31222 */
31223var powerbi;
31224(function (powerbi) {
31225 var visuals;
31226 (function (visuals) {
31227 var LabelsBehavior = (function () {
31228 function LabelsBehavior() {
31229 }
31230 LabelsBehavior.prototype.bindEvents = function (options, selectionHandler) {
31231 this.labelItems = options.labelItems;
31232 visuals.InteractivityUtils.registerStandardSelectionHandler(this.labelItems, selectionHandler);
31233 };
31234 LabelsBehavior.prototype.renderSelection = function (hasSelection) {
31235 if (hasSelection) {
31236 this.labelItems.style({
31237 'opacity': function (d) {
31238 if (!d.selected)
31239 return LabelsBehavior.DimmedLabelOpacity;
31240 else
31241 return LabelsBehavior.DefaultLabelOpacity;
31242 }
31243 });
31244 }
31245 else {
31246 this.labelItems.style({
31247 'opacity': LabelsBehavior.DefaultLabelOpacity,
31248 });
31249 }
31250 };
31251 LabelsBehavior.DefaultLabelOpacity = 1;
31252 LabelsBehavior.DimmedLabelOpacity = 0.6;
31253 return LabelsBehavior;
31254 }());
31255 visuals.LabelsBehavior = LabelsBehavior;
31256 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
31257})(powerbi || (powerbi = {}));
31258/*
31259 * Power BI Visualizations
31260 *
31261 * Copyright (c) Microsoft Corporation
31262 * All rights reserved.
31263 * MIT License
31264 *
31265 * Permission is hereby granted, free of charge, to any person obtaining a copy
31266 * of this software and associated documentation files (the ""Software""), to deal
31267 * in the Software without restriction, including without limitation the rights
31268 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31269 * copies of the Software, and to permit persons to whom the Software is
31270 * furnished to do so, subject to the following conditions:
31271 *
31272 * The above copyright notice and this permission notice shall be included in
31273 * all copies or substantial portions of the Software.
31274 *
31275 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31276 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31277 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31278 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31279 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31280 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31281 * THE SOFTWARE.
31282 */
31283var powerbi;
31284(function (powerbi) {
31285 var visuals;
31286 (function (visuals) {
31287 var CartesianChartBehavior = (function () {
31288 function CartesianChartBehavior(behaviors) {
31289 this.behaviors = behaviors;
31290 }
31291 CartesianChartBehavior.prototype.bindEvents = function (options, selectionHandler) {
31292 var behaviors = this.behaviors;
31293 for (var i = 0, ilen = behaviors.length; i < ilen; i++) {
31294 behaviors[i].bindEvents(options.layerOptions[i], selectionHandler);
31295 }
31296 options.clearCatcher.on('click', function () {
31297 selectionHandler.handleClearSelection();
31298 });
31299 };
31300 CartesianChartBehavior.prototype.renderSelection = function (hasSelection) {
31301 for (var _i = 0, _a = this.behaviors; _i < _a.length; _i++) {
31302 var behavior = _a[_i];
31303 behavior.renderSelection(hasSelection);
31304 }
31305 };
31306 return CartesianChartBehavior;
31307 }());
31308 visuals.CartesianChartBehavior = CartesianChartBehavior;
31309 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
31310})(powerbi || (powerbi = {}));
31311/*
31312 * Power BI Visualizations
31313 *
31314 * Copyright (c) Microsoft Corporation
31315 * All rights reserved.
31316 * MIT License
31317 *
31318 * Permission is hereby granted, free of charge, to any person obtaining a copy
31319 * of this software and associated documentation files (the ""Software""), to deal
31320 * in the Software without restriction, including without limitation the rights
31321 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31322 * copies of the Software, and to permit persons to whom the Software is
31323 * furnished to do so, subject to the following conditions:
31324 *
31325 * The above copyright notice and this permission notice shall be included in
31326 * all copies or substantial portions of the Software.
31327 *
31328 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31329 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31330 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31331 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31332 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31333 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31334 * THE SOFTWARE.
31335 */
31336/*
31337 * Power BI Visualizations
31338 *
31339 * Copyright (c) Microsoft Corporation
31340 * All rights reserved.
31341 * MIT License
31342 *
31343 * Permission is hereby granted, free of charge, to any person obtaining a copy
31344 * of this software and associated documentation files (the ""Software""), to deal
31345 * in the Software without restriction, including without limitation the rights
31346 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31347 * copies of the Software, and to permit persons to whom the Software is
31348 * furnished to do so, subject to the following conditions:
31349 *
31350 * The above copyright notice and this permission notice shall be included in
31351 * all copies or substantial portions of the Software.
31352 *
31353 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31354 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31355 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31356 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31357 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31358 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31359 * THE SOFTWARE.
31360 */
31361var powerbi;
31362(function (powerbi) {
31363 var visuals;
31364 (function (visuals) {
31365 /**
31366 * Default ranges are for when we have a field chosen for the axis,
31367 * but no values are returned by the query.
31368 */
31369 visuals.emptyDomain = [0, 0];
31370 var AxisHelper;
31371 (function (AxisHelper) {
31372 var XLabelMaxAllowedOverflow = 35;
31373 var TextHeightConstant = 10;
31374 var MinTickCount = 2;
31375 var DefaultBestTickCount = 3;
31376 var LeftPadding = 10;
31377 var ScalarTickLabelPadding = 3;
31378 function getRecommendedNumberOfTicksForXAxis(availableWidth) {
31379 if (availableWidth < 300)
31380 return 3;
31381 if (availableWidth < 500)
31382 return 5;
31383 return 8;
31384 }
31385 AxisHelper.getRecommendedNumberOfTicksForXAxis = getRecommendedNumberOfTicksForXAxis;
31386 function getRecommendedNumberOfTicksForYAxis(availableWidth) {
31387 if (availableWidth < 150)
31388 return 3;
31389 if (availableWidth < 300)
31390 return 5;
31391 return 8;
31392 }
31393 AxisHelper.getRecommendedNumberOfTicksForYAxis = getRecommendedNumberOfTicksForYAxis;
31394 /**
31395 * Get the best number of ticks based on minimum value, maximum value,
31396 * measure metadata and max tick count.
31397 *
31398 * @param min The minimum of the data domain.
31399 * @param max The maximum of the data domain.
31400 * @param valuesMetadata The measure metadata array.
31401 * @param maxTickCount The max count of intervals.
31402 * @param isDateTime - flag to show single tick when min is equal to max.
31403 */
31404 function getBestNumberOfTicks(min, max, valuesMetadata, maxTickCount, isDateTime) {
31405 debug.assert(maxTickCount >= 0, "maxTickCount must be greater or equal to zero");
31406 if (isNaN(min) || isNaN(max))
31407 return DefaultBestTickCount;
31408 debug.assert(min <= max, "min value needs to be less or equal to max value");
31409 if (maxTickCount <= 1 || (max <= 1 && min >= -1))
31410 return maxTickCount;
31411 if (min === max) {
31412 // datetime needs to only show one tick value in this case so formatting works correctly
31413 if (!!isDateTime)
31414 return 1;
31415 return DefaultBestTickCount;
31416 }
31417 if (hasNonIntegerData(valuesMetadata))
31418 return maxTickCount;
31419 // e.g. 5 - 2 + 1 = 4, => [2,3,4,5]
31420 return Math.min(max - min + 1, maxTickCount);
31421 }
31422 AxisHelper.getBestNumberOfTicks = getBestNumberOfTicks;
31423 function hasNonIntegerData(valuesMetadata) {
31424 for (var i = 0, len = valuesMetadata.length; i < len; i++) {
31425 var currentMetadata = valuesMetadata[i];
31426 if (currentMetadata && currentMetadata.type && !currentMetadata.type.integer) {
31427 return true;
31428 }
31429 }
31430 return false;
31431 }
31432 AxisHelper.hasNonIntegerData = hasNonIntegerData;
31433 function getRecommendedTickValues(maxTicks, scale, axisType, isScalar, minTickInterval) {
31434 if (!isScalar || isOrdinalScale(scale)) {
31435 return getRecommendedTickValuesForAnOrdinalRange(maxTicks, scale.domain());
31436 }
31437 else if (isDateTime(axisType)) {
31438 return getRecommendedTickValuesForADateTimeRange(maxTicks, scale.domain());
31439 }
31440 return getRecommendedTickValuesForAQuantitativeRange(maxTicks, scale, minTickInterval);
31441 }
31442 AxisHelper.getRecommendedTickValues = getRecommendedTickValues;
31443 function getRecommendedTickValuesForAnOrdinalRange(maxTicks, labels) {
31444 var tickLabels = [];
31445 // return no ticks in this case
31446 if (maxTicks <= 0)
31447 return tickLabels;
31448 var len = labels.length;
31449 if (maxTicks > len)
31450 return labels;
31451 for (var i = 0, step = Math.ceil(len / maxTicks); i < len; i += step) {
31452 tickLabels.push(labels[i]);
31453 }
31454 return tickLabels;
31455 }
31456 AxisHelper.getRecommendedTickValuesForAnOrdinalRange = getRecommendedTickValuesForAnOrdinalRange;
31457 function getRecommendedTickValuesForAQuantitativeRange(maxTicks, scale, minInterval) {
31458 var tickLabels = [];
31459 //if maxticks is zero return none
31460 if (maxTicks === 0)
31461 return tickLabels;
31462 var quantitiveScale = scale;
31463 if (quantitiveScale.ticks) {
31464 tickLabels = quantitiveScale.ticks(maxTicks);
31465 if (tickLabels.length > maxTicks && maxTicks > 1)
31466 tickLabels = quantitiveScale.ticks(maxTicks - 1);
31467 if (tickLabels.length < MinTickCount) {
31468 tickLabels = quantitiveScale.ticks(maxTicks + 1);
31469 }
31470 tickLabels = createTrueZeroTickLabel(tickLabels);
31471 if (minInterval && tickLabels.length > 1) {
31472 var tickInterval = tickLabels[1] - tickLabels[0];
31473 while (tickInterval > 0 && tickInterval < minInterval) {
31474 for (var i = 1; i < tickLabels.length; i++) {
31475 tickLabels.splice(i, 1);
31476 }
31477 tickInterval = tickInterval * 2;
31478 }
31479 // keep at least two labels - the loop above may trim all but one if we have odd # of tick labels and dynamic range < minInterval
31480 if (tickLabels.length === 1) {
31481 tickLabels.push(tickLabels[0] + minInterval);
31482 }
31483 }
31484 return tickLabels;
31485 }
31486 debug.assertFail('must pass a quantitative scale to this method');
31487 return tickLabels;
31488 }
31489 AxisHelper.getRecommendedTickValuesForAQuantitativeRange = getRecommendedTickValuesForAQuantitativeRange;
31490 /**
31491 * Round out very small zero tick values (e.g. -1e-33 becomes 0).
31492 *
31493 * @param ticks Array of numbers (from d3.scale.ticks([maxTicks])).
31494 * @param epsilon Max ratio of calculated tick interval which we will recognize as zero.
31495 *
31496 * e.g.
31497 * ticks = [-2, -1, 1e-10, 3, 4]; epsilon = 1e-5;
31498 * closeZero = 1e-5 * | 2 - 1 | = 1e-5
31499 * // Tick values <= 1e-5 replaced with 0
31500 * return [-2, -1, 0, 3, 4];
31501 */
31502 function createTrueZeroTickLabel(ticks, epsilon) {
31503 if (epsilon === void 0) { epsilon = 1e-5; }
31504 if (!ticks || ticks.length < 2)
31505 return ticks;
31506 var closeZero = epsilon * Math.abs(ticks[1] - ticks[0]);
31507 return ticks.map(function (tick) { return Math.abs(tick) <= closeZero ? 0 : tick; });
31508 }
31509 function getRecommendedTickValuesForADateTimeRange(maxTicks, dataDomain) {
31510 var tickLabels = [];
31511 if (dataDomain[0] === 0 && dataDomain[1] === 0)
31512 return [];
31513 var dateTimeTickLabels = powerbi.DateTimeSequence.calculate(new Date(dataDomain[0]), new Date(dataDomain[1]), maxTicks).sequence;
31514 tickLabels = dateTimeTickLabels.map(function (d) { return d.getTime(); });
31515 tickLabels = ensureValuesInRange(tickLabels, dataDomain[0], dataDomain[1]);
31516 return tickLabels;
31517 }
31518 function normalizeLinearDomain(domain) {
31519 if (isNaN(domain.min) || isNaN(domain.max)) {
31520 domain.min = visuals.emptyDomain[0];
31521 domain.max = visuals.emptyDomain[1];
31522 }
31523 else if (domain.min === domain.max) {
31524 // d3 linear scale will give zero tickValues if max === min, so extend a little
31525 domain.min = domain.min < 0 ? domain.min * 1.2 : domain.min * 0.8;
31526 domain.max = domain.max < 0 ? domain.max * 0.8 : domain.max * 1.2;
31527 }
31528 else {
31529 // Check that min is very small and is a negligable portion of the whole domain.
31530 // (fix floating pt precision bugs)
31531 // sometimes highlight value math causes small negative numbers which makes the axis add
31532 // a large tick interval instead of just rendering at zero.
31533 if (Math.abs(domain.min) < 0.0001 && domain.min / (domain.max - domain.min) < 0.0001) {
31534 domain.min = 0;
31535 }
31536 }
31537 return domain;
31538 }
31539 function getMargin(availableWidth, availableHeight, xMargin, yMargin) {
31540 if (getRecommendedNumberOfTicksForXAxis(availableWidth - xMargin) === 0
31541 || getRecommendedNumberOfTicksForYAxis(availableHeight - yMargin) === 0) {
31542 return {
31543 top: 0,
31544 right: xMargin,
31545 bottom: yMargin,
31546 left: 0
31547 };
31548 }
31549 return {
31550 top: 20,
31551 right: 30,
31552 bottom: 40,
31553 left: 30
31554 };
31555 }
31556 AxisHelper.getMargin = getMargin;
31557 // TODO: Put the parameters into one object
31558 function getTickLabelMargins(viewport, yMarginLimit, textWidthMeasurer, textHeightMeasurer, axes, bottomMarginLimit, properties, scrollbarVisible, showOnRight, renderXAxis, renderY1Axis, renderY2Axis) {
31559 debug.assertValue(axes, 'axes');
31560 var xAxisProperties = axes.x;
31561 var y1AxisProperties = axes.y1;
31562 var y2AxisProperties = axes.y2;
31563 debug.assertValue(viewport, 'viewport');
31564 debug.assertValue(textWidthMeasurer, 'textWidthMeasurer');
31565 debug.assertValue(textHeightMeasurer, 'textHeightMeasurer');
31566 debug.assertValue(xAxisProperties, 'xAxis');
31567 debug.assertValue(y1AxisProperties, 'yAxis');
31568 var xLabels = xAxisProperties.values;
31569 var y1Labels = y1AxisProperties.values;
31570 var leftOverflow = 0;
31571 var rightOverflow = 0;
31572 var maxWidthY1 = 0;
31573 var maxWidthY2 = 0;
31574 var xMax = 0; // bottom margin
31575 var ordinalLabelOffset = xAxisProperties.categoryThickness ? xAxisProperties.categoryThickness / 2 : 0;
31576 var scaleIsOrdinal = isOrdinalScale(xAxisProperties.scale);
31577 var xLabelOuterPadding = 0;
31578 if (xAxisProperties.outerPadding !== undefined) {
31579 xLabelOuterPadding = xAxisProperties.outerPadding;
31580 }
31581 else if (xAxisProperties.xLabelMaxWidth !== undefined) {
31582 xLabelOuterPadding = Math.max(0, (viewport.width - xAxisProperties.xLabelMaxWidth * xLabels.length) / 2);
31583 }
31584 if (getRecommendedNumberOfTicksForXAxis(viewport.width) !== 0
31585 || getRecommendedNumberOfTicksForYAxis(viewport.height) !== 0) {
31586 var rotation = void 0;
31587 if (scrollbarVisible)
31588 rotation = LabelLayoutStrategy.DefaultRotationWithScrollbar;
31589 else
31590 rotation = LabelLayoutStrategy.DefaultRotation;
31591 if (renderY1Axis) {
31592 for (var i = 0, len = y1Labels.length; i < len; i++) {
31593 properties.text = y1Labels[i];
31594 maxWidthY1 = Math.max(maxWidthY1, textWidthMeasurer(properties));
31595 }
31596 }
31597 if (y2AxisProperties && renderY2Axis) {
31598 var y2Labels = y2AxisProperties.values;
31599 for (var i = 0, len = y2Labels.length; i < len; i++) {
31600 properties.text = y2Labels[i];
31601 maxWidthY2 = Math.max(maxWidthY2, textWidthMeasurer(properties));
31602 }
31603 }
31604 var textHeight = textHeightMeasurer(properties);
31605 var maxNumLines = Math.floor(bottomMarginLimit / textHeight);
31606 var xScale = xAxisProperties.scale;
31607 var xDomain = xScale.domain();
31608 if (renderXAxis && xLabels.length > 0) {
31609 for (var i = 0, len = xLabels.length; i < len; i++) {
31610 // find the max height of the x-labels, perhaps rotated or wrapped
31611 var height = void 0;
31612 properties.text = xLabels[i];
31613 var width = textWidthMeasurer(properties);
31614 if (xAxisProperties.willLabelsWordBreak) {
31615 // Split label and count rows
31616 var wordBreaks = jsCommon.WordBreaker.splitByWidth(properties.text, properties, textWidthMeasurer, xAxisProperties.xLabelMaxWidth, maxNumLines);
31617 height = wordBreaks.length * textHeight;
31618 // word wrapping will truncate at xLabelMaxWidth
31619 width = xAxisProperties.xLabelMaxWidth;
31620 }
31621 else if (!xAxisProperties.willLabelsFit && scaleIsOrdinal) {
31622 height = width * rotation.sine;
31623 width = width * rotation.cosine;
31624 }
31625 else {
31626 height = TextHeightConstant;
31627 }
31628 // calculate left and right overflow due to wide X labels
31629 // (Note: no right overflow when rotated)
31630 if (i === 0) {
31631 if (scaleIsOrdinal) {
31632 if (!xAxisProperties.willLabelsFit /*rotated text*/)
31633 leftOverflow = width - ordinalLabelOffset - xLabelOuterPadding;
31634 else
31635 leftOverflow = (width / 2) - ordinalLabelOffset - xLabelOuterPadding;
31636 leftOverflow = Math.max(leftOverflow, 0);
31637 }
31638 else if (xDomain.length > 1) {
31639 // Scalar - do some math
31640 var xPos = xScale(xDomain[0]);
31641 // xPos already incorporates xLabelOuterPadding, don't subtract it twice
31642 leftOverflow = (width / 2) - xPos;
31643 leftOverflow = Math.max(leftOverflow, 0);
31644 }
31645 }
31646 else if (i === len - 1) {
31647 if (scaleIsOrdinal) {
31648 // if we are rotating text (!willLabelsFit) there won't be any right overflow
31649 if (xAxisProperties.willLabelsFit || xAxisProperties.willLabelsWordBreak) {
31650 // assume this label is placed near the edge
31651 rightOverflow = (width / 2) - ordinalLabelOffset - xLabelOuterPadding;
31652 rightOverflow = Math.max(rightOverflow, 0);
31653 }
31654 }
31655 else if (xDomain.length > 1) {
31656 // Scalar - do some math
31657 var xPos = xScale(xDomain[1]);
31658 // xPos already incorporates xLabelOuterPadding, don't subtract it twice
31659 rightOverflow = (width / 2) - (viewport.width - xPos);
31660 rightOverflow = Math.max(rightOverflow, 0);
31661 }
31662 }
31663 xMax = Math.max(xMax, height);
31664 }
31665 // trim any actual overflow to the limit
31666 leftOverflow = Math.min(leftOverflow, XLabelMaxAllowedOverflow);
31667 rightOverflow = Math.min(rightOverflow, XLabelMaxAllowedOverflow);
31668 }
31669 }
31670 var rightMargin = 0, leftMargin = 0, bottomMargin = Math.min(Math.ceil(xMax), bottomMarginLimit);
31671 if (showOnRight) {
31672 leftMargin = Math.min(Math.max(leftOverflow, maxWidthY2), yMarginLimit);
31673 rightMargin = Math.min(Math.max(rightOverflow, maxWidthY1), yMarginLimit);
31674 }
31675 else {
31676 leftMargin = Math.min(Math.max(leftOverflow, maxWidthY1), yMarginLimit);
31677 rightMargin = Math.min(Math.max(rightOverflow, maxWidthY2), yMarginLimit);
31678 }
31679 return {
31680 xMax: Math.ceil(bottomMargin),
31681 yLeft: Math.ceil(leftMargin),
31682 yRight: Math.ceil(rightMargin),
31683 };
31684 }
31685 AxisHelper.getTickLabelMargins = getTickLabelMargins;
31686 function columnDataTypeHasValue(dataType) {
31687 return dataType && (dataType.bool || dataType.numeric || dataType.text || dataType.dateTime);
31688 }
31689 AxisHelper.columnDataTypeHasValue = columnDataTypeHasValue;
31690 function createOrdinalType() {
31691 return powerbi.ValueType.fromDescriptor({ text: true });
31692 }
31693 AxisHelper.createOrdinalType = createOrdinalType;
31694 function isOrdinal(type) {
31695 return !!(type && (type.text || type.bool));
31696 }
31697 AxisHelper.isOrdinal = isOrdinal;
31698 function isOrdinalScale(scale) {
31699 return typeof scale.invert === 'undefined';
31700 }
31701 AxisHelper.isOrdinalScale = isOrdinalScale;
31702 function isDateTime(type) {
31703 return !!(type && type.dateTime);
31704 }
31705 AxisHelper.isDateTime = isDateTime;
31706 function invertScale(scale, x) {
31707 if (isOrdinalScale(scale)) {
31708 return invertOrdinalScale(scale, x);
31709 }
31710 return scale.invert(x);
31711 }
31712 AxisHelper.invertScale = invertScale;
31713 function extent(scale) {
31714 if (isOrdinalScale(scale)) {
31715 return scale.rangeExtent();
31716 }
31717 return scale.range();
31718 }
31719 AxisHelper.extent = extent;
31720 function invertOrdinalScale(scale, x) {
31721 var leftEdges = scale.range();
31722 if (leftEdges.length < 2)
31723 return 0;
31724 var width = scale.rangeBand();
31725 var halfInnerPadding = (leftEdges[1] - leftEdges[0] - width) / 2;
31726 var j;
31727 for (j = 0; x > (leftEdges[j] + width + halfInnerPadding) && j < (leftEdges.length - 1); j++)
31728 ;
31729 return scale.domain()[j];
31730 }
31731 AxisHelper.invertOrdinalScale = invertOrdinalScale;
31732 function findClosestXAxisIndex(categoryValue, categoryAxisValues) {
31733 var closestValueIndex = -1;
31734 var minDistance = Number.MAX_VALUE;
31735 for (var i in categoryAxisValues) {
31736 var distance = Math.abs(categoryValue - categoryAxisValues[i].categoryValue);
31737 if (distance < minDistance) {
31738 minDistance = distance;
31739 closestValueIndex = parseInt(i, 10);
31740 }
31741 }
31742 return closestValueIndex;
31743 }
31744 AxisHelper.findClosestXAxisIndex = findClosestXAxisIndex;
31745 function lookupOrdinalIndex(scale, pixelValue) {
31746 var closestValueIndex = -1;
31747 var minDistance = Number.MAX_VALUE;
31748 var domain = scale.domain();
31749 if (domain.length < 2)
31750 return 0;
31751 var halfWidth = (scale(1) - scale(0)) / 2;
31752 for (var idx in domain) {
31753 var leftEdgeInPixels = scale(idx);
31754 var midPoint = leftEdgeInPixels + halfWidth;
31755 var distance = Math.abs(pixelValue - midPoint);
31756 if (distance < minDistance) {
31757 minDistance = distance;
31758 closestValueIndex = parseInt(idx, 10);
31759 }
31760 }
31761 return closestValueIndex;
31762 }
31763 AxisHelper.lookupOrdinalIndex = lookupOrdinalIndex;
31764 /** scale(value1) - scale(value2) with zero checking and min(+/-1, result) */
31765 function diffScaled(scale, value1, value2) {
31766 debug.assertValue(scale, 'scale');
31767 var value = scale(value1) - scale(value2);
31768 if (value === 0)
31769 return 0;
31770 if (value < 0)
31771 return Math.min(value, -1);
31772 return Math.max(value, 1);
31773 }
31774 AxisHelper.diffScaled = diffScaled;
31775 function createDomain(data, axisType, isScalar, forcedScalarDomain, ensureDomain) {
31776 if (isScalar && !isOrdinal(axisType)) {
31777 var userMin = void 0, userMax = void 0;
31778 if (forcedScalarDomain && forcedScalarDomain.length === 2) {
31779 userMin = forcedScalarDomain[0];
31780 userMax = forcedScalarDomain[1];
31781 }
31782 return createScalarDomain(data, userMin, userMax, axisType, ensureDomain);
31783 }
31784 return createOrdinalDomain(data);
31785 }
31786 AxisHelper.createDomain = createDomain;
31787 function ensureValuesInRange(values, min, max) {
31788 debug.assert(min <= max, "min must be less or equal to max");
31789 var filteredValues = values.filter(function (v) { return v >= min && v <= max; });
31790 if (filteredValues.length < 2)
31791 filteredValues = [min, max];
31792 return filteredValues;
31793 }
31794 AxisHelper.ensureValuesInRange = ensureValuesInRange;
31795 /**
31796 * Gets the ValueType of a category column, defaults to Text if the type is not present.
31797 */
31798 function getCategoryValueType(metadataColumn, isScalar) {
31799 if (metadataColumn && columnDataTypeHasValue(metadataColumn.type))
31800 return metadataColumn.type;
31801 if (isScalar) {
31802 return powerbi.ValueType.fromDescriptor({ numeric: true });
31803 }
31804 return powerbi.ValueType.fromDescriptor({ text: true });
31805 }
31806 AxisHelper.getCategoryValueType = getCategoryValueType;
31807 /**
31808 * Create a D3 axis including scale. Can be vertical or horizontal, and either datetime, numeric, or text.
31809 * @param options The properties used to create the axis.
31810 */
31811 function createAxis(options) {
31812 var pixelSpan = options.pixelSpan, dataDomain = options.dataDomain, metaDataColumn = options.metaDataColumn, formatString = options.formatString, outerPadding = options.outerPadding || 0, isCategoryAxis = !!options.isCategoryAxis, isScalar = !!options.isScalar, isVertical = !!options.isVertical, useTickIntervalForDisplayUnits = !!options.useTickIntervalForDisplayUnits, // DEPRECATE: same meaning as isScalar?
31813 getValueFn = options.getValueFn, categoryThickness = options.categoryThickness, axisDisplayUnits = options.axisDisplayUnits, axisPrecision = options.axisPrecision, is100Pct = !!options.is100Pct;
31814 var dataType = AxisHelper.getCategoryValueType(metaDataColumn, isScalar);
31815 // Create the Scale
31816 var scaleResult = AxisHelper.createScale(options);
31817 var scale = scaleResult.scale;
31818 var bestTickCount = scaleResult.bestTickCount;
31819 var scaleDomain = scale.domain();
31820 var isLogScaleAllowed = AxisHelper.isLogScalePossible(dataDomain, dataType);
31821 // fix categoryThickness if scalar and the domain was adjusted when making the scale "nice"
31822 if (categoryThickness && isScalar && dataDomain && dataDomain.length === 2) {
31823 var oldSpan = dataDomain[1] - dataDomain[0];
31824 var newSpan = scaleDomain[1] - scaleDomain[0];
31825 if (oldSpan > 0 && newSpan > 0) {
31826 categoryThickness = categoryThickness * oldSpan / newSpan;
31827 }
31828 }
31829 // Prepare Tick Values for formatting
31830 var tickValues;
31831 if (isScalar && bestTickCount === 1) {
31832 tickValues = [dataDomain[0]];
31833 }
31834 else {
31835 var minTickInterval = isScalar ? getMinTickValueInterval(formatString, dataType, is100Pct) : undefined;
31836 tickValues = getRecommendedTickValues(bestTickCount, scale, dataType, isScalar, minTickInterval);
31837 }
31838 if (options.scaleType && options.scaleType === visuals.axisScale.log && isLogScaleAllowed) {
31839 tickValues = tickValues.filter(function (d) { return AxisHelper.powerOfTen(d); });
31840 }
31841 var formatter = createFormatter(scaleDomain, dataDomain, dataType, isScalar, formatString, bestTickCount, tickValues, getValueFn, useTickIntervalForDisplayUnits, axisDisplayUnits, axisPrecision);
31842 // sets default orientation only, cartesianChart will fix y2 for comboChart
31843 // tickSize(pixelSpan) is used to create gridLines
31844 var axis = d3.svg.axis()
31845 .scale(scale)
31846 .tickSize(6, 0)
31847 .orient(isVertical ? 'left' : 'bottom')
31848 .ticks(bestTickCount)
31849 .tickValues(tickValues);
31850 var formattedTickValues = [];
31851 if (metaDataColumn)
31852 formattedTickValues = formatAxisTickValues(axis, tickValues, formatter, dataType, getValueFn);
31853 var xLabelMaxWidth;
31854 // Use category layout of labels if specified, otherwise use scalar layout of labels
31855 if (!isScalar && categoryThickness) {
31856 xLabelMaxWidth = Math.max(1, categoryThickness - visuals.CartesianChart.TickLabelPadding * 2);
31857 }
31858 else {
31859 // When there are 0 or 1 ticks, then xLabelMaxWidth = pixelSpan
31860 xLabelMaxWidth = tickValues.length > 1 ? getScalarLabelMaxWidth(scale, tickValues) : pixelSpan;
31861 xLabelMaxWidth = xLabelMaxWidth - ScalarTickLabelPadding * 2;
31862 }
31863 return {
31864 scale: scale,
31865 axis: axis,
31866 formatter: formatter,
31867 values: formattedTickValues,
31868 axisType: dataType,
31869 axisLabel: null,
31870 isCategoryAxis: isCategoryAxis,
31871 xLabelMaxWidth: xLabelMaxWidth,
31872 categoryThickness: categoryThickness,
31873 outerPadding: outerPadding,
31874 usingDefaultDomain: scaleResult.usingDefaultDomain,
31875 isLogScaleAllowed: isLogScaleAllowed,
31876 dataDomain: dataDomain,
31877 };
31878 }
31879 AxisHelper.createAxis = createAxis;
31880 function getScalarLabelMaxWidth(scale, tickValues) {
31881 debug.assertValue(scale, "scale");
31882 debug.assertNonEmpty(tickValues, "tickValues");
31883 // find the distance between two ticks. scalar ticks can be anywhere, such as:
31884 // |---50----------100--------|
31885 if (scale && !_.isEmpty(tickValues)) {
31886 return Math.abs(scale(tickValues[1]) - scale(tickValues[0]));
31887 }
31888 return 1;
31889 }
31890 function createScale(options) {
31891 var pixelSpan = options.pixelSpan, dataDomain = options.dataDomain, metaDataColumn = options.metaDataColumn, outerPadding = options.outerPadding || 0, isScalar = !!options.isScalar, isVertical = !!options.isVertical, forcedTickCount = options.forcedTickCount, categoryThickness = options.categoryThickness, shouldClamp = !!options.shouldClamp;
31892 var dataType = AxisHelper.getCategoryValueType(metaDataColumn, isScalar);
31893 var maxTicks = isVertical ? getRecommendedNumberOfTicksForYAxis(pixelSpan) : getRecommendedNumberOfTicksForXAxis(pixelSpan);
31894 var scalarDomain = dataDomain ? dataDomain.slice() : null;
31895 var bestTickCount = maxTicks;
31896 var scale;
31897 var usingDefaultDomain = false;
31898 if (dataDomain == null || (dataDomain.length === 2 && dataDomain[0] == null && dataDomain[1] == null) || (dataDomain.length !== 2 && isScalar)) {
31899 usingDefaultDomain = true;
31900 if (dataType.dateTime || !isOrdinal(dataType))
31901 dataDomain = visuals.emptyDomain;
31902 else
31903 dataDomain = [];
31904 if (isOrdinal(dataType)) {
31905 scale = createOrdinalScale(pixelSpan, dataDomain, categoryThickness ? outerPadding / categoryThickness : 0);
31906 }
31907 else {
31908 scale = createNumericalScale(options.scaleType, pixelSpan, dataDomain, dataType, outerPadding, bestTickCount);
31909 }
31910 }
31911 else {
31912 if (isScalar && dataDomain.length > 0) {
31913 bestTickCount = forcedTickCount !== undefined
31914 ? (maxTicks !== 0 ? forcedTickCount : 0)
31915 : AxisHelper.getBestNumberOfTicks(dataDomain[0], dataDomain[dataDomain.length - 1], [metaDataColumn], maxTicks, dataType.dateTime);
31916 var normalizedRange = normalizeLinearDomain({ min: dataDomain[0], max: dataDomain[dataDomain.length - 1] });
31917 scalarDomain = [normalizedRange.min, normalizedRange.max];
31918 }
31919 if (isScalar && dataType.numeric && !dataType.dateTime) {
31920 scale = createNumericalScale(options.scaleType, pixelSpan, scalarDomain, dataType, outerPadding, bestTickCount, shouldClamp);
31921 }
31922 else if (isScalar && dataType.dateTime) {
31923 // Use of a linear scale, instead of a D3.time.scale, is intentional since we want
31924 // to control the formatting of the time values, since d3's implementation isn't
31925 // in accordance to our design.
31926 // scalarDomain: should already be in long-int time (via category.values[0].getTime())
31927 scale = createLinearScale(pixelSpan, scalarDomain, outerPadding, null, shouldClamp); // DO NOT PASS TICKCOUNT
31928 }
31929 else if (dataType.text || dataType.dateTime || dataType.numeric || dataType.bool) {
31930 scale = createOrdinalScale(pixelSpan, scalarDomain, categoryThickness ? outerPadding / categoryThickness : 0);
31931 bestTickCount = maxTicks === 0 ? 0
31932 : Math.min(scalarDomain.length, (pixelSpan - outerPadding * 2) / visuals.CartesianChart.MinOrdinalRectThickness);
31933 }
31934 else {
31935 debug.assertFail('unsupported dataType, something other than text or numeric');
31936 }
31937 }
31938 // vertical ordinal axis (e.g. categorical bar chart) does not need to reverse
31939 if (isVertical && isScalar) {
31940 scale.range(scale.range().reverse());
31941 }
31942 visuals.ColumnUtil.normalizeInfinityInScale(scale);
31943 return {
31944 scale: scale,
31945 bestTickCount: bestTickCount,
31946 usingDefaultDomain: usingDefaultDomain,
31947 };
31948 }
31949 AxisHelper.createScale = createScale;
31950 function createFormatter(scaleDomain, dataDomain, dataType, isScalar, formatString, bestTickCount, tickValues, getValueFn, useTickIntervalForDisplayUnits, axisDisplayUnits, axisPrecision) {
31951 if (useTickIntervalForDisplayUnits === void 0) { useTickIntervalForDisplayUnits = false; }
31952 var formatter;
31953 if (dataType.dateTime) {
31954 if (isScalar) {
31955 var value = new Date(scaleDomain[0]);
31956 var value2 = new Date(scaleDomain[1]);
31957 // datetime with only one value needs to pass the same value
31958 // (from the original dataDomain value, not the adjusted scaleDomain)
31959 // so formatting works correctly.
31960 if (bestTickCount === 1)
31961 value = value2 = new Date(dataDomain[0]);
31962 // this will ignore the formatString and create one based on the smallest non-zero portion of the values supplied.
31963 formatter = visuals.valueFormatter.create({
31964 format: formatString,
31965 value: value,
31966 value2: value2,
31967 tickCount: bestTickCount,
31968 });
31969 }
31970 else {
31971 // Use the model formatString for ordinal datetime
31972 formatter = visuals.valueFormatter.createDefaultFormatter(formatString, true);
31973 }
31974 }
31975 else {
31976 if (getValueFn == null && !isScalar) {
31977 debug.assertFail('getValueFn must be supplied for ordinal tickValues');
31978 }
31979 if (useTickIntervalForDisplayUnits && isScalar && tickValues.length > 1) {
31980 var value1 = axisDisplayUnits ? axisDisplayUnits : tickValues[1] - tickValues[0];
31981 var options = {
31982 format: formatString,
31983 value: value1,
31984 value2: 0,
31985 allowFormatBeautification: true,
31986 };
31987 if (axisPrecision)
31988 options.precision = axisPrecision;
31989 else
31990 options.detectAxisPrecision = true;
31991 formatter = visuals.valueFormatter.create(options);
31992 }
31993 else {
31994 // do not use display units, just the basic value formatter
31995 // datetime is handled above, so we are ordinal and either boolean, numeric, or text.
31996 formatter = visuals.valueFormatter.createDefaultFormatter(formatString, true);
31997 }
31998 }
31999 return formatter;
32000 }
32001 AxisHelper.createFormatter = createFormatter;
32002 /**
32003 * Format the linear tick labels or the category labels.
32004 */
32005 function formatAxisTickValues(axis, tickValues, formatter, dataType, getValueFn) {
32006 var formattedTickValues = [];
32007 if (!getValueFn)
32008 getValueFn = function (data) { return data; };
32009 if (formatter) {
32010 axis.tickFormat(function (d) { return formatter.format(getValueFn(d, dataType)); });
32011 formattedTickValues = tickValues.map(function (d) { return formatter.format(getValueFn(d, dataType)); });
32012 }
32013 else {
32014 formattedTickValues = tickValues.map(function (d) { return getValueFn(d, dataType); });
32015 }
32016 return formattedTickValues;
32017 }
32018 function getMinTickValueInterval(formatString, columnType, is100Pct) {
32019 var isCustomFormat = formatString && !powerbi.NumberFormat.isStandardFormat(formatString);
32020 if (isCustomFormat) {
32021 var precision = powerbi.NumberFormat.getCustomFormatMetadata(formatString, true /*calculatePrecision*/).precision;
32022 if (formatString.indexOf('%') > -1)
32023 precision += 2; //percent values are multiplied by 100 during formatting
32024 return Math.pow(10, -precision);
32025 }
32026 else if (is100Pct)
32027 return 0.01;
32028 else if (columnType.integer)
32029 return 1;
32030 return 0;
32031 }
32032 AxisHelper.getMinTickValueInterval = getMinTickValueInterval;
32033 function createScalarDomain(data, userMin, userMax, axisType, ensureDomain) {
32034 debug.assertValue(data, 'data');
32035 if (data.length === 0) {
32036 return null;
32037 }
32038 var defaultMinX = d3.min(data, function (kv) { return d3.min(kv.data, function (d) { return d.categoryValue; }); });
32039 var defaultMaxX = d3.max(data, function (kv) { return d3.max(kv.data, function (d) { return d.categoryValue; }); });
32040 return combineDomain([userMin, userMax], [defaultMinX, defaultMaxX], ensureDomain);
32041 }
32042 /**
32043 * Creates a [min,max] from your Cartiesian data values.
32044 *
32045 * @param data The series array of CartesianDataPoints.
32046 * @param includeZero Columns and bars includeZero, line and scatter do not.
32047 */
32048 function createValueDomain(data, includeZero) {
32049 debug.assertValue(data, 'data');
32050 if (data.length === 0)
32051 return null;
32052 var minY = d3.min(data, function (kv) { return d3.min(kv.data, function (d) { return d.value; }); });
32053 var maxY = d3.max(data, function (kv) { return d3.max(kv.data, function (d) { return d.value; }); });
32054 if (includeZero)
32055 return [Math.min(minY, 0), Math.max(maxY, 0)];
32056 return [minY, maxY];
32057 }
32058 AxisHelper.createValueDomain = createValueDomain;
32059 function createOrdinalDomain(data) {
32060 if (_.isEmpty(data))
32061 return [];
32062 // each series shares the same categories for oridinal axes (even if a series has some nulls)
32063 var domain = [];
32064 var firstSeries = data[0];
32065 for (var _i = 0, _a = firstSeries.data; _i < _a.length; _i++) {
32066 var dp = _a[_i];
32067 if (!dp.highlight)
32068 domain.push(dp.categoryIndex);
32069 }
32070 return domain;
32071 }
32072 var LabelLayoutStrategy;
32073 (function (LabelLayoutStrategy) {
32074 function willLabelsFit(axisProperties, availableWidth, textMeasurer, properties) {
32075 var labels = axisProperties.values;
32076 if (labels.length === 0)
32077 return false;
32078 var labelMaxWidth = axisProperties.xLabelMaxWidth !== undefined
32079 ? axisProperties.xLabelMaxWidth
32080 : availableWidth / labels.length;
32081 return !labels.some(function (d) {
32082 properties.text = d;
32083 return textMeasurer(properties) > labelMaxWidth;
32084 });
32085 }
32086 LabelLayoutStrategy.willLabelsFit = willLabelsFit;
32087 function willLabelsWordBreak(axisProperties, margin, availableWidth, textWidthMeasurer, textHeightMeasurer, textTruncator, properties) {
32088 var labels = axisProperties.values;
32089 var labelMaxWidth = axisProperties.xLabelMaxWidth !== undefined
32090 ? axisProperties.xLabelMaxWidth
32091 : availableWidth / labels.length;
32092 var maxRotatedLength = margin.bottom / LabelLayoutStrategy.DefaultRotation.sine;
32093 var height = textHeightMeasurer(properties);
32094 var maxNumLines = Math.max(1, Math.floor(margin.bottom / height)); // TODO: not taking axis label into account
32095 if (labels.length === 0)
32096 return false;
32097 // If no break character and exceeds max width, word breaking will not work, return false
32098 var mustRotate = labels.some(function (label) {
32099 // Detect must rotate and return immediately
32100 properties.text = label;
32101 return !jsCommon.WordBreaker.hasBreakers(label) && textWidthMeasurer(properties) > labelMaxWidth;
32102 });
32103 if (mustRotate)
32104 return false;
32105 var moreWordBreakChars = labels.filter(function (label, index) {
32106 // ...otherwise compare rotation versus word breaking
32107 var allowedLengthProjectedOnXAxis =
32108 // Left margin is the width of Y axis.
32109 margin.left
32110 + axisProperties.outerPadding
32111 + axisProperties.categoryThickness * (index + 0.5)
32112 - LeftPadding;
32113 var allowedLength = allowedLengthProjectedOnXAxis / LabelLayoutStrategy.DefaultRotation.cosine;
32114 var rotatedLength = Math.min(allowedLength, maxRotatedLength);
32115 // Which shows more characters? Rotated or maxNumLines truncated to labelMaxWidth?
32116 var wordBreakChars = jsCommon.WordBreaker.splitByWidth(label, properties, textWidthMeasurer, labelMaxWidth, maxNumLines, textTruncator).join(' ');
32117 properties.text = label;
32118 var rotateChars = textTruncator(properties, rotatedLength);
32119 // prefer word break (>=) as it takes up less plot area
32120 return visuals.TextUtil.removeEllipses(wordBreakChars).length >= visuals.TextUtil.removeEllipses(rotateChars).length;
32121 });
32122 // prefer word break (>=) as it takes up less plot area
32123 return moreWordBreakChars.length >= Math.floor(labels.length / 2);
32124 }
32125 LabelLayoutStrategy.willLabelsWordBreak = willLabelsWordBreak;
32126 LabelLayoutStrategy.DefaultRotation = {
32127 sine: Math.sin(Math.PI * (35 / 180)),
32128 cosine: Math.cos(Math.PI * (35 / 180)),
32129 tangent: Math.tan(Math.PI * (35 / 180)),
32130 transform: 'rotate(-35)',
32131 dy: '-0.5em',
32132 };
32133 LabelLayoutStrategy.DefaultRotationWithScrollbar = {
32134 sine: Math.sin(Math.PI * (90 / 180)),
32135 cosine: Math.cos(Math.PI * (90 / 180)),
32136 tangent: Math.tan(Math.PI * (90 / 180)),
32137 transform: 'rotate(-90)',
32138 dy: '-0.8em',
32139 };
32140 function rotate(labelSelection, maxBottomMargin, textTruncator, textProperties, needRotate, needEllipsis, axisProperties, margin, scrollbarVisible) {
32141 var rotatedLength;
32142 var defaultRotation;
32143 if (scrollbarVisible)
32144 defaultRotation = LabelLayoutStrategy.DefaultRotationWithScrollbar;
32145 else
32146 defaultRotation = LabelLayoutStrategy.DefaultRotation;
32147 if (needRotate) {
32148 rotatedLength = maxBottomMargin / defaultRotation.sine;
32149 }
32150 labelSelection.each(function () {
32151 var axisLabel = d3.select(this);
32152 var labelText = axisLabel.text();
32153 textProperties.text = labelText;
32154 if (needRotate) {
32155 var textContentIndex = axisProperties.values.indexOf(this.textContent);
32156 var allowedLengthProjectedOnXAxis =
32157 // Left margin is the width of Y axis.
32158 margin.left
32159 + axisProperties.outerPadding
32160 + axisProperties.categoryThickness * (textContentIndex + 0.5);
32161 // Subtracting the left padding space from the allowed length.
32162 if (!scrollbarVisible)
32163 allowedLengthProjectedOnXAxis -= LeftPadding;
32164 // Truncate if scrollbar is visible or rotatedLength exceeds allowedLength
32165 var allowedLength = allowedLengthProjectedOnXAxis / defaultRotation.cosine;
32166 if (scrollbarVisible || needEllipsis || (allowedLength < rotatedLength)) {
32167 labelText = textTruncator(textProperties, Math.min(allowedLength, rotatedLength));
32168 axisLabel.text(labelText);
32169 }
32170 axisLabel.style('text-anchor', 'end')
32171 .attr({
32172 'dx': '-0.5em',
32173 'dy': defaultRotation.dy,
32174 'transform': defaultRotation.transform
32175 });
32176 }
32177 else {
32178 var newLabelText = textTruncator(textProperties, axisProperties.xLabelMaxWidth);
32179 if (newLabelText !== labelText)
32180 axisLabel.text(newLabelText);
32181 axisLabel.style('text-anchor', 'middle')
32182 .attr({
32183 'dx': '0em',
32184 'dy': '1em',
32185 'transform': 'rotate(0)'
32186 });
32187 }
32188 });
32189 }
32190 LabelLayoutStrategy.rotate = rotate;
32191 function wordBreak(text, axisProperties, maxHeight) {
32192 var allowedLength = axisProperties.xLabelMaxWidth;
32193 text.each(function () {
32194 var node = d3.select(this);
32195 // Reset style of text node
32196 node
32197 .style('text-anchor', 'middle')
32198 .attr({
32199 'dx': '0em',
32200 'dy': '1em',
32201 'transform': 'rotate(0)'
32202 });
32203 powerbi.TextMeasurementService.wordBreak(this, allowedLength, maxHeight);
32204 });
32205 }
32206 LabelLayoutStrategy.wordBreak = wordBreak;
32207 function clip(text, availableWidth, svgEllipsis) {
32208 if (text.size() === 0)
32209 return;
32210 text.each(function () {
32211 var text = d3.select(this);
32212 svgEllipsis(text[0][0], availableWidth);
32213 });
32214 }
32215 LabelLayoutStrategy.clip = clip;
32216 })(LabelLayoutStrategy = AxisHelper.LabelLayoutStrategy || (AxisHelper.LabelLayoutStrategy = {}));
32217 function createOrdinalScale(pixelSpan, dataDomain, outerPaddingRatio) {
32218 if (outerPaddingRatio === void 0) { outerPaddingRatio = 0; }
32219 debug.assert(outerPaddingRatio >= 0 && outerPaddingRatio < 4, 'outerPaddingRatio should be a value between zero and four');
32220 var scale = d3.scale.ordinal()
32221 .rangeBands([0, pixelSpan], visuals.CartesianChart.InnerPaddingRatio, outerPaddingRatio)
32222 .domain(dataDomain);
32223 return scale;
32224 }
32225 AxisHelper.createOrdinalScale = createOrdinalScale;
32226 function isLogScalePossible(domain, axisType) {
32227 if (domain == null)
32228 return false;
32229 if (isDateTime(axisType))
32230 return false;
32231 return (domain[0] > 0 && domain[1] > 0) || (domain[0] < 0 && domain[1] < 0); //doman must exclude 0
32232 }
32233 AxisHelper.isLogScalePossible = isLogScalePossible;
32234 //this function can return different scales e.g. log, linear
32235 // NOTE: export only for testing, do not access directly
32236 function createNumericalScale(axisScaleType, pixelSpan, dataDomain, dataType, outerPadding, niceCount, shouldClamp) {
32237 if (outerPadding === void 0) { outerPadding = 0; }
32238 if (axisScaleType === visuals.axisScale.log && isLogScalePossible(dataDomain, dataType)) {
32239 return createLogScale(pixelSpan, dataDomain, outerPadding, niceCount);
32240 }
32241 else {
32242 return createLinearScale(pixelSpan, dataDomain, outerPadding, niceCount, shouldClamp);
32243 }
32244 }
32245 AxisHelper.createNumericalScale = createNumericalScale;
32246 function createLogScale(pixelSpan, dataDomain, outerPadding, niceCount) {
32247 if (outerPadding === void 0) { outerPadding = 0; }
32248 debug.assert(isLogScalePossible(dataDomain), "dataDomain cannot include 0");
32249 var scale = d3.scale.log()
32250 .range([outerPadding, pixelSpan - outerPadding])
32251 .domain([dataDomain[0], dataDomain[1]])
32252 .clamp(true);
32253 if (niceCount) {
32254 scale.nice(niceCount);
32255 }
32256 return scale;
32257 }
32258 // NOTE: export only for testing, do not access directly
32259 function createLinearScale(pixelSpan, dataDomain, outerPadding, niceCount, shouldClamp) {
32260 if (outerPadding === void 0) { outerPadding = 0; }
32261 var scale = d3.scale.linear()
32262 .range([outerPadding, pixelSpan - outerPadding])
32263 .domain([dataDomain[0], dataDomain[1]])
32264 .clamp(shouldClamp);
32265 // .nice(undefined) still modifies the scale boundaries, and for datetime this messes things up.
32266 // we use millisecond ticks since epoch for datetime, so we don't want any "nice" with numbers like 17398203392.
32267 if (niceCount) {
32268 scale.nice(niceCount);
32269 }
32270 return scale;
32271 }
32272 AxisHelper.createLinearScale = createLinearScale;
32273 function getRangeForColumn(sizeColumn) {
32274 var result = {};
32275 if (sizeColumn) {
32276 result.min = sizeColumn.min == null
32277 ? sizeColumn.minLocal == null ? d3.min(sizeColumn.values) : sizeColumn.minLocal
32278 : sizeColumn.min;
32279 result.max = sizeColumn.max == null
32280 ? sizeColumn.maxLocal == null ? d3.max(sizeColumn.values) : sizeColumn.maxLocal
32281 : sizeColumn.max;
32282 }
32283 return result;
32284 }
32285 AxisHelper.getRangeForColumn = getRangeForColumn;
32286 /**
32287 * Set customized domain, but don't change when nothing is set
32288 */
32289 function applyCustomizedDomain(customizedDomain, forcedDomain) {
32290 var domain = [undefined, undefined];
32291 if (forcedDomain && forcedDomain.length === 2) {
32292 domain = [forcedDomain[0], forcedDomain[1]];
32293 }
32294 if (customizedDomain && customizedDomain.length === 2) {
32295 if (customizedDomain[0] != null) {
32296 domain[0] = customizedDomain[0];
32297 }
32298 if (customizedDomain[1] != null) {
32299 domain[1] = customizedDomain[1];
32300 }
32301 }
32302 if (domain[0] == null && domain[1] == null) {
32303 return forcedDomain; //return untouched object
32304 }
32305 //do extra check to see if the user input was valid with the merged axis values.
32306 if (domain[0] != null && domain[1] != null) {
32307 if (domain[0] > domain[1]) {
32308 return forcedDomain;
32309 }
32310 }
32311 return domain;
32312 }
32313 AxisHelper.applyCustomizedDomain = applyCustomizedDomain;
32314 /**
32315 * Combine the forced domain with the actual domain if one of the values was set.
32316 * The forcedDomain is in 1st priority. Extends the domain if the any reference point requires it.
32317 */
32318 function combineDomain(forcedDomain, domain, ensureDomain) {
32319 var combinedDomain = domain ? [domain[0], domain[1]] : [];
32320 if (ensureDomain) {
32321 if (combinedDomain[0] == null || ensureDomain.min < combinedDomain[0])
32322 combinedDomain[0] = ensureDomain.min;
32323 if (combinedDomain[1] == null || ensureDomain.max > combinedDomain[1])
32324 combinedDomain[1] = ensureDomain.max;
32325 }
32326 var domainBeforeForced = [combinedDomain[0], combinedDomain[1]];
32327 if (forcedDomain && forcedDomain.length === 2) {
32328 if (forcedDomain[0] != null) {
32329 combinedDomain[0] = forcedDomain[0];
32330 }
32331 if (forcedDomain[1] != null) {
32332 combinedDomain[1] = forcedDomain[1];
32333 }
32334 if (combinedDomain[0] > combinedDomain[1]) {
32335 combinedDomain = domainBeforeForced; //this is invalid, so take the original domain considering the values and the reference line
32336 }
32337 }
32338 return combinedDomain;
32339 }
32340 AxisHelper.combineDomain = combineDomain;
32341 function createAxisLabel(properties, label, unitType, y2) {
32342 if (y2 === void 0) { y2 = false; }
32343 var propertyName = y2 ? 'secAxisStyle' : 'axisStyle';
32344 if (!properties || !properties[propertyName]) {
32345 return label;
32346 }
32347 var modifiedLabel;
32348 if (properties[propertyName] === visuals.axisStyle.showBoth) {
32349 modifiedLabel = label + ' (' + unitType + ')'; //todo: localize
32350 }
32351 else if (properties[propertyName] === visuals.axisStyle.showUnitOnly) {
32352 modifiedLabel = unitType;
32353 }
32354 else {
32355 modifiedLabel = label;
32356 }
32357 return modifiedLabel;
32358 }
32359 AxisHelper.createAxisLabel = createAxisLabel;
32360 function scaleShouldClamp(combinedDomain, domain) {
32361 if (!combinedDomain || !domain || combinedDomain.length < 2 || domain.length < 2)
32362 return false;
32363 //when the start or end is different, clamp it
32364 return combinedDomain[0] !== domain[0] || combinedDomain[1] !== domain[1];
32365 }
32366 AxisHelper.scaleShouldClamp = scaleShouldClamp;
32367 function normalizeNonFiniteNumber(value) {
32368 if (isNaN(value))
32369 return null;
32370 else if (value === Number.POSITIVE_INFINITY)
32371 return Number.MAX_VALUE;
32372 else if (value === Number.NEGATIVE_INFINITY)
32373 return -Number.MAX_VALUE;
32374 return value;
32375 }
32376 AxisHelper.normalizeNonFiniteNumber = normalizeNonFiniteNumber;
32377 /**
32378 * Indicates whether the number is power of 10.
32379 */
32380 function powerOfTen(d) {
32381 var value = Math.abs(d);
32382 // formula log2(Y)/log2(10) = log10(Y)
32383 // because double issues this won't return exact value
32384 // we need to ceil it to nearest number.
32385 var log10 = Math.log(value) / Math.LN10;
32386 log10 = Math.ceil(log10 - 1e-12);
32387 return value / Math.pow(10, log10) === 1;
32388 }
32389 AxisHelper.powerOfTen = powerOfTen;
32390 })(AxisHelper = visuals.AxisHelper || (visuals.AxisHelper = {}));
32391 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
32392})(powerbi || (powerbi = {}));
32393/*
32394* Power BI Visualizations
32395*
32396* Copyright (c) Microsoft Corporation
32397* All rights reserved.
32398* MIT License
32399*
32400* Permission is hereby granted, free of charge, to any person obtaining a copy
32401* of this software and associated documentation files (the ""Software""), to deal
32402* in the Software without restriction, including without limitation the rights
32403* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32404* copies of the Software, and to permit persons to whom the Software is
32405* furnished to do so, subject to the following conditions:
32406*
32407* The above copyright notice and this permission notice shall be included in
32408* all copies or substantial portions of the Software.
32409*
32410* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32411* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32412* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32413* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32414* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32415* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32416* THE SOFTWARE.
32417*/
32418var powerbi;
32419(function (powerbi) {
32420 var visuals;
32421 (function (visuals) {
32422 var ShapeFactory;
32423 (function (ShapeFactory) {
32424 var ShapeFactoryConsts;
32425 (function (ShapeFactoryConsts) {
32426 ShapeFactoryConsts.PaddingConstRatio = 0.01;
32427 ShapeFactoryConsts.TrianglePaddingConstRatio = 0.15;
32428 ShapeFactoryConsts.TriangleEndPaddingConstRatio = 0.85;
32429 ShapeFactoryConsts.ShapeConstRatio = 1.0 - (ShapeFactoryConsts.PaddingConstRatio * 2);
32430 ShapeFactoryConsts.SmallPaddingConstValue = 10;
32431 ShapeFactoryConsts.OvalRadiusConst = 2;
32432 ShapeFactoryConsts.OvalRadiusConstPadding = 0.2;
32433 ShapeFactoryConsts.ArrowLeftHeadPoint = { x: 0.05, y: 0.42 };
32434 ShapeFactoryConsts.ArrowMiddleHeadPoint = { x: 0.5, y: 0.016 };
32435 ShapeFactoryConsts.ArrowRightHeadPoint = { x: 0.95, y: 0.42 };
32436 ShapeFactoryConsts.ArrowRightMiddleHeadPoint = { x: 0.764, y: 0.42 };
32437 ShapeFactoryConsts.ArrowBottomRightPoint = { x: 0.764, y: 0.993 };
32438 ShapeFactoryConsts.ArrowBottomLeftPoint = { x: 0.246, y: 0.993 };
32439 ShapeFactoryConsts.ArrowLeftMiddleHeadPoint = { x: 0.246, y: 0.42 };
32440 })(ShapeFactoryConsts = ShapeFactory.ShapeFactoryConsts || (ShapeFactory.ShapeFactoryConsts = {}));
32441 /** this function creates a rectangle svg */
32442 function createRectangle(data, viewportHeight, viewportWidth, selectedElement, degrees) {
32443 var x = (viewportWidth * ShapeFactoryConsts.PaddingConstRatio) + (data.lineWeight / 2);
32444 var y = (viewportHeight * ShapeFactoryConsts.PaddingConstRatio) + (data.lineWeight / 2);
32445 var width = (viewportWidth * ShapeFactoryConsts.ShapeConstRatio) - (data.lineWeight);
32446 var height = (viewportHeight * ShapeFactoryConsts.ShapeConstRatio) - (data.lineWeight);
32447 var attrs = { x: x, y: y, width: width, height: height, rx: data.roundEdge, ry: data.roundEdge };
32448 var scale = getScale(width, height, degrees);
32449 createShape(data, viewportHeight, viewportWidth, selectedElement, degrees, scale, 'rect', attrs);
32450 }
32451 ShapeFactory.createRectangle = createRectangle;
32452 /** this function creates a oval svg */
32453 function createOval(data, viewportHeight, viewportWidth, selectedElement, degrees) {
32454 var widthForCircle = (viewportWidth / ShapeFactoryConsts.OvalRadiusConst).toString();
32455 var heightForCircle = (viewportHeight / ShapeFactoryConsts.OvalRadiusConst).toString();
32456 var radiusXForCircle = ((viewportWidth / (ShapeFactoryConsts.OvalRadiusConst + ShapeFactoryConsts.OvalRadiusConstPadding)) - data.lineWeight);
32457 var radiusYForCircle = ((viewportHeight / (ShapeFactoryConsts.OvalRadiusConst + ShapeFactoryConsts.OvalRadiusConstPadding)) - data.lineWeight);
32458 var attrs = { cx: widthForCircle, cy: heightForCircle, rx: radiusXForCircle, ry: radiusYForCircle };
32459 var scale = getScale(viewportWidth, viewportHeight, degrees);
32460 createShape(data, viewportHeight, viewportWidth, selectedElement, degrees, scale, 'ellipse', attrs);
32461 }
32462 ShapeFactory.createOval = createOval;
32463 /** this function creates a line svg */
32464 function createLine(data, viewportHeight, viewportWidth, selectedElement, degrees) {
32465 var x1, y1, x2, y2;
32466 var width = (viewportWidth - ShapeFactoryConsts.SmallPaddingConstValue) - ShapeFactoryConsts.SmallPaddingConstValue;
32467 var height = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue) - ShapeFactoryConsts.SmallPaddingConstValue;
32468 var ratio;
32469 if (degrees <= 45) {
32470 ratio = degrees / 90;
32471 x1 = viewportWidth / 2 + width * ratio;
32472 y1 = ShapeFactoryConsts.SmallPaddingConstValue;
32473 x2 = viewportWidth / 2 - width * ratio;
32474 y2 = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue);
32475 }
32476 else if (degrees <= 135) {
32477 ratio = (degrees - 45) / 90;
32478 x1 = (viewportWidth - ShapeFactoryConsts.SmallPaddingConstValue);
32479 y1 = ShapeFactoryConsts.SmallPaddingConstValue + height * ratio;
32480 x2 = ShapeFactoryConsts.SmallPaddingConstValue;
32481 y2 = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue) - height * ratio;
32482 }
32483 else if (degrees <= 225) {
32484 ratio = (degrees - 135) / 90;
32485 x1 = (viewportWidth - ShapeFactoryConsts.SmallPaddingConstValue) - width * ratio;
32486 y1 = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue);
32487 x2 = ShapeFactoryConsts.SmallPaddingConstValue + width * ratio;
32488 y2 = ShapeFactoryConsts.SmallPaddingConstValue;
32489 }
32490 else if (degrees <= 315) {
32491 ratio = (degrees - 225) / 90;
32492 x1 = ShapeFactoryConsts.SmallPaddingConstValue;
32493 y1 = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue) - height * ratio;
32494 x2 = (viewportWidth - ShapeFactoryConsts.SmallPaddingConstValue);
32495 y2 = ShapeFactoryConsts.SmallPaddingConstValue + height * ratio;
32496 }
32497 else if (degrees <= 360) {
32498 ratio = (degrees - 315) / 90;
32499 x1 = ShapeFactoryConsts.SmallPaddingConstValue + width * ratio;
32500 y1 = ShapeFactoryConsts.SmallPaddingConstValue;
32501 x2 = (viewportWidth - ShapeFactoryConsts.SmallPaddingConstValue) - width * ratio;
32502 y2 = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue);
32503 }
32504 // create the inner path with the wanted shape
32505 selectedElement
32506 .append('svg')
32507 .attr({
32508 width: viewportWidth,
32509 height: viewportHeight
32510 })
32511 .append('line')
32512 .attr({
32513 x1: x1,
32514 y1: y1,
32515 x2: x2,
32516 y2: y2,
32517 })
32518 .style({
32519 'vector-effect': 'non-scaling-stroke',
32520 'stroke-width': data.lineWeight + 'px',
32521 'stroke-opacity': (100 - data.lineTransparency) / 100,
32522 'stroke': data.lineColor
32523 });
32524 }
32525 ShapeFactory.createLine = createLine;
32526 /** this function creates a arrow svg */
32527 function createUpArrow(data, viewportHeight, viewportWidth, selectedElement, degrees) {
32528 var lineWeight = data.lineWeight;
32529 var viewportHeightWeight = viewportHeight - lineWeight;
32530 var viewportWidthWeight = viewportWidth - lineWeight;
32531 var arrowPoints = [
32532 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowLeftHeadPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowLeftHeadPoint.y).toString() },
32533 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowMiddleHeadPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowMiddleHeadPoint.y).toString() },
32534 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowRightHeadPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowRightHeadPoint.y).toString() },
32535 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowRightMiddleHeadPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowRightMiddleHeadPoint.y).toString() },
32536 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowBottomRightPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowBottomRightPoint.y).toString() },
32537 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowBottomLeftPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowBottomLeftPoint.y).toString() },
32538 { 'x': (viewportWidthWeight * ShapeFactoryConsts.ArrowLeftMiddleHeadPoint.x).toString(), 'y': (viewportHeightWeight * ShapeFactoryConsts.ArrowLeftMiddleHeadPoint.y).toString() },
32539 ];
32540 // create the inner path with the wanted shape
32541 createPathFromArray(data, arrowPoints, selectedElement, viewportHeight, viewportWidth, degrees);
32542 }
32543 ShapeFactory.createUpArrow = createUpArrow;
32544 /** this function creates a triangle svg */
32545 function createTriangle(data, viewportHeight, viewportWidth, selectedElement, degrees) {
32546 var lineWeight = data.lineWeight;
32547 // remove the basic line weight
32548 if (lineWeight > 3) {
32549 lineWeight -= 3;
32550 }
32551 var firstPointX = ((viewportWidth + lineWeight) * ShapeFactoryConsts.TrianglePaddingConstRatio);
32552 var firstPointY = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue - lineWeight) < 0 ?
32553 (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue) : (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue - lineWeight);
32554 var secondPointY = ((viewportHeight + lineWeight) * ShapeFactoryConsts.TrianglePaddingConstRatio);
32555 var thirdPointX = ((viewportWidth - lineWeight) * ShapeFactoryConsts.TriangleEndPaddingConstRatio) < 0 ?
32556 (viewportWidth * ShapeFactoryConsts.TriangleEndPaddingConstRatio) : ((viewportWidth - lineWeight) * ShapeFactoryConsts.TriangleEndPaddingConstRatio);
32557 var thirdPointY = (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue - lineWeight) < 0 ?
32558 (viewportHeight - ShapeFactoryConsts.SmallPaddingConstValue) : (viewportHeight - lineWeight - ShapeFactoryConsts.SmallPaddingConstValue);
32559 var secondPointX = ((firstPointX + thirdPointX) / 2);
32560 if (firstPointX < 10) {
32561 firstPointX = ShapeFactoryConsts.SmallPaddingConstValue;
32562 }
32563 if (secondPointY < 10) {
32564 secondPointY = ShapeFactoryConsts.SmallPaddingConstValue;
32565 }
32566 var trianglePoints = [
32567 { 'x': firstPointX, 'y': firstPointY },
32568 { 'x': secondPointX, 'y': secondPointY },
32569 { 'x': thirdPointX, 'y': thirdPointY },
32570 ];
32571 createPathFromArray(data, trianglePoints, selectedElement, viewportHeight, viewportWidth, degrees);
32572 }
32573 ShapeFactory.createTriangle = createTriangle;
32574 /** this funcion adds a path to an svg element from an array of points (x,y) */
32575 function createPathFromArray(data, points, selectedElement, viewportHeight, viewportWidth, degrees) {
32576 var lineFunction = d3.svg.line()
32577 .x(function (d) { return d.x; })
32578 .y(function (d) { return d.y; })
32579 .interpolate('linear');
32580 var attrs = { d: lineFunction(points) + ' Z' };
32581 var scale = getScale(viewportWidth, viewportHeight, degrees);
32582 createShape(data, viewportHeight, viewportWidth, selectedElement, degrees, scale, 'path', attrs);
32583 }
32584 function createShape(data, viewportHeight, viewportWidth, selectedElement, degrees, scale, shapeType, shapeAttrs) {
32585 selectedElement
32586 .append('div')
32587 .style({
32588 'transform': 'rotate(' + degrees + 'deg) scale(' + scale + ')',
32589 'transform-origin': 'center',
32590 // for testing with phantomjs we need the webkit prefix
32591 '-webkit-transform': 'rotate(' + degrees + 'deg) scale(' + scale + ')',
32592 '-webkit-transform-origin': 'center',
32593 'width': viewportWidth + 'px',
32594 'height': viewportHeight + 'px'
32595 })
32596 .append('svg')
32597 .attr({
32598 width: viewportWidth,
32599 height: viewportHeight
32600 })
32601 .append(shapeType)
32602 .attr(shapeAttrs)
32603 .style({
32604 'vector-effect': 'non-scaling-stroke',
32605 'stroke-width': data.lineWeight + 'px',
32606 'stroke': data.lineColor,
32607 'stroke-opacity': (100 - data.lineTransparency) / 100,
32608 'fill': data.fillColor,
32609 'fill-opacity': data.showFill === true ? ((100 - data.shapeTransparency) / 100) : 0
32610 });
32611 }
32612 // this function return the scale to add to the shape.
32613 // it calculate it by the ratio of the original shape's diagonal and the shape's diagonal after rotate (the maximum diagonal that still fit to the container).
32614 // it calculate the shape's diagonal by the rotate angle.
32615 function getScale(width, height, degrees) {
32616 var originalWidth = width;
32617 var originalHeight = height;
32618 var offsetAngle = Math.atan2(height, width);
32619 var originalFactor = Math.sqrt(Math.pow(height, 2) + Math.pow(width, 2));
32620 var radians = (degrees / 180) * Math.PI;
32621 if (width >= height) {
32622 if (degrees < 90) {
32623 radians += offsetAngle;
32624 }
32625 else if (degrees < 180) {
32626 radians -= offsetAngle;
32627 }
32628 else if (degrees < 270) {
32629 radians += offsetAngle;
32630 }
32631 else {
32632 radians -= offsetAngle;
32633 }
32634 return (originalHeight / Math.abs(Math.sin(radians))) / originalFactor;
32635 }
32636 else {
32637 if (degrees < 90) {
32638 radians -= offsetAngle;
32639 }
32640 else if (degrees < 180) {
32641 radians += offsetAngle;
32642 }
32643 else if (degrees < 270) {
32644 radians -= offsetAngle;
32645 }
32646 else {
32647 radians += offsetAngle;
32648 }
32649 return (originalWidth / Math.abs(Math.cos(radians))) / originalFactor;
32650 }
32651 }
32652 })(ShapeFactory = visuals.ShapeFactory || (visuals.ShapeFactory = {}));
32653 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
32654})(powerbi || (powerbi = {}));
32655/*
32656 * Power BI Visualizations
32657 *
32658 * Copyright (c) Microsoft Corporation
32659 * All rights reserved.
32660 * MIT License
32661 *
32662 * Permission is hereby granted, free of charge, to any person obtaining a copy
32663 * of this software and associated documentation files (the ""Software""), to deal
32664 * in the Software without restriction, including without limitation the rights
32665 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32666 * copies of the Software, and to permit persons to whom the Software is
32667 * furnished to do so, subject to the following conditions:
32668 *
32669 * The above copyright notice and this permission notice shall be included in
32670 * all copies or substantial portions of the Software.
32671 *
32672 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32673 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32674 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32675 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32676 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32677 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32678 * THE SOFTWARE.
32679 */
32680var powerbi;
32681(function (powerbi) {
32682 var visuals;
32683 (function (visuals) {
32684 var CartesianHelper;
32685 (function (CartesianHelper) {
32686 function getCategoryAxisProperties(dataViewMetadata, axisTitleOnByDefault) {
32687 var toReturn = {};
32688 if (!dataViewMetadata)
32689 return toReturn;
32690 var objects = dataViewMetadata.objects;
32691 if (objects) {
32692 var categoryAxisObject = objects['categoryAxis'];
32693 if (categoryAxisObject) {
32694 toReturn = {
32695 show: categoryAxisObject['show'],
32696 axisType: categoryAxisObject['axisType'],
32697 axisScale: categoryAxisObject['axisScale'],
32698 start: categoryAxisObject['start'],
32699 end: categoryAxisObject['end'],
32700 showAxisTitle: categoryAxisObject['showAxisTitle'] == null ? axisTitleOnByDefault : categoryAxisObject['showAxisTitle'],
32701 axisStyle: categoryAxisObject['axisStyle'],
32702 labelColor: categoryAxisObject['labelColor'],
32703 labelDisplayUnits: categoryAxisObject['labelDisplayUnits'],
32704 labelPrecision: categoryAxisObject['labelPrecision'],
32705 duration: categoryAxisObject['duration'],
32706 };
32707 }
32708 }
32709 return toReturn;
32710 }
32711 CartesianHelper.getCategoryAxisProperties = getCategoryAxisProperties;
32712 function getValueAxisProperties(dataViewMetadata, axisTitleOnByDefault) {
32713 var toReturn = {};
32714 if (!dataViewMetadata)
32715 return toReturn;
32716 var objects = dataViewMetadata.objects;
32717 if (objects) {
32718 var valueAxisObject = objects['valueAxis'];
32719 if (valueAxisObject) {
32720 toReturn = {
32721 show: valueAxisObject['show'],
32722 position: valueAxisObject['position'],
32723 axisScale: valueAxisObject['axisScale'],
32724 start: valueAxisObject['start'],
32725 end: valueAxisObject['end'],
32726 showAxisTitle: valueAxisObject['showAxisTitle'] == null ? axisTitleOnByDefault : valueAxisObject['showAxisTitle'],
32727 axisStyle: valueAxisObject['axisStyle'],
32728 labelColor: valueAxisObject['labelColor'],
32729 labelDisplayUnits: valueAxisObject['labelDisplayUnits'],
32730 labelPrecision: valueAxisObject['labelPrecision'],
32731 secShow: valueAxisObject['secShow'],
32732 secPosition: valueAxisObject['secPosition'],
32733 secAxisScale: valueAxisObject['secAxisScale'],
32734 secStart: valueAxisObject['secStart'],
32735 secEnd: valueAxisObject['secEnd'],
32736 secShowAxisTitle: valueAxisObject['secShowAxisTitle'],
32737 secAxisStyle: valueAxisObject['secAxisStyle'],
32738 secLabelColor: valueAxisObject['secLabelColor'],
32739 secLabelDisplayUnits: valueAxisObject['secLabelDisplayUnits'],
32740 secLabelPrecision: valueAxisObject['secLabelPrecision'],
32741 };
32742 }
32743 }
32744 return toReturn;
32745 }
32746 CartesianHelper.getValueAxisProperties = getValueAxisProperties;
32747 function isScalar(isScalar, xAxisCardProperties) {
32748 if (isScalar) {
32749 //now check what the user wants
32750 isScalar = xAxisCardProperties && xAxisCardProperties['axisType'] ? xAxisCardProperties['axisType'] === visuals.axisType.scalar : true;
32751 }
32752 return isScalar;
32753 }
32754 CartesianHelper.isScalar = isScalar;
32755 function getPrecision(precision) {
32756 if (precision != null) {
32757 if (precision < 0) {
32758 return 0;
32759 }
32760 return precision;
32761 }
32762 return null;
32763 }
32764 CartesianHelper.getPrecision = getPrecision;
32765 function lookupXValue(data, index, type, isScalar) {
32766 debug.assertValue(data, 'data');
32767 debug.assertValue(type, 'type');
32768 var isDateTime = visuals.AxisHelper.isDateTime(type);
32769 if (isScalar) {
32770 if (isDateTime)
32771 return new Date(index);
32772 // index is the numeric value
32773 return index;
32774 }
32775 if (type.text) {
32776 debug.assert(index < data.categories.length, 'category index out of range');
32777 return data.categories[index];
32778 }
32779 if (data && data.series && data.series.length > 0) {
32780 var firstSeries = data.series[0];
32781 if (firstSeries) {
32782 var seriesValues = firstSeries.data;
32783 if (seriesValues) {
32784 if (data.hasHighlights)
32785 index = index * 2;
32786 var dataAtIndex = seriesValues[index];
32787 if (dataAtIndex) {
32788 if (isDateTime && dataAtIndex.categoryValue != null)
32789 return new Date(dataAtIndex.categoryValue);
32790 return dataAtIndex.categoryValue;
32791 }
32792 }
32793 }
32794 }
32795 return index;
32796 }
32797 CartesianHelper.lookupXValue = lookupXValue;
32798 function findMaxCategoryIndex(series) {
32799 if (_.isEmpty(series)) {
32800 return 0;
32801 }
32802 var maxCategoryIndex = 0;
32803 for (var _i = 0, series_1 = series; _i < series_1.length; _i++) {
32804 var singleSeries = series_1[_i];
32805 if (!_.isEmpty(singleSeries.data)) {
32806 var lastIndex = singleSeries.data[singleSeries.data.length - 1].categoryIndex;
32807 maxCategoryIndex = Math.max(lastIndex, maxCategoryIndex);
32808 }
32809 }
32810 return maxCategoryIndex;
32811 }
32812 CartesianHelper.findMaxCategoryIndex = findMaxCategoryIndex;
32813 })(CartesianHelper = visuals.CartesianHelper || (visuals.CartesianHelper = {}));
32814 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
32815})(powerbi || (powerbi = {}));
32816/*
32817 * Power BI Visualizations
32818 *
32819 * Copyright (c) Microsoft Corporation
32820 * All rights reserved.
32821 * MIT License
32822 *
32823 * Permission is hereby granted, free of charge, to any person obtaining a copy
32824 * of this software and associated documentation files (the ""Software""), to deal
32825 * in the Software without restriction, including without limitation the rights
32826 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32827 * copies of the Software, and to permit persons to whom the Software is
32828 * furnished to do so, subject to the following conditions:
32829 *
32830 * The above copyright notice and this permission notice shall be included in
32831 * all copies or substantial portions of the Software.
32832 *
32833 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32834 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32835 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32836 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32837 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32838 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32839 * THE SOFTWARE.
32840 */
32841var powerbi;
32842(function (powerbi) {
32843 var visuals;
32844 (function (visuals) {
32845 var SQExprShortSerializer = powerbi.data.SQExprShortSerializer;
32846 var ColorHelper = (function () {
32847 function ColorHelper(colors, fillProp, defaultDataPointColor) {
32848 this.colors = colors;
32849 this.fillProp = fillProp;
32850 this.defaultDataPointColor = defaultDataPointColor;
32851 this.defaultColorScale = colors.getNewColorScale();
32852 }
32853 /**
32854 * Gets the color for the given series value.
32855 * If no explicit color or default color has been set then the color is
32856 * allocated from the color scale for this series.
32857 */
32858 ColorHelper.prototype.getColorForSeriesValue = function (objects, fieldIds, value) {
32859 return (this.fillProp && powerbi.DataViewObjects.getFillColor(objects, this.fillProp))
32860 || this.defaultDataPointColor
32861 || this.getColorScaleForSeries(fieldIds).getColor(value).value;
32862 };
32863 /**
32864 * Gets the color scale for the given series.
32865 */
32866 ColorHelper.prototype.getColorScaleForSeries = function (fieldIds) {
32867 return this.colors.getColorScaleByKey(SQExprShortSerializer.serializeArray(fieldIds || []));
32868 };
32869 /**
32870 * Gets the color for the given measure.
32871 */
32872 ColorHelper.prototype.getColorForMeasure = function (objects, measureKey) {
32873 // Note, this allocates the color from the scale regardless of if we use it or not which helps keep colors stable.
32874 var scaleColor = this.defaultColorScale.getColor(measureKey).value;
32875 return (this.fillProp && powerbi.DataViewObjects.getFillColor(objects, this.fillProp))
32876 || this.defaultDataPointColor
32877 || scaleColor;
32878 };
32879 ColorHelper.normalizeSelector = function (selector, isSingleSeries) {
32880 debug.assertAnyValue(selector, 'selector');
32881 // For dynamic series charts, colors are set per category. So, exclude any measure (metadata repetition) from the selector.
32882 if (selector && (isSingleSeries || selector.data))
32883 return { data: selector.data };
32884 return selector;
32885 };
32886 return ColorHelper;
32887 }());
32888 visuals.ColorHelper = ColorHelper;
32889 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
32890})(powerbi || (powerbi = {}));
32891/*
32892 * Power BI Visualizations
32893 *
32894 * Copyright (c) Microsoft Corporation
32895 * All rights reserved.
32896 * MIT License
32897 *
32898 * Permission is hereby granted, free of charge, to any person obtaining a copy
32899 * of this software and associated documentation files (the ""Software""), to deal
32900 * in the Software without restriction, including without limitation the rights
32901 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32902 * copies of the Software, and to permit persons to whom the Software is
32903 * furnished to do so, subject to the following conditions:
32904 *
32905 * The above copyright notice and this permission notice shall be included in
32906 * all copies or substantial portions of the Software.
32907 *
32908 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32909 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32910 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32911 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32912 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32913 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32914 * THE SOFTWARE.
32915 */
32916var powerbi;
32917(function (powerbi) {
32918 var visuals;
32919 (function (visuals) {
32920 var rectName = 'rect';
32921 var ColumnUtil;
32922 (function (ColumnUtil) {
32923 ColumnUtil.DimmedOpacity = 0.4;
32924 ColumnUtil.DefaultOpacity = 1.0;
32925 function applyUserMinMax(isScalar, dataView, xAxisCardProperties) {
32926 if (isScalar) {
32927 var min = xAxisCardProperties['start'];
32928 var max = xAxisCardProperties['end'];
32929 return ColumnUtil.transformDomain(dataView, min, max);
32930 }
32931 return dataView;
32932 }
32933 ColumnUtil.applyUserMinMax = applyUserMinMax;
32934 function transformDomain(dataView, min, max) {
32935 if (!dataView.categories || !dataView.values || dataView.categories.length === 0 || dataView.values.length === 0)
32936 return dataView; // no need to do something when there are no categories
32937 if (typeof min !== "number" && typeof max !== "number")
32938 return dataView; //user did not set min max, nothing to do here
32939 var category = dataView.categories[0]; //at the moment we only support one category
32940 var categoryValues = category.values;
32941 var categoryObjects = category.objects;
32942 if (!categoryValues || !categoryObjects)
32943 return dataView;
32944 var newcategoryValues = [];
32945 var newValues = [];
32946 var newObjects = [];
32947 //get new min max
32948 if (typeof min !== "number") {
32949 min = categoryValues[0];
32950 }
32951 if (typeof max !== "number") {
32952 max = categoryValues[categoryValues.length - 1];
32953 }
32954 //don't allow this
32955 if (min > max)
32956 return dataView;
32957 //build measure array
32958 for (var j = 0, len = dataView.values.length; j < len; j++) {
32959 newValues.push([]);
32960 }
32961 for (var t = 0, len = categoryValues.length; t < len; t++) {
32962 if (categoryValues[t] >= min && categoryValues[t] <= max) {
32963 newcategoryValues.push(categoryValues[t]);
32964 if (categoryObjects) {
32965 newObjects.push(categoryObjects[t]);
32966 }
32967 //on each measure set the new range
32968 if (dataView.values) {
32969 for (var k = 0; k < dataView.values.length; k++) {
32970 newValues[k].push(dataView.values[k].values[t]);
32971 }
32972 }
32973 }
32974 }
32975 //don't write directly to dataview
32976 var resultDataView = powerbi.Prototype.inherit(dataView);
32977 var resultDataViewValues = resultDataView.values = powerbi.Prototype.inherit(resultDataView.values);
32978 var resultDataViewCategories = resultDataView.categories = powerbi.Prototype.inherit(dataView.categories);
32979 var resultDataViewCategories0 = resultDataView.categories[0] = powerbi.Prototype.inherit(resultDataViewCategories[0]);
32980 resultDataViewCategories0.values = newcategoryValues;
32981 //only if we had objects, then you set the new objects
32982 if (resultDataViewCategories0.objects) {
32983 resultDataViewCategories0.objects = newObjects;
32984 }
32985 //update measure array
32986 for (var t = 0, len = dataView.values.length; t < len; t++) {
32987 var measureArray = resultDataViewValues[t] = powerbi.Prototype.inherit(resultDataViewValues[t]);
32988 measureArray.values = newValues[t];
32989 }
32990 return resultDataView;
32991 }
32992 ColumnUtil.transformDomain = transformDomain;
32993 function getCategoryAxis(data, size, layout, isVertical, forcedXMin, forcedXMax, axisScaleType, axisDisplayUnits, axisPrecision, ensureXDomain) {
32994 var categoryThickness = layout.categoryThickness;
32995 var isScalar = layout.isScalar;
32996 var outerPaddingRatio = layout.outerPaddingRatio;
32997 var domain = visuals.AxisHelper.createDomain(data.series, data.categoryMetadata ? data.categoryMetadata.type : powerbi.ValueType.fromDescriptor({ text: true }), isScalar, [forcedXMin, forcedXMax], ensureXDomain);
32998 var axisProperties = visuals.AxisHelper.createAxis({
32999 pixelSpan: size,
33000 dataDomain: domain,
33001 metaDataColumn: data.categoryMetadata,
33002 formatString: visuals.valueFormatter.getFormatString(data.categoryMetadata, visuals.columnChartProps.general.formatString),
33003 outerPadding: categoryThickness * outerPaddingRatio,
33004 isCategoryAxis: true,
33005 isScalar: isScalar,
33006 isVertical: isVertical,
33007 categoryThickness: categoryThickness,
33008 useTickIntervalForDisplayUnits: true,
33009 getValueFn: function (index, type) { return visuals.CartesianHelper.lookupXValue(data, index, type, isScalar); },
33010 scaleType: axisScaleType,
33011 axisDisplayUnits: axisDisplayUnits,
33012 axisPrecision: axisPrecision
33013 });
33014 // intentionally updating the input layout by ref
33015 layout.categoryThickness = axisProperties.categoryThickness;
33016 return axisProperties;
33017 }
33018 ColumnUtil.getCategoryAxis = getCategoryAxis;
33019 function applyInteractivity(columns, onDragStart) {
33020 debug.assertValue(columns, 'columns');
33021 if (onDragStart) {
33022 columns
33023 .attr('draggable', 'true')
33024 .on('dragstart', onDragStart);
33025 }
33026 }
33027 ColumnUtil.applyInteractivity = applyInteractivity;
33028 function getFillOpacity(selected, highlight, hasSelection, hasPartialHighlights) {
33029 if ((hasPartialHighlights && !highlight) || (hasSelection && !selected))
33030 return ColumnUtil.DimmedOpacity;
33031 return ColumnUtil.DefaultOpacity;
33032 }
33033 ColumnUtil.getFillOpacity = getFillOpacity;
33034 function getClosestColumnIndex(coordinate, columnsCenters) {
33035 var currentIndex = 0;
33036 var distance = Number.MAX_VALUE;
33037 for (var i = 0, ilen = columnsCenters.length; i < ilen; i++) {
33038 var currentDistance = Math.abs(coordinate - columnsCenters[i]);
33039 if (currentDistance < distance) {
33040 distance = currentDistance;
33041 currentIndex = i;
33042 }
33043 }
33044 return currentIndex;
33045 }
33046 ColumnUtil.getClosestColumnIndex = getClosestColumnIndex;
33047 function setChosenColumnOpacity(mainGraphicsContext, columnGroupSelector, selectedColumnIndex, lastColumnIndex) {
33048 var series = mainGraphicsContext.selectAll(visuals.ColumnChart.SeriesClasses.selector);
33049 var lastColumnUndefined = typeof lastColumnIndex === 'undefined';
33050 // find all columns that do not belong to the selected column and set a dimmed opacity with a smooth animation to those columns
33051 series.selectAll(rectName + columnGroupSelector).filter(function (d) {
33052 return (d.categoryIndex !== selectedColumnIndex) && (lastColumnUndefined || d.categoryIndex === lastColumnIndex);
33053 }).transition().style('fill-opacity', ColumnUtil.DimmedOpacity);
33054 // set the default opacity for the selected column
33055 series.selectAll(rectName + columnGroupSelector).filter(function (d) {
33056 return d.categoryIndex === selectedColumnIndex;
33057 }).style('fill-opacity', ColumnUtil.DefaultOpacity);
33058 }
33059 ColumnUtil.setChosenColumnOpacity = setChosenColumnOpacity;
33060 function drawSeries(data, graphicsContext, axisOptions) {
33061 var colGroupSelection = graphicsContext.selectAll(visuals.ColumnChart.SeriesClasses.selector);
33062 var series = colGroupSelection.data(data.series, function (d) { return d.key; });
33063 series
33064 .enter()
33065 .append('g')
33066 .classed(visuals.ColumnChart.SeriesClasses.class, true);
33067 series
33068 .style({
33069 fill: function (d) { return d.color; },
33070 });
33071 series
33072 .exit()
33073 .remove();
33074 return series;
33075 }
33076 ColumnUtil.drawSeries = drawSeries;
33077 function drawDefaultShapes(data, series, layout, itemCS, filterZeros, hasSelection) {
33078 // We filter out invisible (0, null, etc.) values from the dataset
33079 // based on whether animations are enabled or not, Dashboard and
33080 // Exploration mode, respectively.
33081 var dataSelector;
33082 if (filterZeros) {
33083 dataSelector = function (d) {
33084 var filteredData = _.filter(d.data, function (datapoint) { return !!datapoint.value; });
33085 return filteredData;
33086 };
33087 }
33088 else {
33089 dataSelector = function (d) { return d.data; };
33090 }
33091 var shapeSelection = series.selectAll(itemCS.selector);
33092 var shapes = shapeSelection.data(dataSelector, function (d) { return d.key; });
33093 shapes.enter()
33094 .append(rectName)
33095 .attr("class", function (d) { return itemCS.class.concat(d.highlight ? " highlight" : ""); });
33096 shapes
33097 .style("fill-opacity", function (d) { return ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, data.hasHighlights); })
33098 .style("fill", function (d) { return d.color !== data.series[d.seriesIndex].color ? d.color : null; }) // PERF: Only set the fill color if it is different than series.
33099 .attr(layout.shapeLayout);
33100 shapes
33101 .exit()
33102 .remove();
33103 return shapes;
33104 }
33105 ColumnUtil.drawDefaultShapes = drawDefaultShapes;
33106 function drawDefaultLabels(series, context, layout, viewPort, isAnimator, animationDuration) {
33107 if (isAnimator === void 0) { isAnimator = false; }
33108 if (series) {
33109 var seriesData = series.data();
33110 var dataPoints = [];
33111 for (var i = 0, len = seriesData.length; i < len; i++) {
33112 Array.prototype.push.apply(dataPoints, seriesData[i].data);
33113 }
33114 return visuals.dataLabelUtils.drawDefaultLabelsForDataPointChart(dataPoints, context, layout, viewPort, isAnimator, animationDuration);
33115 }
33116 else {
33117 visuals.dataLabelUtils.cleanDataLabels(context);
33118 }
33119 }
33120 ColumnUtil.drawDefaultLabels = drawDefaultLabels;
33121 function normalizeInfinityInScale(scale) {
33122 // When large values (eg Number.MAX_VALUE) are involved, a call to scale.nice occasionally
33123 // results in infinite values being included in the domain. To correct for that, we need to
33124 // re-normalize the domain now to not include infinities.
33125 var scaledDomain = scale.domain();
33126 for (var i = 0, len = scaledDomain.length; i < len; ++i) {
33127 if (scaledDomain[i] === Number.POSITIVE_INFINITY)
33128 scaledDomain[i] = Number.MAX_VALUE;
33129 else if (scaledDomain[i] === Number.NEGATIVE_INFINITY)
33130 scaledDomain[i] = -Number.MAX_VALUE;
33131 }
33132 scale.domain(scaledDomain);
33133 }
33134 ColumnUtil.normalizeInfinityInScale = normalizeInfinityInScale;
33135 function calculatePosition(d, axisOptions) {
33136 var xScale = axisOptions.xScale;
33137 var yScale = axisOptions.yScale;
33138 var scaledY0 = yScale(0);
33139 var scaledX0 = xScale(0);
33140 switch (d.chartType) {
33141 case visuals.ColumnChartType.stackedBar:
33142 case visuals.ColumnChartType.hundredPercentStackedBar:
33143 return scaledX0 + Math.abs(visuals.AxisHelper.diffScaled(xScale, 0, d.valueAbsolute)) +
33144 visuals.AxisHelper.diffScaled(xScale, d.position - d.valueAbsolute, 0) + visuals.dataLabelUtils.defaultColumnLabelMargin;
33145 case visuals.ColumnChartType.clusteredBar:
33146 return scaledX0 + visuals.AxisHelper.diffScaled(xScale, Math.max(0, d.value), 0) + visuals.dataLabelUtils.defaultColumnLabelMargin;
33147 case visuals.ColumnChartType.stackedColumn:
33148 case visuals.ColumnChartType.hundredPercentStackedColumn:
33149 return scaledY0 + visuals.AxisHelper.diffScaled(yScale, d.position, 0) - visuals.dataLabelUtils.defaultColumnLabelMargin;
33150 case visuals.ColumnChartType.clusteredColumn:
33151 return scaledY0 + visuals.AxisHelper.diffScaled(yScale, Math.max(0, d.value), 0) - visuals.dataLabelUtils.defaultColumnLabelMargin;
33152 }
33153 }
33154 ColumnUtil.calculatePosition = calculatePosition;
33155 })(ColumnUtil = visuals.ColumnUtil || (visuals.ColumnUtil = {}));
33156 var ClusteredUtil;
33157 (function (ClusteredUtil) {
33158 function clearColumns(mainGraphicsContext, itemCS) {
33159 debug.assertValue(mainGraphicsContext, 'mainGraphicsContext');
33160 debug.assertValue(itemCS, 'itemCS');
33161 var cols = mainGraphicsContext.selectAll(itemCS.selector)
33162 .data([]);
33163 cols.exit().remove();
33164 }
33165 ClusteredUtil.clearColumns = clearColumns;
33166 })(ClusteredUtil = visuals.ClusteredUtil || (visuals.ClusteredUtil = {}));
33167 var StackedUtil;
33168 (function (StackedUtil) {
33169 var PctRoundingError = 0.0001;
33170 function getSize(scale, size, zeroVal) {
33171 if (zeroVal === void 0) { zeroVal = 0; }
33172 return visuals.AxisHelper.diffScaled(scale, zeroVal, size);
33173 }
33174 StackedUtil.getSize = getSize;
33175 function calcValueDomain(data, is100pct) {
33176 var defaultNumberRange = {
33177 min: 0,
33178 max: 10
33179 };
33180 if (data.length === 0)
33181 return defaultNumberRange;
33182 // Can't use AxisHelper because Stacked layout has a slightly different calc, (position - valueAbs)
33183 var min = d3.min(data, function (d) { return d3.min(d.data, function (e) { return e.position - e.valueAbsolute; }); });
33184 var max = d3.max(data, function (d) { return d3.max(d.data, function (e) { return e.position; }); });
33185 if (is100pct) {
33186 min = powerbi.Double.roundToPrecision(min, PctRoundingError);
33187 max = powerbi.Double.roundToPrecision(max, PctRoundingError);
33188 }
33189 return {
33190 min: min,
33191 max: max,
33192 };
33193 }
33194 StackedUtil.calcValueDomain = calcValueDomain;
33195 function getStackedMultiplier(dataView, rowIdx, seriesCount, categoryCount, converterStrategy) {
33196 debug.assertValue(dataView, 'dataView');
33197 debug.assertValue(rowIdx, 'rowIdx');
33198 var pos = 0, neg = 0;
33199 for (var i = 0; i < seriesCount; i++) {
33200 var value = converterStrategy.getValueBySeriesAndCategory(i, rowIdx);
33201 value = visuals.AxisHelper.normalizeNonFiniteNumber(value);
33202 if (value > 0)
33203 pos += value;
33204 else if (value < 0)
33205 neg -= value;
33206 }
33207 var absTotal = pos + neg;
33208 return {
33209 pos: pos ? (pos / absTotal) / pos : 1,
33210 neg: neg ? (neg / absTotal) / neg : 1,
33211 };
33212 }
33213 StackedUtil.getStackedMultiplier = getStackedMultiplier;
33214 function clearColumns(mainGraphicsContext, itemCS) {
33215 debug.assertValue(mainGraphicsContext, 'mainGraphicsContext');
33216 debug.assertValue(itemCS, 'itemCS');
33217 var bars = mainGraphicsContext.selectAll(itemCS.selector)
33218 .data([]);
33219 bars.exit().remove();
33220 }
33221 StackedUtil.clearColumns = clearColumns;
33222 })(StackedUtil = visuals.StackedUtil || (visuals.StackedUtil = {}));
33223 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
33224})(powerbi || (powerbi = {}));
33225/*
33226 * Power BI Visualizations
33227 *
33228 * Copyright (c) Microsoft Corporation
33229 * All rights reserved.
33230 * MIT License
33231 *
33232 * Permission is hereby granted, free of charge, to any person obtaining a copy
33233 * of this software and associated documentation files (the ""Software""), to deal
33234 * in the Software without restriction, including without limitation the rights
33235 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33236 * copies of the Software, and to permit persons to whom the Software is
33237 * furnished to do so, subject to the following conditions:
33238 *
33239 * The above copyright notice and this permission notice shall be included in
33240 * all copies or substantial portions of the Software.
33241 *
33242 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33243 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33244 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33245 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33246 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33247 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33248 * THE SOFTWARE.
33249 */
33250var powerbi;
33251(function (powerbi) {
33252 var visuals;
33253 (function (visuals) {
33254 var DataRoleHelper = powerbi.data.DataRoleHelper;
33255 var converterHelper;
33256 (function (converterHelper) {
33257 function categoryIsAlsoSeriesRole(dataView, seriesRoleName, categoryRoleName) {
33258 if (dataView.categories && dataView.categories.length > 0) {
33259 // Need to pivot data if our category soure is a series role
33260 var category = dataView.categories[0];
33261 return category.source &&
33262 DataRoleHelper.hasRole(category.source, seriesRoleName) &&
33263 DataRoleHelper.hasRole(category.source, categoryRoleName);
33264 }
33265 return false;
33266 }
33267 converterHelper.categoryIsAlsoSeriesRole = categoryIsAlsoSeriesRole;
33268 function getPivotedCategories(dataView, formatStringProp) {
33269 if (dataView.categories && dataView.categories.length > 0) {
33270 var category = dataView.categories[0];
33271 var categoryValues = category.values;
33272 return category.values.length > 0
33273 ? {
33274 categories: categoryValues,
33275 categoryFormatter: visuals.valueFormatter.create({
33276 format: visuals.valueFormatter.getFormatString(category.source, formatStringProp),
33277 value: categoryValues[0],
33278 value2: categoryValues[categoryValues.length - 1],
33279 // Do not use display units such as K/M/bn etc. on the x-axis.
33280 // PowerView does not use units either as large ranges will make the x-axis indecipherable.
33281 displayUnitSystemType: powerbi.DisplayUnitSystemType.Verbose,
33282 }),
33283 categoryIdentities: category.identity,
33284 categoryObjects: category.objects,
33285 }
33286 : {
33287 categories: [],
33288 categoryFormatter: { format: visuals.valueFormatter.format },
33289 };
33290 }
33291 // For cases where the category source is just a series role, we are pivoting the data on the role which means we
33292 // will have no categories.
33293 return defaultCategories();
33294 }
33295 converterHelper.getPivotedCategories = getPivotedCategories;
33296 function getSeriesName(source) {
33297 debug.assertValue(source, 'source');
33298 return (source.groupName !== undefined)
33299 ? source.groupName
33300 : source.queryName;
33301 }
33302 converterHelper.getSeriesName = getSeriesName;
33303 function getFormattedLegendLabel(source, values, formatStringProp) {
33304 debug.assertValue(source, 'source');
33305 debug.assertValue(values, 'values');
33306 var sourceForFormat = source;
33307 var nameForFormat = source.displayName;
33308 if (source.groupName !== undefined) {
33309 sourceForFormat = values.source;
33310 nameForFormat = source.groupName;
33311 }
33312 return visuals.valueFormatter.format(nameForFormat, visuals.valueFormatter.getFormatString(sourceForFormat, formatStringProp));
33313 }
33314 converterHelper.getFormattedLegendLabel = getFormattedLegendLabel;
33315 function defaultCategories() {
33316 return {
33317 categories: [null],
33318 categoryFormatter: { format: visuals.valueFormatter.format },
33319 };
33320 }
33321 function createAxesLabels(categoryAxisProperties, valueAxisProperties, category, values) {
33322 var xAxisLabel = null;
33323 var yAxisLabel = null;
33324 if (categoryAxisProperties) {
33325 // Take the value only if it's there
33326 if (category && category.displayName) {
33327 xAxisLabel = category.displayName;
33328 }
33329 }
33330 if (valueAxisProperties) {
33331 var valuesNames = [];
33332 if (values) {
33333 // Take the name from the values, and make it unique because there are sometimes duplications
33334 valuesNames = values.map(function (v) { return v ? v.displayName : ''; }).filter(function (value, index, self) { return value !== '' && self.indexOf(value) === index; });
33335 yAxisLabel = visuals.valueFormatter.formatListAnd(valuesNames);
33336 }
33337 }
33338 return { xAxisLabel: xAxisLabel, yAxisLabel: yAxisLabel };
33339 }
33340 converterHelper.createAxesLabels = createAxesLabels;
33341 function isImageUrlColumn(column) {
33342 var misc = getMiscellaneousTypeDescriptor(column);
33343 return misc != null && misc.imageUrl === true;
33344 }
33345 converterHelper.isImageUrlColumn = isImageUrlColumn;
33346 function isWebUrlColumn(column) {
33347 var misc = getMiscellaneousTypeDescriptor(column);
33348 return misc != null && misc.webUrl === true;
33349 }
33350 converterHelper.isWebUrlColumn = isWebUrlColumn;
33351 function getMiscellaneousTypeDescriptor(column) {
33352 return column
33353 && column.type
33354 && column.type.misc;
33355 }
33356 function hasImageUrlColumn(dataView) {
33357 if (!dataView || !dataView.metadata || _.isEmpty(dataView.metadata.columns))
33358 return false;
33359 return _.any(dataView.metadata.columns, function (column) { return isImageUrlColumn(column) === true; });
33360 }
33361 converterHelper.hasImageUrlColumn = hasImageUrlColumn;
33362 function formatFromMetadataColumn(value, column, formatStringProp) {
33363 debug.assertValue(column, 'column should exist');
33364 var formatString = visuals.valueFormatter.getFormatString(column, formatStringProp, true);
33365 if (!formatString && column) {
33366 formatString = column.format;
33367 }
33368 return visuals.valueFormatter.format(value, formatString);
33369 }
33370 converterHelper.formatFromMetadataColumn = formatFromMetadataColumn;
33371 })(converterHelper = visuals.converterHelper || (visuals.converterHelper = {}));
33372 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
33373})(powerbi || (powerbi = {}));
33374/*
33375 * Power BI Visualizations
33376 *
33377 * Copyright (c) Microsoft Corporation
33378 * All rights reserved.
33379 * MIT License
33380 *
33381 * Permission is hereby granted, free of charge, to any person obtaining a copy
33382 * of this software and associated documentation files (the ""Software""), to deal
33383 * in the Software without restriction, including without limitation the rights
33384 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33385 * copies of the Software, and to permit persons to whom the Software is
33386 * furnished to do so, subject to the following conditions:
33387 *
33388 * The above copyright notice and this permission notice shall be included in
33389 * all copies or substantial portions of the Software.
33390 *
33391 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33392 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33393 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33394 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33395 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33396 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33397 * THE SOFTWARE.
33398 */
33399var powerbi;
33400(function (powerbi) {
33401 var visuals;
33402 (function (visuals) {
33403 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
33404 var PixelConverter = jsCommon.PixelConverter;
33405 var LabelStyle = visuals.labelStyle;
33406 var dataLabelUtils;
33407 (function (dataLabelUtils) {
33408 dataLabelUtils.minLabelFontSize = 8;
33409 dataLabelUtils.labelMargin = 8;
33410 dataLabelUtils.maxLabelWidth = 50;
33411 dataLabelUtils.defaultColumnLabelMargin = 5;
33412 dataLabelUtils.defaultColumnHalfLabelHeight = 4;
33413 dataLabelUtils.DefaultDy = '-0.15em';
33414 dataLabelUtils.DefaultFontSizeInPt = 9;
33415 dataLabelUtils.StandardFontFamily = 'wf_segoe-ui_normal';
33416 dataLabelUtils.LabelTextProperties = {
33417 fontFamily: 'wf_standard-font',
33418 fontSize: PixelConverter.fromPoint(dataLabelUtils.DefaultFontSizeInPt),
33419 fontWeight: 'normal',
33420 };
33421 dataLabelUtils.defaultLabelColor = "#777777";
33422 dataLabelUtils.defaultInsideLabelColor = "#ffffff";
33423 dataLabelUtils.hundredPercentFormat = "0.00 %;-0.00 %;0.00 %";
33424 dataLabelUtils.defaultLabelPrecision = undefined;
33425 var defaultCountLabelPrecision = 0;
33426 var labelGraphicsContextClass = createClassAndSelector('labels');
33427 var linesGraphicsContextClass = createClassAndSelector('lines');
33428 var labelsClass = createClassAndSelector('data-labels');
33429 var lineClass = createClassAndSelector('line-label');
33430 function updateLabelSettingsFromLabelsObject(labelsObj, labelSettings) {
33431 if (labelsObj) {
33432 if (labelsObj.show !== undefined)
33433 labelSettings.show = labelsObj.show;
33434 if (labelsObj.showSeries !== undefined)
33435 labelSettings.show = labelsObj.showSeries;
33436 if (labelsObj.color !== undefined)
33437 labelSettings.labelColor = labelsObj.color.solid.color;
33438 if (labelsObj.labelDisplayUnits !== undefined)
33439 labelSettings.displayUnits = labelsObj.labelDisplayUnits;
33440 if (labelsObj.labelPrecision !== undefined)
33441 labelSettings.precision = (labelsObj.labelPrecision >= 0) ? labelsObj.labelPrecision : dataLabelUtils.defaultLabelPrecision;
33442 if (labelsObj.fontSize !== undefined)
33443 labelSettings.fontSize = labelsObj.fontSize;
33444 if (labelsObj.showAll !== undefined)
33445 labelSettings.showLabelPerSeries = labelsObj.showAll;
33446 if (labelsObj.labelStyle !== undefined)
33447 labelSettings.labelStyle = labelsObj.labelStyle;
33448 }
33449 }
33450 dataLabelUtils.updateLabelSettingsFromLabelsObject = updateLabelSettingsFromLabelsObject;
33451 function updateLineChartLabelSettingsFromLabelsObject(labelsObj, labelSettings) {
33452 updateLabelSettingsFromLabelsObject(labelsObj, labelSettings);
33453 if (labelsObj && labelsObj.labelDensity !== undefined)
33454 labelSettings.labelDensity = labelsObj.labelDensity;
33455 }
33456 dataLabelUtils.updateLineChartLabelSettingsFromLabelsObject = updateLineChartLabelSettingsFromLabelsObject;
33457 function getDefaultLabelSettings(show, labelColor, fontSize) {
33458 if (show === void 0) { show = false; }
33459 return {
33460 show: show,
33461 position: 0 /* Above */,
33462 displayUnits: 0,
33463 precision: dataLabelUtils.defaultLabelPrecision,
33464 labelColor: labelColor || dataLabelUtils.defaultLabelColor,
33465 formatterOptions: null,
33466 fontSize: fontSize || dataLabelUtils.DefaultFontSizeInPt,
33467 };
33468 }
33469 dataLabelUtils.getDefaultLabelSettings = getDefaultLabelSettings;
33470 function getDefaultCardLabelSettings(labelColor, categoryLabelColor, fontSize) {
33471 var labelSettings = getDefaultLabelSettings(true, labelColor, fontSize);
33472 labelSettings.showCategory = true;
33473 labelSettings.categoryLabelColor = categoryLabelColor;
33474 return labelSettings;
33475 }
33476 dataLabelUtils.getDefaultCardLabelSettings = getDefaultCardLabelSettings;
33477 function getDefaultTreemapLabelSettings() {
33478 return {
33479 show: false,
33480 displayUnits: 0,
33481 precision: dataLabelUtils.defaultLabelPrecision,
33482 labelColor: dataLabelUtils.defaultInsideLabelColor,
33483 showCategory: true,
33484 formatterOptions: null,
33485 };
33486 }
33487 dataLabelUtils.getDefaultTreemapLabelSettings = getDefaultTreemapLabelSettings;
33488 function getDefaultSunburstLabelSettings() {
33489 return {
33490 show: false,
33491 labelColor: dataLabelUtils.defaultInsideLabelColor,
33492 fontSize: dataLabelUtils.DefaultFontSizeInPt,
33493 displayUnits: 0,
33494 precision: dataLabelUtils.defaultLabelPrecision,
33495 showCategory: true,
33496 };
33497 }
33498 dataLabelUtils.getDefaultSunburstLabelSettings = getDefaultSunburstLabelSettings;
33499 function getDefaultColumnLabelSettings(isLabelPositionInside) {
33500 var labelSettings = getDefaultLabelSettings(false, undefined);
33501 labelSettings.position = null;
33502 labelSettings.labelColor = undefined;
33503 return labelSettings;
33504 }
33505 dataLabelUtils.getDefaultColumnLabelSettings = getDefaultColumnLabelSettings;
33506 function getDefaultPointLabelSettings() {
33507 return {
33508 show: false,
33509 position: 0 /* Above */,
33510 displayUnits: 0,
33511 precision: dataLabelUtils.defaultLabelPrecision,
33512 labelColor: dataLabelUtils.defaultLabelColor,
33513 formatterOptions: null,
33514 fontSize: dataLabelUtils.DefaultFontSizeInPt,
33515 };
33516 }
33517 dataLabelUtils.getDefaultPointLabelSettings = getDefaultPointLabelSettings;
33518 function getDefaultLineChartLabelSettings(isComboChart) {
33519 return {
33520 show: false,
33521 position: 0 /* Above */,
33522 displayUnits: 0,
33523 precision: dataLabelUtils.defaultLabelPrecision,
33524 labelColor: dataLabelUtils.defaultLabelColor,
33525 formatterOptions: null,
33526 fontSize: dataLabelUtils.DefaultFontSizeInPt,
33527 labelDensity: isComboChart ? visuals.NewDataLabelUtils.LabelDensityMax : visuals.NewDataLabelUtils.LabelDensityMin,
33528 };
33529 }
33530 dataLabelUtils.getDefaultLineChartLabelSettings = getDefaultLineChartLabelSettings;
33531 function getDefaultMapLabelSettings() {
33532 return {
33533 show: false,
33534 showCategory: false,
33535 position: 0 /* Above */,
33536 displayUnits: 0,
33537 precision: dataLabelUtils.defaultLabelPrecision,
33538 labelColor: dataLabelUtils.defaultInsideLabelColor,
33539 formatterOptions: null,
33540 fontSize: dataLabelUtils.DefaultFontSizeInPt,
33541 };
33542 }
33543 dataLabelUtils.getDefaultMapLabelSettings = getDefaultMapLabelSettings;
33544 function getDefaultDonutLabelSettings() {
33545 var labelSettings = dataLabelUtils.getDefaultLabelSettings(true, dataLabelUtils.defaultLabelColor, dataLabelUtils.DefaultFontSizeInPt);
33546 labelSettings.labelStyle = LabelStyle.category;
33547 return labelSettings;
33548 }
33549 dataLabelUtils.getDefaultDonutLabelSettings = getDefaultDonutLabelSettings;
33550 function getDefaultGaugeLabelSettings() {
33551 return {
33552 show: true,
33553 displayUnits: 0,
33554 precision: dataLabelUtils.defaultLabelPrecision,
33555 labelColor: null,
33556 position: null,
33557 fontSize: dataLabelUtils.minLabelFontSize,
33558 formatterOptions: null,
33559 };
33560 }
33561 dataLabelUtils.getDefaultGaugeLabelSettings = getDefaultGaugeLabelSettings;
33562 function getDefaultFunnelLabelSettings() {
33563 return {
33564 show: true,
33565 position: powerbi.visuals.labelPosition.insideCenter,
33566 displayUnits: 0,
33567 precision: dataLabelUtils.defaultLabelPrecision,
33568 labelColor: dataLabelUtils.defaultLabelColor,
33569 formatterOptions: null,
33570 fontSize: dataLabelUtils.DefaultFontSizeInPt,
33571 };
33572 }
33573 dataLabelUtils.getDefaultFunnelLabelSettings = getDefaultFunnelLabelSettings;
33574 function getDefaultKpiLabelSettings() {
33575 return {
33576 show: false,
33577 displayUnits: 0,
33578 precision: dataLabelUtils.defaultLabelPrecision,
33579 labelColor: dataLabelUtils.defaultLabelColor,
33580 position: null,
33581 showCategory: true,
33582 formatterOptions: null,
33583 };
33584 }
33585 dataLabelUtils.getDefaultKpiLabelSettings = getDefaultKpiLabelSettings;
33586 function getLabelPrecision(precision, format) {
33587 debug.assertAnyValue(format, 'format');
33588 if (precision !== dataLabelUtils.defaultLabelPrecision)
33589 return precision;
33590 if (format === 'g' || format === 'G')
33591 return;
33592 if (format) {
33593 // Calculate precision from positive format by default
33594 var positiveFormat = format.split(";")[0];
33595 var formatMetadata = powerbi.NumberFormat.getCustomFormatMetadata(positiveFormat, true /*calculatePrecision*/);
33596 if (formatMetadata.hasDots) {
33597 return formatMetadata.precision;
33598 }
33599 }
33600 // For count fields we do not want a precision by default
33601 return defaultCountLabelPrecision;
33602 }
33603 dataLabelUtils.getLabelPrecision = getLabelPrecision;
33604 function drawDefaultLabelsForDataPointChart(data, context, layout, viewport, isAnimator, animationDuration, hasSelection) {
33605 if (isAnimator === void 0) { isAnimator = false; }
33606 debug.assertValue(data, 'data cannot be null or undefined');
33607 // Hide and reposition labels that overlap
33608 var dataLabelManager = new powerbi.DataLabelManager();
33609 var filteredData = dataLabelManager.hideCollidedLabels(viewport, data, layout);
33610 var hasAnimation = isAnimator && !!animationDuration;
33611 var labels = selectLabels(filteredData, context, false, hasAnimation);
33612 if (!labels)
33613 return;
33614 if (hasAnimation) {
33615 labels
33616 .text(function (d) { return d.labeltext; })
33617 .transition()
33618 .duration(animationDuration)
33619 .style(layout.style)
33620 .style('opacity', hasSelection ? function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); } : 1)
33621 .attr({ x: function (d) { return d.labelX; }, y: function (d) { return d.labelY; } });
33622 labels
33623 .exit()
33624 .transition()
33625 .duration(animationDuration)
33626 .style('opacity', 0) //fade out labels that are removed
33627 .remove();
33628 }
33629 else {
33630 labels
33631 .attr({ x: function (d) { return d.labelX; }, y: function (d) { return d.labelY; } })
33632 .text(function (d) { return d.labeltext; })
33633 .style(layout.style);
33634 labels
33635 .exit()
33636 .remove();
33637 }
33638 return labels;
33639 }
33640 dataLabelUtils.drawDefaultLabelsForDataPointChart = drawDefaultLabelsForDataPointChart;
33641 /**
33642 * Note: Funnel chart uses animation and does not use collision detection.
33643 */
33644 function drawDefaultLabelsForFunnelChart(data, context, layout, isAnimator, animationDuration) {
33645 if (isAnimator === void 0) { isAnimator = false; }
33646 debug.assertValue(data, 'data could not be null or undefined');
33647 var filteredData = data.filter(layout.filter);
33648 var labels = selectLabels(filteredData, context);
33649 if (!labels)
33650 return;
33651 labels
33652 .attr(layout.labelLayout)
33653 .text(layout.labelText)
33654 .style(layout.style);
33655 if (isAnimator && animationDuration) {
33656 labels.transition().duration(animationDuration);
33657 }
33658 labels
33659 .exit()
33660 .remove();
33661 return labels;
33662 }
33663 dataLabelUtils.drawDefaultLabelsForFunnelChart = drawDefaultLabelsForFunnelChart;
33664 function selectLabels(filteredData, context, isDonut, forAnimation) {
33665 if (isDonut === void 0) { isDonut = false; }
33666 if (forAnimation === void 0) { forAnimation = false; }
33667 // Check for a case where resizing leaves no labels - then we need to remove the labels 'g'
33668 if (filteredData.length === 0) {
33669 cleanDataLabels(context, true);
33670 return null;
33671 }
33672 if (context.select(labelGraphicsContextClass.selector).empty())
33673 context.append('g').classed(labelGraphicsContextClass.class, true);
33674 // line chart ViewModel has a special 'key' property for point identification since the 'identity' field is set to the series identity
33675 var hasKey = filteredData[0].key != null;
33676 var hasDataPointIdentity = filteredData[0].identity != null;
33677 var getIdentifier = hasKey ?
33678 function (d) { return d.key; }
33679 : hasDataPointIdentity ?
33680 function (d) { return d.identity.getKey(); }
33681 : undefined;
33682 var labels = isDonut ?
33683 context.select(labelGraphicsContextClass.selector).selectAll(labelsClass.selector).data(filteredData, function (d) { return d.data.identity.getKey(); })
33684 : getIdentifier != null ?
33685 context.select(labelGraphicsContextClass.selector).selectAll(labelsClass.selector).data(filteredData, getIdentifier)
33686 : context.select(labelGraphicsContextClass.selector).selectAll(labelsClass.selector).data(filteredData);
33687 var newLabels = labels.enter()
33688 .append('text')
33689 .classed(labelsClass.class, true);
33690 if (forAnimation)
33691 newLabels.style('opacity', 0);
33692 return labels;
33693 }
33694 function cleanDataLabels(context, removeLines) {
33695 if (removeLines === void 0) { removeLines = false; }
33696 var empty = [];
33697 var labels = context.selectAll(labelsClass.selector).data(empty);
33698 labels.exit().remove();
33699 context.selectAll(labelGraphicsContextClass.selector).remove();
33700 if (removeLines) {
33701 var lines = context.selectAll(lineClass.selector).data(empty);
33702 lines.exit().remove();
33703 context.selectAll(linesGraphicsContextClass.selector).remove();
33704 }
33705 }
33706 dataLabelUtils.cleanDataLabels = cleanDataLabels;
33707 function setHighlightedLabelsOpacity(context, hasSelection, hasHighlights) {
33708 context.selectAll(labelsClass.selector).style("fill-opacity", function (d) {
33709 var labelOpacity = visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, !d.highlight && hasSelection, !d.selected && hasHighlights) < 1 ? 0 : 1;
33710 return labelOpacity;
33711 });
33712 }
33713 dataLabelUtils.setHighlightedLabelsOpacity = setHighlightedLabelsOpacity;
33714 function getLabelFormattedText(options) {
33715 var properties = {
33716 text: options.formatter
33717 ? options.formatter.format(options.label)
33718 : powerbi.formattingService.formatValue(options.label, options.format),
33719 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
33720 fontSize: PixelConverter.fromPoint(options.fontSize),
33721 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
33722 };
33723 return powerbi.TextMeasurementService.getTailoredTextOrDefault(properties, options.maxWidth ? options.maxWidth : dataLabelUtils.maxLabelWidth);
33724 }
33725 dataLabelUtils.getLabelFormattedText = getLabelFormattedText;
33726 function getLabelLayoutXYForWaterfall(xAxisProperties, categoryWidth, yAxisProperties, dataDomain) {
33727 return {
33728 x: function (d) { return xAxisProperties.scale(d.categoryIndex) + (categoryWidth / 2); },
33729 y: function (d) { return getWaterfallLabelYPosition(yAxisProperties.scale, d, dataDomain); }
33730 };
33731 }
33732 dataLabelUtils.getLabelLayoutXYForWaterfall = getLabelLayoutXYForWaterfall;
33733 function getWaterfallLabelYPosition(scale, d, dataDomain) {
33734 var yValue = scale(0) - scale(Math.abs(d.value));
33735 var yPos = scale(d.position);
33736 var scaleMinDomain = scale(dataDomain[0]);
33737 var endPosition = scale(d.position + d.value);
33738 if (d.value < 0) {
33739 var properties = {
33740 text: d.labeltext,
33741 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
33742 fontSize: dataLabelUtils.LabelTextProperties.fontSize,
33743 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
33744 };
33745 var outsideBelowPosition = yPos + yValue + powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
33746 // Try to honor the position, but if the label doesn't fit where specified, then swap the position.
33747 if (scaleMinDomain > outsideBelowPosition) {
33748 return outsideBelowPosition;
33749 }
33750 }
33751 else {
33752 var outsideAbovePosition = yPos - yValue - dataLabelUtils.labelMargin;
33753 // Try to honor the position, but if the label doesn't fit where specified, then swap the position.
33754 if (outsideAbovePosition > 0) {
33755 return outsideAbovePosition;
33756 }
33757 }
33758 d.isLabelInside = true;
33759 return getWaterfallInsideLabelYPosition(yPos, endPosition, scaleMinDomain);
33760 }
33761 function getWaterfallInsideLabelYPosition(startPosition, endPosition, scaleMinDomain) {
33762 // Get the start and end position of the column
33763 // If the start or end is outside of the visual because of clipping - adjust the position
33764 startPosition = startPosition < 0 ? 0 : startPosition;
33765 startPosition = startPosition > scaleMinDomain ? scaleMinDomain : startPosition;
33766 endPosition = endPosition < 0 ? 0 : endPosition;
33767 endPosition = endPosition > scaleMinDomain ? scaleMinDomain : endPosition;
33768 return (Math.abs(endPosition - startPosition) / 2) + Math.min(startPosition, endPosition);
33769 }
33770 function doesDataLabelFitInShape(d, yAxisProperties, layout) {
33771 if (d == null || d.value === null)
33772 return false;
33773 var properties = {
33774 text: layout.labelText(d),
33775 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
33776 fontSize: dataLabelUtils.LabelTextProperties.fontSize,
33777 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
33778 };
33779 var outsidePosition = visuals.WaterfallChart.getRectTop(yAxisProperties.scale, d.position, d.value) - dataLabelUtils.labelMargin;
33780 // The shape is fit to be outside
33781 if (outsidePosition > 0)
33782 return true;
33783 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
33784 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
33785 var shapeWidth = layout.categoryWidth;
33786 var shapeHeight = Math.abs(visuals.AxisHelper.diffScaled(yAxisProperties.scale, Math.max(0, Math.abs(d.value)), 0));
33787 //checking that labels aren't greater than shape
33788 if ((textWidth > shapeWidth) || (textHeight > shapeHeight))
33789 return false;
33790 return true;
33791 }
33792 dataLabelUtils.doesDataLabelFitInShape = doesDataLabelFitInShape;
33793 function getMapLabelLayout(labelSettings) {
33794 return {
33795 labelText: function (d) {
33796 return getLabelFormattedText({
33797 label: d.labeltext,
33798 fontSize: labelSettings.fontSize
33799 });
33800 },
33801 labelLayout: {
33802 x: function (d) { return d.x; },
33803 y: function (d) {
33804 var margin = d.radius + dataLabelUtils.labelMargin;
33805 return labelSettings.position === 0 /* Above */ ? d.y - margin : d.y + margin;
33806 },
33807 },
33808 filter: function (d) {
33809 return (d != null && d.labeltext != null);
33810 },
33811 style: {
33812 'fill': function (d) { return d.labelFill; },
33813 'font-size': PixelConverter.fromPoint(labelSettings.fontSize),
33814 },
33815 };
33816 }
33817 dataLabelUtils.getMapLabelLayout = getMapLabelLayout;
33818 function getColumnChartLabelLayout(data, labelLayoutXY, isColumn, isHundredPercent, axisFormatter, axisOptions, interactivityService, visualWidth) {
33819 var formatOverride = (isHundredPercent) ? dataLabelUtils.hundredPercentFormat : null;
33820 var formattersCache = createColumnFormatterCacheManager();
33821 var hasSelection = interactivityService ? interactivityService.hasSelection() : false;
33822 return {
33823 labelText: function (d) {
33824 var formatString = (formatOverride != null) ? formatOverride : d.labelFormatString;
33825 var value2 = getDisplayUnitValueFromAxisFormatter(axisFormatter, d.labelSettings);
33826 var formatter = formattersCache.getOrCreate(formatString, d.labelSettings, value2);
33827 return getLabelFormattedText({
33828 label: formatter.format(d.value),
33829 maxWidth: dataLabelUtils.maxLabelWidth
33830 });
33831 },
33832 labelLayout: labelLayoutXY,
33833 filter: function (d) { return dataLabelUtils.getColumnChartLabelFilter(d, hasSelection, data.hasHighlights, axisOptions, visualWidth); },
33834 style: {
33835 'fill': function (d) { return d.labelFill; },
33836 'text-anchor': isColumn ? 'middle' : 'start',
33837 },
33838 };
33839 }
33840 dataLabelUtils.getColumnChartLabelLayout = getColumnChartLabelLayout;
33841 /**
33842 * Valide for stacked column/bar chart and 100% stacked column/bar chart,
33843 * that labels that should to be inside the shape aren't bigger then shapes.
33844 */
33845 function validateLabelsSize(d, axisOptions, visualWidth) {
33846 var xScale = axisOptions.xScale;
33847 var yScale = axisOptions.yScale;
33848 var columnWidth = axisOptions.columnWidth;
33849 var properties = {
33850 text: d.labeltext,
33851 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
33852 fontSize: dataLabelUtils.LabelTextProperties.fontSize,
33853 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
33854 };
33855 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
33856 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
33857 var shapeWidth, shapeHeight;
33858 var inside = false;
33859 var outsidePosition = visuals.ColumnUtil.calculatePosition(d, axisOptions);
33860 switch (d.chartType) {
33861 case visuals.ColumnChartType.stackedBar:
33862 case visuals.ColumnChartType.hundredPercentStackedBar:
33863 // if the series isn't last or the label doesn't fit where specified, then it should be inside
33864 if (!d.lastSeries || (outsidePosition + textWidth > visualWidth) || d.chartType === visuals.ColumnChartType.hundredPercentStackedBar) {
33865 shapeWidth = -visuals.StackedUtil.getSize(xScale, d.valueAbsolute);
33866 shapeHeight = columnWidth;
33867 inside = true;
33868 }
33869 break;
33870 case visuals.ColumnChartType.clusteredBar:
33871 // if the label doesn't fit where specified, then it should be inside
33872 if ((outsidePosition + textWidth) > visualWidth) {
33873 shapeWidth = Math.abs(visuals.AxisHelper.diffScaled(xScale, 0, d.value));
33874 shapeHeight = columnWidth;
33875 inside = true;
33876 }
33877 break;
33878 case visuals.ColumnChartType.stackedColumn:
33879 case visuals.ColumnChartType.hundredPercentStackedColumn:
33880 // if the series isn't last or the label doesn't fit where specified, then it should be inside
33881 if (!d.lastSeries || outsidePosition <= 0 || d.chartType === visuals.ColumnChartType.hundredPercentStackedColumn) {
33882 shapeWidth = columnWidth;
33883 shapeHeight = visuals.StackedUtil.getSize(yScale, d.valueAbsolute);
33884 inside = true;
33885 }
33886 break;
33887 case visuals.ColumnChartType.clusteredColumn:
33888 // if the label doesn't fit where specified, then it should be inside
33889 if (outsidePosition <= 0) {
33890 shapeWidth = columnWidth;
33891 shapeHeight = Math.abs(visuals.AxisHelper.diffScaled(yScale, 0, d.value));
33892 inside = true;
33893 }
33894 break;
33895 default:
33896 return true;
33897 }
33898 //checking that labels aren't greater than shape
33899 if (inside && ((textWidth > shapeWidth) || textHeight > shapeHeight))
33900 return false;
33901 return true;
33902 }
33903 function getColumnChartLabelFilter(d, hasSelection, hasHighlights, axisOptions, visualWidth) {
33904 //labels of dimmed are hidden
33905 var shapesOpacity = hasSelection ? visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, !d.highlight && hasSelection, !d.selected && hasHighlights) :
33906 visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, hasHighlights);
33907 return (d != null && d.value != null && validateLabelsSize(d, axisOptions, visualWidth) && shapesOpacity === 1);
33908 }
33909 dataLabelUtils.getColumnChartLabelFilter = getColumnChartLabelFilter;
33910 function getScatterChartLabelLayout(xScale, yScale, labelSettings, viewport, sizeRange) {
33911 return {
33912 labelText: function (d) {
33913 return getLabelFormattedText({
33914 label: d.formattedCategory.getValue(),
33915 maxWidth: dataLabelUtils.maxLabelWidth * 2.0
33916 });
33917 },
33918 labelLayout: {
33919 x: function (d) { return xScale(d.x); },
33920 y: function (d) {
33921 var margin = visuals.ScatterChart.getBubbleRadius(d.radius, sizeRange, viewport) + dataLabelUtils.labelMargin;
33922 return labelSettings.position === 0 /* Above */ ? yScale(d.y) - margin : yScale(d.y) + margin;
33923 },
33924 },
33925 filter: function (d) {
33926 return (d != null && d.formattedCategory.getValue() != null);
33927 },
33928 style: {
33929 'fill': function (d) { return d.labelFill; },
33930 },
33931 };
33932 }
33933 dataLabelUtils.getScatterChartLabelLayout = getScatterChartLabelLayout;
33934 function getLineChartLabelLayout(xScale, yScale, labelSettings, isScalar, axisFormatter) {
33935 var formattersCache = createColumnFormatterCacheManager();
33936 return {
33937 labelText: function (d) {
33938 var value2 = getDisplayUnitValueFromAxisFormatter(axisFormatter, d.labelSettings);
33939 var formatter = formattersCache.getOrCreate(d.labelFormatString, d.labelSettings, value2);
33940 return getLabelFormattedText({ label: formatter.format(d.value) });
33941 },
33942 labelLayout: {
33943 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex); },
33944 y: function (d) { return labelSettings.position === 0 /* Above */ ? yScale(d.value) - dataLabelUtils.labelMargin : yScale(d.value) + dataLabelUtils.labelMargin; },
33945 },
33946 filter: function (d) {
33947 return (d != null && d.value != null);
33948 },
33949 style: {
33950 'fill': function (d) { return d.labelFill; },
33951 'font-size': function (d) { return PixelConverter.fromPoint(d.labelSettings.fontSize); },
33952 },
33953 };
33954 }
33955 dataLabelUtils.getLineChartLabelLayout = getLineChartLabelLayout;
33956 function getFunnelChartLabelLayout(data, axisOptions, textMinimumPadding, labelSettings, currentViewport) {
33957 var categoryScale = axisOptions.categoryScale;
33958 var valueScale = axisOptions.valueScale;
33959 var marginLeft = axisOptions.margin.left;
33960 var innerTextHeightRate = 0.7;
33961 var rangeBand = axisOptions.categoryScale.rangeBand();
33962 var pixelSpan = axisOptions.maxWidth / 2;
33963 var formatString = visuals.valueFormatter.getFormatString(data.valuesMetadata[0], visuals.funnelChartProps.general.formatString);
33964 var textMeasurer = powerbi.TextMeasurementService.measureSvgTextWidth;
33965 var value2 = null;
33966 if (labelSettings.displayUnits === 0) {
33967 var minY = d3.min(data.slices, function (d) { return d.value; });
33968 var maxY = d3.max(data.slices, function (d) { return d.value; });
33969 value2 = Math.max(Math.abs(minY), Math.abs(maxY));
33970 }
33971 var formattersCache = createColumnFormatterCacheManager();
33972 return {
33973 labelText: function (d) {
33974 var barWidth = Math.abs(categoryScale(d.value) - categoryScale(0));
33975 var insideAvailableSpace = Math.abs(categoryScale(d.value) - categoryScale(0)) - (textMinimumPadding * 2);
33976 var outsideAvailableSpace = pixelSpan - (barWidth / 2) - textMinimumPadding;
33977 var labelFormatString = (formatString != null) ? formatString : d.labelFormatString;
33978 var maximumTextSize = Math.max(insideAvailableSpace, outsideAvailableSpace);
33979 var formatter = formattersCache.getOrCreate(labelFormatString, labelSettings, value2);
33980 var labelText = formatter.format(visuals.FunnelChart.getFunnelSliceValue(d, true /* asOriginal */));
33981 return getLabelFormattedText({
33982 label: labelText,
33983 maxWidth: maximumTextSize,
33984 fontSize: labelSettings.fontSize
33985 });
33986 },
33987 labelLayout: {
33988 y: function (d, i) {
33989 var properties = {
33990 text: d.labeltext,
33991 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
33992 fontSize: PixelConverter.fromPoint(labelSettings.fontSize),
33993 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
33994 };
33995 //in order to make it center aligned we should 'correct' the height to not calculate text margin
33996 var labelHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
33997 return categoryScale(d.categoryOrMeasureIndex) + (rangeBand / 2) + (labelHeight / 2);
33998 },
33999 x: function (d) {
34000 var barWidth = Math.abs(valueScale(d.value) - valueScale(0));
34001 var insideAvailableSpace = Math.abs(valueScale(d.value) - valueScale(0)) - (textMinimumPadding * 2);
34002 var outsideAvailableSpace = pixelSpan - (barWidth / 2) - textMinimumPadding;
34003 var maximumTextSize = Math.max(insideAvailableSpace, outsideAvailableSpace);
34004 var labelFormatString = (formatString != null) ? formatString : d.labelFormatString;
34005 var formatter = formattersCache.getOrCreate(labelFormatString, labelSettings, value2);
34006 var labelText = formatter.format(visuals.FunnelChart.getFunnelSliceValue(d, true /* asOriginal */));
34007 var properties = {
34008 text: getLabelFormattedText({
34009 label: labelText,
34010 maxWidth: maximumTextSize
34011 }),
34012 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
34013 fontSize: PixelConverter.fromPoint(labelSettings.fontSize),
34014 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
34015 };
34016 var textLength = textMeasurer(properties);
34017 // Try to honor the position, but if the label doesn't fit where specified, then swap the position.
34018 var labelPositionValue = labelSettings.position;
34019 if ((labelPositionValue === visuals.labelPosition.outsideEnd && outsideAvailableSpace < textLength) || d.value === 0)
34020 labelPositionValue = visuals.labelPosition.insideCenter;
34021 else if (labelPositionValue === visuals.labelPosition.insideCenter && insideAvailableSpace < textLength) {
34022 labelPositionValue = visuals.labelPosition.outsideEnd;
34023 }
34024 switch (labelPositionValue) {
34025 case visuals.labelPosition.outsideEnd:
34026 return marginLeft + pixelSpan + (barWidth / 2) + textMinimumPadding + (textLength / 2);
34027 default:
34028 // Inside position, change color to white unless value is 0
34029 d.labelFill = d.value !== 0 ? dataLabelUtils.defaultInsideLabelColor : d.labelFill;
34030 return marginLeft + pixelSpan;
34031 }
34032 },
34033 dy: '-0.15em',
34034 },
34035 filter: function (d) {
34036 if (!(d != null && d.value != null && data.hasHighlights === !!d.highlight))
34037 return false;
34038 var properties = {
34039 text: d.labeltext,
34040 fontFamily: dataLabelUtils.LabelTextProperties.fontFamily,
34041 fontSize: PixelConverter.fromPoint(labelSettings.fontSize),
34042 fontWeight: dataLabelUtils.LabelTextProperties.fontWeight,
34043 };
34044 var labelHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties) * innerTextHeightRate;
34045 return labelHeight < rangeBand;
34046 },
34047 style: {
34048 'fill': function (d) { return d.labelFill; },
34049 'fill-opacity': function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, false, false); },
34050 'font-size': function (d) { return PixelConverter.fromPoint(labelSettings.fontSize); },
34051 },
34052 };
34053 }
34054 dataLabelUtils.getFunnelChartLabelLayout = getFunnelChartLabelLayout;
34055 function enumerateDataLabels(options) {
34056 debug.assertValue(options, 'options');
34057 debug.assertValue(options.enumeration, 'enumeration');
34058 if (!options.dataLabelsSettings)
34059 return;
34060 var instance = {
34061 objectName: 'labels',
34062 selector: options.selector,
34063 properties: {},
34064 };
34065 if (options.show && options.selector) {
34066 instance.properties['showSeries'] = options.dataLabelsSettings.show;
34067 }
34068 else if (options.show) {
34069 instance.properties['show'] = options.dataLabelsSettings.show;
34070 }
34071 instance.properties['color'] = options.dataLabelsSettings.labelColor || dataLabelUtils.defaultLabelColor;
34072 if (options.displayUnits) {
34073 instance.properties['labelDisplayUnits'] = options.dataLabelsSettings.displayUnits;
34074 }
34075 if (options.precision) {
34076 var precision = options.dataLabelsSettings.precision;
34077 instance.properties['labelPrecision'] = precision === dataLabelUtils.defaultLabelPrecision ? null : precision;
34078 }
34079 if (options.position) {
34080 instance.properties['labelPosition'] = options.dataLabelsSettings.position;
34081 if (options.positionObject) {
34082 debug.assert(!instance.validValues, '!instance.validValues');
34083 instance.validValues = { 'labelPosition': options.positionObject };
34084 }
34085 }
34086 if (options.labelStyle)
34087 instance.properties['labelStyle'] = options.dataLabelsSettings.labelStyle;
34088 if (options.fontSize)
34089 instance.properties['fontSize'] = options.dataLabelsSettings.fontSize;
34090 if (options.labelDensity) {
34091 var lineChartSettings = options.dataLabelsSettings;
34092 if (lineChartSettings)
34093 instance.properties['labelDensity'] = lineChartSettings.labelDensity;
34094 }
34095 //Keep show all as the last property of the instance.
34096 if (options.showAll)
34097 instance.properties['showAll'] = options.dataLabelsSettings.showLabelPerSeries;
34098 return options.enumeration.pushInstance(instance);
34099 }
34100 dataLabelUtils.enumerateDataLabels = enumerateDataLabels;
34101 function enumerateCategoryLabels(enumeration, dataLabelsSettings, withFill, isShowCategory, fontSize) {
34102 if (isShowCategory === void 0) { isShowCategory = false; }
34103 var labelSettings = (dataLabelsSettings)
34104 ? dataLabelsSettings
34105 : getDefaultPointLabelSettings();
34106 var instance = {
34107 objectName: 'categoryLabels',
34108 selector: null,
34109 properties: {
34110 show: isShowCategory
34111 ? labelSettings.showCategory
34112 : labelSettings.show,
34113 fontSize: dataLabelsSettings ? dataLabelsSettings.fontSize : dataLabelUtils.DefaultFontSizeInPt,
34114 },
34115 };
34116 if (withFill) {
34117 instance.properties['color'] = labelSettings.categoryLabelColor
34118 ? labelSettings.categoryLabelColor
34119 : labelSettings.labelColor;
34120 }
34121 if (fontSize) {
34122 instance.properties['fontSize'] = fontSize;
34123 }
34124 enumeration.pushInstance(instance);
34125 }
34126 dataLabelUtils.enumerateCategoryLabels = enumerateCategoryLabels;
34127 function getDisplayUnitValueFromAxisFormatter(axisFormatter, labelSettings) {
34128 if (axisFormatter && axisFormatter.displayUnit && labelSettings.displayUnits === 0)
34129 return axisFormatter.displayUnit.value;
34130 return null;
34131 }
34132 function createColumnFormatterCacheManager() {
34133 return {
34134 cache: { defaultFormatter: null, },
34135 getOrCreate: function (formatString, labelSetting, value2) {
34136 if (formatString) {
34137 var cacheKeyObject = {
34138 formatString: formatString,
34139 displayUnits: labelSetting.displayUnits,
34140 precision: getLabelPrecision(labelSetting.precision, formatString),
34141 value2: value2
34142 };
34143 var cacheKey = JSON.stringify(cacheKeyObject);
34144 if (!this.cache[cacheKey])
34145 this.cache[cacheKey] = visuals.valueFormatter.create(getOptionsForLabelFormatter(labelSetting, formatString, value2, cacheKeyObject.precision));
34146 return this.cache[cacheKey];
34147 }
34148 if (!this.cache.defaultFormatter) {
34149 this.cache.defaultFormatter = visuals.valueFormatter.create(getOptionsForLabelFormatter(labelSetting, formatString, value2, labelSetting.precision));
34150 }
34151 return this.cache.defaultFormatter;
34152 }
34153 };
34154 }
34155 dataLabelUtils.createColumnFormatterCacheManager = createColumnFormatterCacheManager;
34156 function getOptionsForLabelFormatter(labelSetting, formatString, value2, precision) {
34157 return {
34158 displayUnitSystemType: powerbi.DisplayUnitSystemType.DataLabels,
34159 format: formatString,
34160 precision: precision,
34161 value: labelSetting.displayUnits,
34162 value2: value2,
34163 allowFormatBeautification: true,
34164 };
34165 }
34166 dataLabelUtils.getOptionsForLabelFormatter = getOptionsForLabelFormatter;
34167 function isTextWidthOverflows(textWidth, maxTextWidth) {
34168 return textWidth > maxTextWidth;
34169 }
34170 dataLabelUtils.isTextWidthOverflows = isTextWidthOverflows;
34171 ;
34172 function isTextHeightOverflows(textHeight, innerChordLength) {
34173 return textHeight > innerChordLength;
34174 }
34175 dataLabelUtils.isTextHeightOverflows = isTextHeightOverflows;
34176 ;
34177 })(dataLabelUtils = visuals.dataLabelUtils || (visuals.dataLabelUtils = {}));
34178 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
34179})(powerbi || (powerbi = {}));
34180/*
34181 * Power BI Visualizations
34182 *
34183 * Copyright (c) Microsoft Corporation
34184 * All rights reserved.
34185 * MIT License
34186 *
34187 * Permission is hereby granted, free of charge, to any person obtaining a copy
34188 * of this software and associated documentation files (the ""Software""), to deal
34189 * in the Software without restriction, including without limitation the rights
34190 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34191 * copies of the Software, and to permit persons to whom the Software is
34192 * furnished to do so, subject to the following conditions:
34193 *
34194 * The above copyright notice and this permission notice shall be included in
34195 * all copies or substantial portions of the Software.
34196 *
34197 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34198 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34199 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34200 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34201 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34202 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34203 * THE SOFTWARE.
34204 */
34205var powerbi;
34206(function (powerbi) {
34207 var visuals;
34208 (function (visuals) {
34209 var DonutLabelUtils;
34210 (function (DonutLabelUtils) {
34211 DonutLabelUtils.LineStrokeWidth = 1;
34212 DonutLabelUtils.DiagonalLineIndex = 0;
34213 DonutLabelUtils.HorizontalLineIndex = 1;
34214 function getLabelLeaderLineForDonutChart(donutArcDescriptor, donutProperties, parentPoint, sliceArc) {
34215 if (sliceArc === void 0) { sliceArc = 0; }
34216 var innerLinePointMultiplier = 2.05;
34217 var textPoint;
34218 var midPoint;
34219 var chartPoint;
34220 // Label position has changed
34221 if (sliceArc) {
34222 var arc = sliceArc;
34223 var outerRadius = donutProperties.radius * donutProperties.outerArcRadiusRatio;
34224 var innerRadius = (donutProperties.radius / 2) * donutProperties.innerArcRadiusRatio;
34225 midPoint = [Math.cos(arc) * outerRadius, Math.sin(arc) * outerRadius];
34226 chartPoint = [Math.cos(arc) * innerRadius, Math.sin(arc) * innerRadius];
34227 }
34228 else {
34229 midPoint = donutProperties.outerArc.centroid(donutArcDescriptor);
34230 chartPoint = donutProperties.arc.centroid(donutArcDescriptor);
34231 }
34232 var textPointX = parentPoint.x;
34233 var lineMargin = visuals.NewDataLabelUtils.maxLabelOffset / 2;
34234 textPointX += textPointX < 0 ? -lineMargin : lineMargin;
34235 textPoint = [textPointX, parentPoint.y];
34236 chartPoint[0] *= innerLinePointMultiplier;
34237 chartPoint[1] *= innerLinePointMultiplier;
34238 return [chartPoint, midPoint, textPoint];
34239 }
34240 DonutLabelUtils.getLabelLeaderLineForDonutChart = getLabelLeaderLineForDonutChart;
34241 /** We calculate the rectangles of the leader lines for collision detection
34242 *width: x2 - x1; height: y2 - y1 */
34243 function getLabelLeaderLinesSizeForDonutChart(leaderLinePoints) {
34244 if (leaderLinePoints && leaderLinePoints.length > 2) {
34245 var diagonalLineSize = {
34246 width: Math.abs(leaderLinePoints[1][0] - leaderLinePoints[0][0]),
34247 height: Math.abs(leaderLinePoints[1][1] - leaderLinePoints[0][1]),
34248 };
34249 // For horizontal line we set 1 in the height
34250 var horizontalLineSize = {
34251 width: Math.abs(leaderLinePoints[2][0] - leaderLinePoints[1][0]),
34252 height: DonutLabelUtils.LineStrokeWidth,
34253 };
34254 return [diagonalLineSize, horizontalLineSize];
34255 }
34256 return null;
34257 }
34258 DonutLabelUtils.getLabelLeaderLinesSizeForDonutChart = getLabelLeaderLinesSizeForDonutChart;
34259 function getXPositionForDonutLabel(textPointX) {
34260 var margin = textPointX < 0 ? -visuals.NewDataLabelUtils.maxLabelOffset : visuals.NewDataLabelUtils.maxLabelOffset;
34261 return textPointX += margin;
34262 }
34263 DonutLabelUtils.getXPositionForDonutLabel = getXPositionForDonutLabel;
34264 function getSpaceAvailableForDonutLabels(labelXPos, viewport) {
34265 return viewport.width / 2 - Math.abs(labelXPos) - visuals.NewDataLabelUtils.maxLabelOffset;
34266 }
34267 DonutLabelUtils.getSpaceAvailableForDonutLabels = getSpaceAvailableForDonutLabels;
34268 })(DonutLabelUtils = visuals.DonutLabelUtils || (visuals.DonutLabelUtils = {}));
34269 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
34270})(powerbi || (powerbi = {}));
34271/*
34272 * Power BI Visualizations
34273 *
34274 * Copyright (c) Microsoft Corporation
34275 * All rights reserved.
34276 * MIT License
34277 *
34278 * Permission is hereby granted, free of charge, to any person obtaining a copy
34279 * of this software and associated documentation files (the ""Software""), to deal
34280 * in the Software without restriction, including without limitation the rights
34281 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34282 * copies of the Software, and to permit persons to whom the Software is
34283 * furnished to do so, subject to the following conditions:
34284 *
34285 * The above copyright notice and this permission notice shall be included in
34286 * all copies or substantial portions of the Software.
34287 *
34288 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34289 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34290 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34291 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34292 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34293 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34294 * THE SOFTWARE.
34295 */
34296var powerbi;
34297(function (powerbi) {
34298 var visuals;
34299 (function (visuals) {
34300 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
34301 var PixelConverter = jsCommon.PixelConverter;
34302 var NewDataLabelUtils;
34303 (function (NewDataLabelUtils) {
34304 NewDataLabelUtils.DefaultLabelFontSizeInPt = 9;
34305 NewDataLabelUtils.MapPolylineOpacity = 0.5;
34306 NewDataLabelUtils.LabelDensityBufferFactor = 3;
34307 NewDataLabelUtils.LabelDensityPadding = 6;
34308 NewDataLabelUtils.LabelDensityMin = 0;
34309 NewDataLabelUtils.LabelDensityMax = 6;
34310 NewDataLabelUtils.startingLabelOffset = 8;
34311 NewDataLabelUtils.maxLabelOffset = 8;
34312 NewDataLabelUtils.maxLabelWidth = 50;
34313 NewDataLabelUtils.hundredPercentFormat = '0.00 %;-0.00 %;0.00 %';
34314 NewDataLabelUtils.LabelTextProperties = {
34315 fontFamily: 'wf_standard-font',
34316 fontSize: PixelConverter.fromPoint(NewDataLabelUtils.DefaultLabelFontSizeInPt),
34317 fontWeight: 'normal',
34318 };
34319 NewDataLabelUtils.defaultLabelColor = "#777777";
34320 NewDataLabelUtils.defaultInsideLabelColor = "#ffffff"; //white
34321 NewDataLabelUtils.horizontalLabelBackgroundPadding = 4;
34322 NewDataLabelUtils.verticalLabelBackgroundPadding = 2;
34323 var labelBackgroundRounding = 4;
34324 var defaultLabelPrecision = undefined;
34325 var defaultCountLabelPrecision = 0;
34326 NewDataLabelUtils.labelGraphicsContextClass = createClassAndSelector('labelGraphicsContext');
34327 NewDataLabelUtils.labelBackgroundGraphicsContextClass = createClassAndSelector('labelBackgroundGraphicsContext');
34328 var labelsClass = createClassAndSelector('label');
34329 var secondLineLabelClass = createClassAndSelector('label-second-line');
34330 var linesGraphicsContextClass = createClassAndSelector('leader-lines');
34331 var lineClass = createClassAndSelector('line-label');
34332 function drawDefaultLabels(context, dataLabels, numeric, twoRows, hasTooltip) {
34333 if (numeric === void 0) { numeric = false; }
34334 if (twoRows === void 0) { twoRows = false; }
34335 if (hasTooltip === void 0) { hasTooltip = false; }
34336 var filteredDataLabels = _.filter(dataLabels, function (d) { return d.isVisible; });
34337 var labels = context.selectAll(labelsClass.selector)
34338 .data(filteredDataLabels, labelKeyFunction);
34339 labels.enter()
34340 .append("text")
34341 .classed(labelsClass.class, true);
34342 var labelAttr = {
34343 x: function (d) {
34344 return (d.boundingBox.left + (d.boundingBox.width / 2));
34345 },
34346 y: function (d) {
34347 if (d.hasBackground)
34348 return d.boundingBox.top + d.boundingBox.height - NewDataLabelUtils.verticalLabelBackgroundPadding;
34349 else
34350 return d.boundingBox.top + d.boundingBox.height;
34351 },
34352 dy: "-0.15em",
34353 };
34354 if (numeric) {
34355 labelAttr.dy = undefined;
34356 }
34357 labels
34358 .text(function (d) { return d.text; })
34359 .attr(labelAttr)
34360 .style({
34361 'fill': function (d) { return d.fill; },
34362 'font-size': function (d) { return PixelConverter.fromPoint(d.fontSize || NewDataLabelUtils.DefaultLabelFontSizeInPt); },
34363 'text-anchor': function (d) { return d.textAnchor; },
34364 });
34365 labels.exit()
34366 .remove();
34367 var filteredCategoryLabels = _.filter(twoRows ? dataLabels : [], function (d) { return d.isVisible && !_.isEmpty(d.secondRowText); });
34368 var secondLineLabels = context.selectAll(secondLineLabelClass.selector)
34369 .data(filteredCategoryLabels, function (d, index) { return d.identity ? d.identity.getKeyWithoutHighlight() : index; });
34370 secondLineLabels.enter()
34371 .append("text")
34372 .classed(secondLineLabelClass.class, true);
34373 labelAttr = {
34374 x: function (d) {
34375 return (d.boundingBox.left + (d.boundingBox.width / 2));
34376 },
34377 y: function (d) {
34378 var boundingBoxHeight = (d.text !== undefined) ? d.boundingBox.height / 2 : d.boundingBox.height;
34379 if (d.hasBackground)
34380 return d.boundingBox.top + boundingBoxHeight - NewDataLabelUtils.verticalLabelBackgroundPadding;
34381 else
34382 return d.boundingBox.top + boundingBoxHeight;
34383 },
34384 dy: "-0.15em",
34385 };
34386 if (numeric) {
34387 labelAttr.dy = undefined;
34388 }
34389 secondLineLabels
34390 .text(function (d) { return d.secondRowText; })
34391 .attr(labelAttr)
34392 .style({
34393 'fill': function (d) { return d.fill; },
34394 'font-size': function (d) { return PixelConverter.fromPoint(d.fontSize || NewDataLabelUtils.DefaultLabelFontSizeInPt); },
34395 'text-anchor': function (d) { return d.textAnchor; },
34396 });
34397 secondLineLabels.exit()
34398 .remove();
34399 if (hasTooltip) {
34400 labels.append('title').text(function (d) { return d.tooltip; });
34401 secondLineLabels.append('title').text(function (d) { return d.tooltip; });
34402 labels.style("pointer-events", "all");
34403 secondLineLabels.style("pointer-events", "all");
34404 }
34405 return labels;
34406 }
34407 NewDataLabelUtils.drawDefaultLabels = drawDefaultLabels;
34408 function animateDefaultLabels(context, dataLabels, duration, numeric, easeType) {
34409 if (numeric === void 0) { numeric = false; }
34410 if (easeType === void 0) { easeType = 'cubic-in-out'; }
34411 var labels = context.selectAll(labelsClass.selector)
34412 .data(_.filter(dataLabels, function (d) { return d.isVisible; }), labelKeyFunction);
34413 labels.enter()
34414 .append("text")
34415 .classed(labelsClass.class, true)
34416 .style('opacity', 0);
34417 var labelAttr = {
34418 x: function (d) {
34419 return (d.boundingBox.left + (d.boundingBox.width / 2));
34420 },
34421 y: function (d) {
34422 return d.boundingBox.top + d.boundingBox.height;
34423 },
34424 dy: "-0.15em",
34425 };
34426 if (numeric) {
34427 labelAttr.dy = undefined;
34428 }
34429 labels.text(function (d) { return d.text; })
34430 .style({
34431 'fill': function (d) { return d.fill; },
34432 'font-size': function (d) { return PixelConverter.fromPoint(d.fontSize || NewDataLabelUtils.DefaultLabelFontSizeInPt); },
34433 })
34434 .transition()
34435 .ease(easeType)
34436 .duration(duration)
34437 .attr(labelAttr)
34438 .style('opacity', 1);
34439 labels.exit()
34440 .transition()
34441 .duration(duration)
34442 .style('opacity', 0)
34443 .remove();
34444 return labels;
34445 }
34446 NewDataLabelUtils.animateDefaultLabels = animateDefaultLabels;
34447 /** Draws black rectangles based on the bounding bx of labels, to be used in debugging */
34448 function drawLabelBackground(context, dataLabels, fill, fillOpacity) {
34449 var labelRects = context.selectAll("rect")
34450 .data(_.filter(dataLabels, function (d) { return d.isVisible; }), labelKeyFunction);
34451 labelRects.enter()
34452 .append("rect");
34453 labelRects
34454 .attr({
34455 x: function (d) {
34456 return d.boundingBox.left - NewDataLabelUtils.horizontalLabelBackgroundPadding;
34457 },
34458 y: function (d) {
34459 return d.boundingBox.top - NewDataLabelUtils.verticalLabelBackgroundPadding;
34460 },
34461 rx: labelBackgroundRounding,
34462 ry: labelBackgroundRounding,
34463 width: function (d) {
34464 return d.boundingBox.width + 2 * NewDataLabelUtils.horizontalLabelBackgroundPadding;
34465 },
34466 height: function (d) {
34467 if (d.text === undefined && d.secondRowText === undefined) {
34468 return 0;
34469 }
34470 return d.boundingBox.height + 2 * NewDataLabelUtils.verticalLabelBackgroundPadding;
34471 },
34472 })
34473 .style("fill", fill ? fill : "#000000")
34474 .style("fill-opacity", fillOpacity != null ? fillOpacity : 1);
34475 labelRects.exit()
34476 .remove();
34477 return labelRects;
34478 }
34479 NewDataLabelUtils.drawLabelBackground = drawLabelBackground;
34480 function drawLabelLeaderLines(context, filteredDataLabels, key, leaderLineColor) {
34481 if (context.select(linesGraphicsContextClass.selector).empty())
34482 context.append('g').classed(linesGraphicsContextClass.class, true);
34483 var lines = context.select(linesGraphicsContextClass.selector).selectAll('polyline')
34484 .data(filteredDataLabels, key);
34485 lines.enter()
34486 .append('polyline')
34487 .classed(lineClass.class, true);
34488 lines
34489 .attr('points', function (d) {
34490 return d.leaderLinePoints;
34491 }).
34492 style({
34493 'stroke': function (d) { return leaderLineColor ? leaderLineColor : d.fill; },
34494 'stroke-width': visuals.DonutLabelUtils.LineStrokeWidth,
34495 });
34496 lines
34497 .exit()
34498 .remove();
34499 }
34500 NewDataLabelUtils.drawLabelLeaderLines = drawLabelLeaderLines;
34501 function getLabelFormattedText(label, format, formatter) {
34502 return formatter ? formatter.format(label) : powerbi.formattingService.formatValue(label, format);
34503 }
34504 NewDataLabelUtils.getLabelFormattedText = getLabelFormattedText;
34505 function getDisplayUnitValueFromAxisFormatter(axisFormatter, labelSettings) {
34506 if (axisFormatter && axisFormatter.displayUnit && labelSettings.displayUnits === 0)
34507 return axisFormatter.displayUnit.value;
34508 return null;
34509 }
34510 NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter = getDisplayUnitValueFromAxisFormatter;
34511 function getLabelPrecision(precision, format) {
34512 debug.assertAnyValue(format, 'format');
34513 if (precision !== defaultLabelPrecision)
34514 return precision;
34515 if (format) {
34516 // Calculate precision from positive format by default
34517 var positiveFormat = format.split(";")[0];
34518 var formatMetadata = powerbi.NumberFormat.getCustomFormatMetadata(positiveFormat, true /*calculatePrecision*/);
34519 if (formatMetadata.hasDots) {
34520 return formatMetadata.precision;
34521 }
34522 }
34523 // For count fields we do not want a precision by default
34524 return defaultCountLabelPrecision;
34525 }
34526 function createColumnFormatterCacheManager() {
34527 return {
34528 cache: { defaultFormatter: null, },
34529 getOrCreate: function (formatString, labelSetting, value2) {
34530 if (formatString) {
34531 var cacheKeyObject = {
34532 formatString: formatString,
34533 displayUnits: labelSetting.displayUnits,
34534 precision: getLabelPrecision(labelSetting.precision, formatString),
34535 value2: value2
34536 };
34537 var cacheKey = JSON.stringify(cacheKeyObject);
34538 if (!this.cache[cacheKey])
34539 this.cache[cacheKey] = visuals.valueFormatter.create(getOptionsForLabelFormatter(labelSetting, formatString, value2, cacheKeyObject.precision));
34540 return this.cache[cacheKey];
34541 }
34542 if (!this.cache.defaultFormatter) {
34543 this.cache.defaultFormatter = visuals.valueFormatter.create(getOptionsForLabelFormatter(labelSetting, formatString, value2, labelSetting.precision));
34544 }
34545 return this.cache.defaultFormatter;
34546 }
34547 };
34548 }
34549 NewDataLabelUtils.createColumnFormatterCacheManager = createColumnFormatterCacheManager;
34550 function getOptionsForLabelFormatter(labelSetting, formatString, value2, precision) {
34551 return {
34552 displayUnitSystemType: powerbi.DisplayUnitSystemType.DataLabels,
34553 format: formatString,
34554 precision: precision,
34555 value: labelSetting.displayUnits,
34556 value2: value2,
34557 allowFormatBeautification: true,
34558 };
34559 }
34560 function removeDuplicates(labelDataPoints) {
34561 var uniqueLabelDataPoints = [];
34562 var labelDataPointMap = {};
34563 var sameParentIsInArray = function (newValue, array, parentIsRect) {
34564 return array.some(function (arrayValue) {
34565 if (parentIsRect) {
34566 return visuals.shapes.Rect.equals(newValue.parentShape.rect, arrayValue.rect);
34567 }
34568 else {
34569 return visuals.shapes.Point.equals(newValue.parentShape.point, arrayValue.point);
34570 }
34571 });
34572 };
34573 for (var _i = 0, labelDataPoints_1 = labelDataPoints; _i < labelDataPoints_1.length; _i++) {
34574 var dataPoint = labelDataPoints_1[_i];
34575 var parentIsRect = dataPoint.parentType === 1 /* Rectangle */;
34576 var resultsFromMap = labelDataPointMap[dataPoint.text];
34577 if (!resultsFromMap) {
34578 uniqueLabelDataPoints.push(dataPoint);
34579 labelDataPointMap[dataPoint.text] = [dataPoint.parentShape];
34580 }
34581 else {
34582 if (!sameParentIsInArray(dataPoint, resultsFromMap, parentIsRect)) {
34583 uniqueLabelDataPoints.push(dataPoint);
34584 resultsFromMap.push(dataPoint.parentShape);
34585 }
34586 }
34587 }
34588 return uniqueLabelDataPoints;
34589 }
34590 NewDataLabelUtils.removeDuplicates = removeDuplicates;
34591 function getDataLabelLayoutOptions(type) {
34592 switch (type) {
34593 case 9 /* Scatter */:
34594 return {
34595 maximumOffset: visuals.ScatterChart.dataLabelLayoutMaximumOffset,
34596 startingOffset: visuals.ScatterChart.dataLabelLayoutStartingOffset,
34597 offsetIterationDelta: visuals.ScatterChart.dataLabelLayoutOffsetIterationDelta,
34598 allowLeaderLines: true,
34599 attemptToMoveLabelsIntoViewport: true,
34600 };
34601 default:
34602 return {
34603 maximumOffset: NewDataLabelUtils.maxLabelOffset,
34604 startingOffset: NewDataLabelUtils.startingLabelOffset,
34605 attemptToMoveLabelsIntoViewport: true,
34606 };
34607 }
34608 }
34609 NewDataLabelUtils.getDataLabelLayoutOptions = getDataLabelLayoutOptions;
34610 function getTextSize(text, fontSize) {
34611 var labelTextProperties = NewDataLabelUtils.LabelTextProperties;
34612 var properties = {
34613 text: text,
34614 fontFamily: labelTextProperties.fontFamily,
34615 fontSize: jsCommon.PixelConverter.fromPoint(fontSize),
34616 fontWeight: labelTextProperties.fontWeight,
34617 };
34618 return {
34619 width: powerbi.TextMeasurementService.measureSvgTextWidth(properties),
34620 height: powerbi.TextMeasurementService.estimateSvgTextHeight(properties),
34621 };
34622 }
34623 NewDataLabelUtils.getTextSize = getTextSize;
34624 /**
34625 * Obtains the key from the label. Index is required to use as a backup in cases
34626 * where labels have no key or identity.
34627 */
34628 function labelKeyFunction(label, index) {
34629 if (label.key) {
34630 return label.key;
34631 }
34632 if (label.identity) {
34633 return label.identity.getKeyWithoutHighlight();
34634 }
34635 return index;
34636 }
34637 })(NewDataLabelUtils = visuals.NewDataLabelUtils || (visuals.NewDataLabelUtils = {}));
34638 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
34639})(powerbi || (powerbi = {}));
34640/*
34641 * Power BI Visualizations
34642 *
34643 * Copyright (c) Microsoft Corporation
34644 * All rights reserved.
34645 * MIT License
34646 *
34647 * Permission is hereby granted, free of charge, to any person obtaining a copy
34648 * of this software and associated documentation files (the ""Software""), to deal
34649 * in the Software without restriction, including without limitation the rights
34650 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34651 * copies of the Software, and to permit persons to whom the Software is
34652 * furnished to do so, subject to the following conditions:
34653 *
34654 * The above copyright notice and this permission notice shall be included in
34655 * all copies or substantial portions of the Software.
34656 *
34657 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34658 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34659 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34660 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34661 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34662 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34663 * THE SOFTWARE.
34664 */
34665var powerbi;
34666(function (powerbi) {
34667 var visuals;
34668 (function (visuals) {
34669 var KpiUtil;
34670 (function (KpiUtil) {
34671 var KPIImageClassName = 'powervisuals-glyph';
34672 var BigImageClassName = 'big-kpi';
34673 var RYGStatusIconClassNames = ['kpi-red', 'kpi-yellow', 'kpi-green'];
34674 var threeLights = {
34675 kpiIconClass: 'circle',
34676 statusValues: RYGStatusIconClassNames,
34677 };
34678 var roadSigns = {
34679 kpiIconClass: '',
34680 statusValues: ['circle-x kpi-red', 'circle-exclamation kpi-yellow', 'circle-checkmark kpi-green'],
34681 };
34682 var trafficLight = {
34683 kpiIconClass: 'traffic-light',
34684 statusValues: RYGStatusIconClassNames,
34685 };
34686 var shapes = {
34687 kpiIconClass: '',
34688 statusValues: ['rhombus kpi-red', 'triangle kpi-yellow', 'circle kpi-green'],
34689 };
34690 var gauge = {
34691 kpiIconClass: '',
34692 statusValues: ['circle-empty', 'circle-one-quarter', 'circle-half', 'circle-three-quarters', 'circle-full'],
34693 };
34694 var statusGraphicFormatStrings = {
34695 'THREE CIRCLES COLORED': threeLights,
34696 'TRAFFIC LIGHT - SINGLE': threeLights,
34697 'THREE FLAGS COLORED': {
34698 kpiIconClass: 'flag',
34699 statusValues: RYGStatusIconClassNames,
34700 },
34701 'ROAD SIGNS': roadSigns,
34702 'THREE SYMBOLS CIRCLED COLORED': roadSigns,
34703 'TRAFFIC LIGHT': trafficLight,
34704 'THREE TRAFFIC LIGHTS RIMMED COLORED': trafficLight,
34705 'THREE SYMBOLS UNCIRCLED COLORED': {
34706 kpiIconClass: '',
34707 statusValues: ['x kpi-red', 'exclamation kpi-yellow', 'checkmark kpi-green'],
34708 },
34709 'SHAPES': shapes,
34710 'SMILEY FACE': shapes,
34711 'THERMOMETER': shapes,
34712 'CYLINDER': shapes,
34713 'THREE SIGNS COLORED': shapes,
34714 'THREE STARS COLORED': {
34715 kpiIconClass: 'star-stacked',
34716 statusValues: ['star-empty', 'star-half-full', 'star-full'],
34717 },
34718 'FIVE BARS COLORED': {
34719 kpiIconClass: 'bars-stacked',
34720 statusValues: ['bars-zero', 'bars-one', 'bars-two', 'bars-three', 'bars-four'],
34721 },
34722 'FIVE BOXES COLORED': {
34723 kpiIconClass: 'boxes-stacked',
34724 statusValues: ['boxes-zero', 'boxes-one', 'boxes-two', 'boxes-three', 'boxes-four'],
34725 },
34726 'FIVE QUARTERS COLORED': gauge,
34727 'GAUGE - ASCENDING': gauge,
34728 'GAUGE - DESCENDING': {
34729 kpiIconClass: '',
34730 statusValues: ['circle-full', 'circle-three-quarters', 'circle-half', 'circle-one-quarter', 'circle-empty'],
34731 },
34732 'STANDARD ARROW': {
34733 kpiIconClass: '',
34734 statusValues: ['arrow-down', 'arrow-right-down', 'arrow-right', 'arrow-right-up', 'arrow-up'],
34735 },
34736 'VARIANCE ARROW': {
34737 kpiIconClass: '',
34738 statusValues: ['arrow-down kpi-red', 'arrow-right kpi-yellow', 'arrow-up kpi-green'],
34739 },
34740 'STATUS ARROW - ASCENDING': {
34741 kpiIconClass: '',
34742 statusValues: ['arrow-down kpi-red', 'arrow-right-down kpi-yellow', 'arrow-right kpi-yellow', 'arrow-right-up kpi-yellow', 'arrow-up kpi-green'],
34743 },
34744 'STATUS ARROW - DESCENDING': {
34745 kpiIconClass: '',
34746 statusValues: ['arrow-up kpi-green', 'arrow-right-up kpi-yellow', 'arrow-right kpi-yellow', 'arrow-right-down kpi-yellow', 'arrow-down kpi-red'],
34747 },
34748 };
34749 function getKpiIcon(kpi, value) {
34750 var numValue = parseFloat(value);
34751 if (!kpi)
34752 return;
34753 var statusGraphicFormat = statusGraphicFormatStrings[kpi.graphic.toUpperCase()];
34754 if (!statusGraphicFormat || isNaN(numValue))
34755 return undefined;
34756 var statusValues = statusGraphicFormat.statusValues;
34757 // Normalize range of (-1, -0.5, 0, 0.5, 1) to (-2, -1, 0, 1, 2)
34758 if (kpi.normalizedFiveStateKpiRange && statusValues.length === 5)
34759 numValue = numValue * 2;
34760 // Convert values from the range of (-n/2, ..., 0, ..., n/2) to (0, 1, ..., n-1)
34761 var num = numValue + Math.floor(statusValues.length / 2);
34762 return [statusGraphicFormat.kpiIconClass, statusValues[num]].join(' ').trim();
34763 }
34764 function getKpiIconClassName(kpiIcon, kpiImageSize) {
34765 if (!kpiIcon)
34766 return undefined;
34767 if (kpiImageSize === 1 /* Big */)
34768 return [KPIImageClassName, BigImageClassName, kpiIcon].join(' ');
34769 else
34770 return [KPIImageClassName, kpiIcon].join(' ');
34771 }
34772 function getClassForKpi(kpi, value, kpiImageSize) {
34773 debug.assertValue(kpi, 'kpi');
34774 debug.assertValue(value, 'value');
34775 var kpiIcon = getKpiIcon(kpi, value);
34776 return getKpiIconClassName(kpiIcon, kpiImageSize);
34777 }
34778 KpiUtil.getClassForKpi = getClassForKpi;
34779 function getKpiImageMetadata(metaDataColumn, value, kpiImageSize) {
34780 var kpi = metaDataColumn && metaDataColumn.kpi;
34781 if (kpi) {
34782 var kpiIcon = getKpiIcon(kpi, value);
34783 if (kpiIcon) {
34784 return {
34785 caption: kpiIcon,
34786 statusGraphic: kpi.graphic,
34787 class: getKpiIconClassName(kpiIcon, kpiImageSize),
34788 };
34789 }
34790 }
34791 }
34792 KpiUtil.getKpiImageMetadata = getKpiImageMetadata;
34793 })(KpiUtil = visuals.KpiUtil || (visuals.KpiUtil = {}));
34794 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
34795})(powerbi || (powerbi = {}));
34796/*
34797 * Power BI Visualizations
34798 *
34799 * Copyright (c) Microsoft Corporation
34800 * All rights reserved.
34801 * MIT License
34802 *
34803 * Permission is hereby granted, free of charge, to any person obtaining a copy
34804 * of this software and associated documentation files (the ""Software""), to deal
34805 * in the Software without restriction, including without limitation the rights
34806 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34807 * copies of the Software, and to permit persons to whom the Software is
34808 * furnished to do so, subject to the following conditions:
34809 *
34810 * The above copyright notice and this permission notice shall be included in
34811 * all copies or substantial portions of the Software.
34812 *
34813 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34814 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34815 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34816 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34817 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34818 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34819 * THE SOFTWARE.
34820 */
34821var powerbi;
34822(function (powerbi) {
34823 var visuals;
34824 (function (visuals) {
34825 var ReferenceLineHelper;
34826 (function (ReferenceLineHelper) {
34827 ReferenceLineHelper.referenceLineProps = {
34828 show: 'show',
34829 lineColor: 'lineColor',
34830 transparency: 'transparency',
34831 value: 'value',
34832 style: 'style',
34833 position: 'position',
34834 dataLabelShow: 'dataLabelShow',
34835 dataLabelColor: 'dataLabelColor',
34836 dataLabelDecimalPoints: 'dataLabelDecimalPoints',
34837 dataLabelHorizontalPosition: 'dataLabelHorizontalPosition',
34838 dataLabelVerticalPosition: 'dataLabelVerticalPosition',
34839 dataLabelDisplayUnits: 'dataLabelDisplayUnits',
34840 };
34841 function enumerateObjectInstances(enumeration, referenceLines, defaultColor, objectName) {
34842 debug.assertValue(enumeration, 'enumeration');
34843 if (_.isEmpty(referenceLines)) {
34844 // NOTE: We do not currently have support for object maps in the property pane. For now we will generate a single reference line
34845 // object that the format pane can handle.In the future we will need property pane support for multiple reference lines. Also, we're
34846 // assuming that the user-defined IDs will be numeric strings, this may change in the future and will likley be controlled by the property pane.
34847 var instance = {
34848 selector: {
34849 id: '0'
34850 },
34851 properties: {
34852 show: false,
34853 value: '',
34854 lineColor: { solid: { color: defaultColor } },
34855 transparency: 50,
34856 style: visuals.lineStyle.dashed,
34857 position: visuals.referenceLinePosition.back,
34858 dataLabelShow: false,
34859 },
34860 objectName: objectName
34861 };
34862 enumeration.pushInstance(instance);
34863 return;
34864 }
34865 for (var _i = 0, referenceLines_1 = referenceLines; _i < referenceLines_1.length; _i++) {
34866 var referenceLine = referenceLines_1[_i];
34867 var referenceLineProperties = referenceLine.object;
34868 var show = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.show, false);
34869 var value = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.value);
34870 var lineColor = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.lineColor, { solid: { color: defaultColor } });
34871 var transparency = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.transparency, 50);
34872 var style = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.style, visuals.lineStyle.dashed);
34873 var position = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.position, visuals.referenceLinePosition.back);
34874 var dataLabelShow = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelShow, false);
34875 var instance = {
34876 selector: {
34877 id: referenceLine.id
34878 },
34879 properties: {
34880 show: show,
34881 value: value,
34882 lineColor: lineColor,
34883 transparency: transparency,
34884 style: style,
34885 position: position,
34886 dataLabelShow: dataLabelShow,
34887 },
34888 objectName: objectName
34889 };
34890 // Show the data label properties only if the user chose to show the data label
34891 if (dataLabelShow) {
34892 var dataLabelColor = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelColor, { solid: { color: defaultColor } });
34893 var dataLabelHorizontalPosition = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelHorizontalPosition, visuals.referenceLineDataLabelHorizontalPosition.left);
34894 var dataLabelVerticalPosition = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelVerticalPosition, visuals.referenceLineDataLabelVerticalPosition.above);
34895 var dataLabelDecimalPoints = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelDecimalPoints, undefined) < 0
34896 ? undefined
34897 : powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelDecimalPoints, undefined);
34898 var dataLabelDisplayUnits = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelDisplayUnits, 0);
34899 instance.properties[ReferenceLineHelper.referenceLineProps.dataLabelColor] = dataLabelColor;
34900 instance.properties[ReferenceLineHelper.referenceLineProps.dataLabelHorizontalPosition] = dataLabelHorizontalPosition;
34901 instance.properties[ReferenceLineHelper.referenceLineProps.dataLabelVerticalPosition] = dataLabelVerticalPosition;
34902 instance.properties[ReferenceLineHelper.referenceLineProps.dataLabelDecimalPoints] = dataLabelDecimalPoints;
34903 instance.properties[ReferenceLineHelper.referenceLineProps.dataLabelDisplayUnits] = dataLabelDisplayUnits;
34904 }
34905 enumeration.pushInstance(instance);
34906 }
34907 }
34908 ReferenceLineHelper.enumerateObjectInstances = enumerateObjectInstances;
34909 function render(options) {
34910 var graphicContext = options.graphicContext;
34911 var axes = options.axes;
34912 var referenceLineProperties = options.referenceLineProperties;
34913 var isHorizontal = options.isHorizontal;
34914 var viewport = options.viewport;
34915 var classAndSelector = options.classAndSelector;
34916 var xScale = axes.x.scale;
34917 var yScale = axes.y1.scale;
34918 var refValue = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.value, 0);
34919 var lineColor = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.lineColor, { solid: { color: options.defaultColor } });
34920 var transparency = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.transparency);
34921 var style = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.style, visuals.lineStyle.dashed);
34922 var position = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.position, visuals.referenceLinePosition.back);
34923 var refLine = graphicContext.select(classAndSelector.selector);
34924 var index = $(refLine[0]).index();
34925 var currentPosition = index > 1 ? visuals.referenceLinePosition.front : visuals.referenceLinePosition.back;
34926 var isRefLineExists = index !== -1;
34927 var isPositionChanged = currentPosition !== position;
34928 if (isRefLineExists && isPositionChanged)
34929 refLine.remove();
34930 if (!isRefLineExists || isPositionChanged)
34931 refLine = (position === visuals.referenceLinePosition.back) ? graphicContext.insert('line', ":first-child") : graphicContext.append('line');
34932 var refLineX1 = isHorizontal ? 0 : xScale(refValue);
34933 var refLineY1 = isHorizontal ? yScale(refValue) : 0;
34934 var refLineX2 = isHorizontal ? viewport.width : xScale(refValue);
34935 var refLineY2 = isHorizontal ? yScale(refValue) : viewport.height;
34936 refLine.attr({
34937 'class': classAndSelector.class,
34938 x1: refLineX1,
34939 y1: refLineY1,
34940 x2: refLineX2,
34941 y2: refLineY2,
34942 })
34943 .style({
34944 'stroke': lineColor.solid.color,
34945 });
34946 if (transparency != null)
34947 refLine.style('stroke-opacity', ((100 - transparency) / 100));
34948 if (style === visuals.lineStyle.dashed) {
34949 refLine.style('stroke-dasharray', ("5, 5"));
34950 }
34951 else if (style === visuals.lineStyle.dotted) {
34952 refLine.style({
34953 'stroke-dasharray': ("1, 5"),
34954 'stroke-linecap': "round"
34955 });
34956 }
34957 else if (style === visuals.lineStyle.solid) {
34958 refLine.style({
34959 'stroke-dasharray': null,
34960 'stroke-linecap': null
34961 });
34962 }
34963 }
34964 ReferenceLineHelper.render = render;
34965 function createLabelDataPoint(options) {
34966 var offsetRefLine = 5;
34967 var axes = options.axes;
34968 var referenceLineProperties = options.referenceLineProperties;
34969 var isHorizontal = options.isHorizontal;
34970 var viewport = options.viewport;
34971 var xScale = axes.x.scale;
34972 var yScale = axes.y1.scale;
34973 // Get the data label properties
34974 var refValue = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.value, 0);
34975 var color = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelColor, { solid: { color: options.defaultColor } });
34976 var decimalPoints = (referenceLineProperties[ReferenceLineHelper.referenceLineProps.dataLabelDecimalPoints] < 0 ? undefined : referenceLineProperties[ReferenceLineHelper.referenceLineProps.dataLabelDecimalPoints]);
34977 var horizontalPosition = referenceLineProperties[ReferenceLineHelper.referenceLineProps.dataLabelHorizontalPosition] || visuals.referenceLineDataLabelHorizontalPosition.left;
34978 var verticalPosition = referenceLineProperties[ReferenceLineHelper.referenceLineProps.dataLabelVerticalPosition] || visuals.referenceLineDataLabelVerticalPosition.above;
34979 var displayUnits = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.dataLabelDisplayUnits, 0);
34980 // Format the reference line data label text according to the matching axis formatter
34981 // When options is null default formatter is used either boolean, numeric, or text
34982 var axisFormatter = isHorizontal ? axes.y1.formatter : axes.x.formatter;
34983 var formatterForReferenceLineDataLabel = axisFormatter;
34984 if (axisFormatter.options != null) {
34985 var formatterOptions = powerbi.Prototype.inherit(axisFormatter.options);
34986 formatterOptions.precision = decimalPoints;
34987 formatterOptions.value = displayUnits;
34988 formatterOptions.detectAxisPrecision = false;
34989 formatterForReferenceLineDataLabel = visuals.valueFormatter.create(formatterOptions);
34990 }
34991 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatterForReferenceLineDataLabel.format(refValue));
34992 var properties = {
34993 text: text,
34994 fontFamily: visuals.dataLabelUtils.LabelTextProperties.fontFamily,
34995 fontSize: visuals.dataLabelUtils.LabelTextProperties.fontSize,
34996 fontWeight: visuals.dataLabelUtils.LabelTextProperties.fontWeight,
34997 };
34998 // Get the height and with of the text element that will be created in order to place it correctly
34999 var rectWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
35000 var rectHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
35001 var dataLabelX;
35002 var dataLabelY;
35003 var x1 = isHorizontal ? 0 : xScale(refValue);
35004 var y1 = isHorizontal ? yScale(refValue) : 0;
35005 var x2 = isHorizontal ? viewport.width : xScale(refValue);
35006 var y2 = isHorizontal ? yScale(refValue) : viewport.height;
35007 var validPositions = [1 /* Above */];
35008 if (isHorizontal) {
35009 // Horizontal line. y1 = y2
35010 dataLabelX = (horizontalPosition === visuals.referenceLineDataLabelHorizontalPosition.left) ? x1 + offsetRefLine : x2 - (rectWidth / 2) - offsetRefLine;
35011 dataLabelY = y1;
35012 validPositions = (verticalPosition === visuals.referenceLineDataLabelVerticalPosition.above) ? [1 /* Above */] : [2 /* Below */];
35013 }
35014 else {
35015 // Vertical line. x1 = x2
35016 dataLabelX = x1;
35017 dataLabelY = (verticalPosition === visuals.referenceLineDataLabelVerticalPosition.above) ? y1 + (rectHeight / 2) + offsetRefLine : y2 - (rectHeight / 2) - offsetRefLine;
35018 validPositions = (horizontalPosition === visuals.referenceLineDataLabelHorizontalPosition.left) ? [4 /* Left */] : [8 /* Right */];
35019 }
35020 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
35021 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
35022 var parentShape;
35023 parentShape = {
35024 point: {
35025 x: dataLabelX,
35026 y: dataLabelY,
35027 },
35028 radius: 0,
35029 validPositions: validPositions,
35030 };
35031 return {
35032 isPreferred: true,
35033 text: text,
35034 textSize: {
35035 width: textWidth,
35036 height: textHeight,
35037 },
35038 outsideFill: color.solid.color,
35039 insideFill: null,
35040 parentShape: parentShape,
35041 parentType: 0 /* Point */,
35042 fontSize: 9,
35043 identity: null,
35044 secondRowText: null,
35045 key: options.key,
35046 };
35047 }
35048 ReferenceLineHelper.createLabelDataPoint = createLabelDataPoint;
35049 function extractReferenceLineValue(referenceLineProperties) {
35050 var referenceLineValue = null;
35051 if (referenceLineProperties && powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.show, false))
35052 referenceLineValue = powerbi.DataViewObject.getValue(referenceLineProperties, ReferenceLineHelper.referenceLineProps.value, null);
35053 return referenceLineValue;
35054 }
35055 ReferenceLineHelper.extractReferenceLineValue = extractReferenceLineValue;
35056 })(ReferenceLineHelper = visuals.ReferenceLineHelper || (visuals.ReferenceLineHelper = {}));
35057 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
35058})(powerbi || (powerbi = {}));
35059/*
35060 * Power BI Visualizations
35061 *
35062 * Copyright (c) Microsoft Corporation
35063 * All rights reserved.
35064 * MIT License
35065 *
35066 * Permission is hereby granted, free of charge, to any person obtaining a copy
35067 * of this software and associated documentation files (the ""Software""), to deal
35068 * in the Software without restriction, including without limitation the rights
35069 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35070 * copies of the Software, and to permit persons to whom the Software is
35071 * furnished to do so, subject to the following conditions:
35072 *
35073 * The above copyright notice and this permission notice shall be included in
35074 * all copies or substantial portions of the Software.
35075 *
35076 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35077 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35078 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35079 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35080 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35081 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35082 * THE SOFTWARE.
35083 */
35084var powerbi;
35085(function (powerbi) {
35086 var visuals;
35087 (function (visuals) {
35088 var InteractivityUtils;
35089 (function (InteractivityUtils) {
35090 function getPositionOfLastInputEvent() {
35091 return {
35092 x: d3.event.clientX,
35093 y: d3.event.clientY
35094 };
35095 }
35096 InteractivityUtils.getPositionOfLastInputEvent = getPositionOfLastInputEvent;
35097 function registerStandardInteractivityHandlers(selection, selectionHandler) {
35098 registerStandardSelectionHandler(selection, selectionHandler);
35099 registerStandardContextMenuHandler(selection, selectionHandler);
35100 }
35101 InteractivityUtils.registerStandardInteractivityHandlers = registerStandardInteractivityHandlers;
35102 function registerStandardSelectionHandler(selection, selectionHandler) {
35103 selection.on('click', function (d) { return handleSelection(d, selectionHandler); });
35104 }
35105 InteractivityUtils.registerStandardSelectionHandler = registerStandardSelectionHandler;
35106 function registerStandardContextMenuHandler(selection, selectionHandler) {
35107 selection.on('contextmenu', function (d) { return handleContextMenu(d, selectionHandler); });
35108 }
35109 InteractivityUtils.registerStandardContextMenuHandler = registerStandardContextMenuHandler;
35110 function registerGroupInteractivityHandlers(group, selectionHandler) {
35111 registerGroupSelectionHandler(group, selectionHandler);
35112 registerGroupContextMenuHandler(group, selectionHandler);
35113 }
35114 InteractivityUtils.registerGroupInteractivityHandlers = registerGroupInteractivityHandlers;
35115 function registerGroupSelectionHandler(group, selectionHandler) {
35116 group.on('click', function () {
35117 var target = d3.event.target;
35118 var d = d3.select(target).datum();
35119 handleSelection(d, selectionHandler);
35120 });
35121 }
35122 InteractivityUtils.registerGroupSelectionHandler = registerGroupSelectionHandler;
35123 function registerGroupContextMenuHandler(group, selectionHandler) {
35124 group.on('contextmenu', function () {
35125 var target = d3.event.target;
35126 var d = d3.select(target).datum();
35127 handleContextMenu(d, selectionHandler);
35128 });
35129 }
35130 InteractivityUtils.registerGroupContextMenuHandler = registerGroupContextMenuHandler;
35131 function handleContextMenu(d, selectionHandler) {
35132 if (d3.event.ctrlKey)
35133 return;
35134 d3.event.preventDefault();
35135 var position = InteractivityUtils.getPositionOfLastInputEvent();
35136 selectionHandler.handleContextMenu(d, position);
35137 }
35138 function handleSelection(d, selectionHandler) {
35139 selectionHandler.handleSelection(d, d3.event.ctrlKey);
35140 }
35141 })(InteractivityUtils = visuals.InteractivityUtils || (visuals.InteractivityUtils = {}));
35142 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
35143})(powerbi || (powerbi = {}));
35144/*
35145 * Power BI Visualizations
35146 *
35147 * Copyright (c) Microsoft Corporation
35148 * All rights reserved.
35149 * MIT License
35150 *
35151 * Permission is hereby granted, free of charge, to any person obtaining a copy
35152 * of this software and associated documentation files (the ""Software""), to deal
35153 * in the Software without restriction, including without limitation the rights
35154 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35155 * copies of the Software, and to permit persons to whom the Software is
35156 * furnished to do so, subject to the following conditions:
35157 *
35158 * The above copyright notice and this permission notice shall be included in
35159 * all copies or substantial portions of the Software.
35160 *
35161 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35162 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35163 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35164 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35165 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35166 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35167 * THE SOFTWARE.
35168 */
35169var powerbi;
35170(function (powerbi) {
35171 var visuals;
35172 (function (visuals) {
35173 function getInvalidValueWarnings(dataViews, supportsNaN, supportsNegativeInfinity, supportsPositiveInfinity) {
35174 var checker = new InvalidDataValuesChecker(supportsNaN /*supportsNaN*/, supportsNegativeInfinity /*supportsNegativeInfinity*/, supportsPositiveInfinity /*supportsPositiveInfinity*/);
35175 // Show a warning if necessary.
35176 return checker.getWarningMessages(dataViews);
35177 }
35178 visuals.getInvalidValueWarnings = getInvalidValueWarnings;
35179 var InvalidDataValuesChecker = (function () {
35180 function InvalidDataValuesChecker(supportsNaN, supportsNegativeInfinity, supportsPositiveInfinity) {
35181 this.supportsNaN = supportsNaN;
35182 this.supportsNegativeInfinity = supportsNegativeInfinity;
35183 this.supportsPositiveInfinity = supportsPositiveInfinity;
35184 }
35185 InvalidDataValuesChecker.prototype.getWarningMessages = function (dataViews) {
35186 this.loadWarningStatus(dataViews);
35187 var warnings = [];
35188 if (this.hasNaN && !this.supportsNaN) {
35189 warnings.push(new visuals.NaNNotSupportedWarning());
35190 }
35191 if ((this.hasNegativeInfinity && !this.supportsNegativeInfinity)
35192 || (this.hasPositiveInfinity && !this.supportsPositiveInfinity)) {
35193 warnings.push(new visuals.InfinityValuesNotSupportedWarning());
35194 }
35195 if (this.hasOutOfRange) {
35196 warnings.push(new visuals.ValuesOutOfRangeWarning());
35197 }
35198 return warnings;
35199 };
35200 InvalidDataValuesChecker.prototype.loadWarningStatus = function (dataViews) {
35201 this.hasNaN = false;
35202 this.hasNegativeInfinity = false;
35203 this.hasOutOfRange = false;
35204 this.hasPositiveInfinity = false;
35205 for (var k = 0; k < dataViews.length; k++) {
35206 var dataView = dataViews[k];
35207 var values = dataView && dataView.categorical && dataView.categorical.values
35208 ? dataView.categorical.values
35209 : null;
35210 if (!values)
35211 return;
35212 var valueLength = values.length;
35213 for (var i = 0; i < valueLength; i++) {
35214 var value = values[i];
35215 if (value.values) {
35216 var valueValueLength = value.values.length;
35217 for (var j = 0; j < valueValueLength; j++) {
35218 var v = value.values[j];
35219 if (isNaN(v))
35220 this.hasNaN = true;
35221 else if (v === Number.POSITIVE_INFINITY)
35222 this.hasPositiveInfinity = true;
35223 else if (v === Number.NEGATIVE_INFINITY)
35224 this.hasNegativeInfinity = true;
35225 else if (v < -1e300 || v > 1e300)
35226 this.hasOutOfRange = true;
35227 }
35228 }
35229 }
35230 }
35231 };
35232 return InvalidDataValuesChecker;
35233 }());
35234 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
35235})(powerbi || (powerbi = {}));
35236/*
35237 * Power BI Visualizations
35238 *
35239 * Copyright (c) Microsoft Corporation
35240 * All rights reserved.
35241 * MIT License
35242 *
35243 * Permission is hereby granted, free of charge, to any person obtaining a copy
35244 * of this software and associated documentation files (the ""Software""), to deal
35245 * in the Software without restriction, including without limitation the rights
35246 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35247 * copies of the Software, and to permit persons to whom the Software is
35248 * furnished to do so, subject to the following conditions:
35249 *
35250 * The above copyright notice and this permission notice shall be included in
35251 * all copies or substantial portions of the Software.
35252 *
35253 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35254 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35255 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35256 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35257 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35258 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35259 * THE SOFTWARE.
35260 */
35261var powerbi;
35262(function (powerbi) {
35263 var visuals;
35264 (function (visuals) {
35265 var ListViewFactory;
35266 (function (ListViewFactory) {
35267 function createListView(options) {
35268 return new ListView(options);
35269 }
35270 ListViewFactory.createListView = createListView;
35271 })(ListViewFactory = visuals.ListViewFactory || (visuals.ListViewFactory = {}));
35272 /**
35273 * A UI Virtualized List, that uses the D3 Enter, Update & Exit pattern to update rows.
35274 * It can create lists containing either HTML or SVG elements.
35275 */
35276 var ListView = (function () {
35277 function ListView(options) {
35278 var _this = this;
35279 // make a copy of options so that it is not modified later by caller
35280 this.options = $.extend(true, {}, options);
35281 this.scrollbarInner = options.baseContainer
35282 .append('div')
35283 .classed('scrollbar-inner', true)
35284 .on('scroll', function () { return _this.renderImpl(_this.options.rowHeight); });
35285 this.scrollContainer = this.scrollbarInner
35286 .append('div')
35287 .classed('scrollRegion', true)
35288 .on('touchstart', function () { return _this.stopTouchPropagation(); })
35289 .on('touchmove', function () { return _this.stopTouchPropagation(); });
35290 this.visibleGroupContainer = this.scrollContainer
35291 .append('div')
35292 .classed('visibleGroup', true);
35293 $(options.baseContainer.node()).find('.scroll-element').attr('drag-resize-disabled', 'true');
35294 ListView.SetDefaultOptions(options);
35295 }
35296 ListView.SetDefaultOptions = function (options) {
35297 options.rowHeight = options.rowHeight || ListView.defaultRowHeight;
35298 };
35299 ListView.prototype.rowHeight = function (rowHeight) {
35300 this.options.rowHeight = Math.ceil(rowHeight);
35301 return this;
35302 };
35303 ListView.prototype.data = function (data, getDatumIndex, dataReset) {
35304 if (dataReset === void 0) { dataReset = false; }
35305 this._data = data;
35306 this.getDatumIndex = getDatumIndex;
35307 this.setTotalRows();
35308 if (dataReset)
35309 $(this.scrollbarInner.node()).scrollTop(0);
35310 this.render();
35311 return this;
35312 };
35313 ListView.prototype.viewport = function (viewport) {
35314 this.options.viewport = viewport;
35315 this.render();
35316 return this;
35317 };
35318 ListView.prototype.empty = function () {
35319 this._data = [];
35320 this.render();
35321 };
35322 ListView.prototype.render = function () {
35323 var _this = this;
35324 if (this.renderTimeoutId)
35325 window.clearTimeout(this.renderTimeoutId);
35326 this.renderTimeoutId = window.setTimeout(function () {
35327 _this.getRowHeight().then(function (rowHeight) {
35328 _this.renderImpl(rowHeight);
35329 });
35330 _this.renderTimeoutId = undefined;
35331 }, 0);
35332 };
35333 ListView.prototype.renderImpl = function (rowHeight) {
35334 var totalHeight = this.options.scrollEnabled ? Math.max(0, (this._totalRows * rowHeight)) : this.options.viewport.height;
35335 this.scrollContainer
35336 .style('height', totalHeight + "px")
35337 .attr('height', totalHeight);
35338 this.scrollToFrame(true /*loadMoreData*/);
35339 };
35340 /*
35341 * This method is called in order to prevent a bug found in the Interact.js.
35342 * The bug is caused when finishing a scroll outside the scroll area.
35343 * In that case the Interact doesn't process a touchcancel event and thinks a touch point still exists.
35344 * since the Interact listens on the visualContainer, by stoping the propagation we prevent the bug from taking place.
35345 */
35346 ListView.prototype.stopTouchPropagation = function () {
35347 //Stop the propagation only in read mode so the drag won't be affected.
35348 if (this.options.isReadMode()) {
35349 if (d3.event.type === "touchstart") {
35350 var event_1 = d3.event;
35351 //If there is another touch point outside this visual than the event should be propagated.
35352 //This way the pinch to zoom will not be affected.
35353 if (event_1.touches && event_1.touches.length === 1) {
35354 d3.event.stopPropagation();
35355 }
35356 }
35357 if (d3.event.type === "touchmove") {
35358 d3.event.stopPropagation();
35359 }
35360 }
35361 };
35362 ListView.prototype.scrollToFrame = function (loadMoreData) {
35363 var options = this.options;
35364 var visibleGroupContainer = this.visibleGroupContainer;
35365 var totalRows = this._totalRows;
35366 var rowHeight = options.rowHeight || ListView.defaultRowHeight;
35367 var visibleRows = this.getVisibleRows() || 1;
35368 var scrollTop = this.scrollbarInner.node().scrollTop;
35369 var scrollPosition = (scrollTop === 0) ? 0 : Math.floor(scrollTop / rowHeight);
35370 var transformAttr = visuals.SVGUtil.translateWithPixels(0, scrollPosition * rowHeight);
35371 visibleGroupContainer.style({
35372 //order matters for proper overriding
35373 'transform': function (d) { return transformAttr; },
35374 '-webkit-transform': transformAttr
35375 });
35376 var position0 = Math.max(0, Math.min(scrollPosition, totalRows - visibleRows + 1)), position1 = position0 + visibleRows;
35377 if (this.options.scrollEnabled) {
35378 // Subtract the amount of height of the top row that's hidden when it's partially visible.
35379 var topRowHiddenHeight = scrollTop - (scrollPosition * rowHeight);
35380 var halfRowHeight = rowHeight * 0.5;
35381 // If more than half the top row is hidden, we'll need to render an extra item at the bottom
35382 if (topRowHiddenHeight > halfRowHeight) {
35383 position1++; // Add 1 to handle when rows are partially visible (when scrolling)
35384 }
35385 }
35386 var rowSelection = visibleGroupContainer.selectAll(".row")
35387 .data(this._data.slice(position0, Math.min(position1, totalRows)), this.getDatumIndex);
35388 rowSelection
35389 .enter()
35390 .append('div')
35391 .classed('row', true)
35392 .call(function (d) { return options.enter(d); });
35393 rowSelection.order();
35394 var rowUpdateSelection = visibleGroupContainer.selectAll('.row:not(.transitioning)');
35395 rowUpdateSelection.call(function (d) { return options.update(d); });
35396 rowSelection
35397 .exit()
35398 .call(function (d) { return options.exit(d); })
35399 .remove();
35400 if (loadMoreData && visibleRows !== totalRows && position1 >= totalRows * ListView.loadMoreDataThreshold)
35401 options.loadMoreData();
35402 };
35403 ListView.prototype.setTotalRows = function () {
35404 var data = this._data;
35405 this._totalRows = data ? data.length : 0;
35406 };
35407 ListView.prototype.getVisibleRows = function () {
35408 var minimumVisibleRows = 1;
35409 var rowHeight = this.options.rowHeight;
35410 var viewportHeight = this.options.viewport.height;
35411 if (!rowHeight || rowHeight < 1)
35412 return minimumVisibleRows;
35413 if (this.options.scrollEnabled)
35414 return Math.min(Math.ceil(viewportHeight / rowHeight), this._totalRows) || minimumVisibleRows;
35415 return Math.min(Math.floor(viewportHeight / rowHeight), this._totalRows) || minimumVisibleRows;
35416 };
35417 ListView.prototype.getRowHeight = function () {
35418 var deferred = $.Deferred();
35419 var listView = this;
35420 var options = listView.options;
35421 if (this.cancelMeasurePass)
35422 this.cancelMeasurePass();
35423 // if there is no data, resolve and return
35424 if (!(this._data && this._data.length && options)) {
35425 listView.rowHeight(ListView.defaultRowHeight);
35426 return deferred.resolve(options.rowHeight).promise();
35427 }
35428 //render the first item to calculate the row height
35429 this.scrollToFrame(false /*loadMoreData*/);
35430 var requestAnimationFrameId = window.requestAnimationFrame(function () {
35431 //measure row height
35432 var rows = listView.visibleGroupContainer.select(".row");
35433 if (!rows.empty()) {
35434 var firstRow = rows.node();
35435 // If the container (child) has margins amd the row (parent) doesn't, the child's margins will collapse into the parent.
35436 // outerHeight doesn't report the correct height for the parent in this case, but it does measure the child properly.
35437 // Fix for #7497261 Measures both and take the max to work around this issue.
35438 var rowHeight = Math.max($(firstRow).outerHeight(true), $(firstRow).children().first().outerHeight(true));
35439 listView.rowHeight(rowHeight);
35440 deferred.resolve(rowHeight);
35441 }
35442 listView.cancelMeasurePass = undefined;
35443 window.cancelAnimationFrame(requestAnimationFrameId);
35444 });
35445 this.cancelMeasurePass = function () {
35446 window.cancelAnimationFrame(requestAnimationFrameId);
35447 deferred.reject();
35448 };
35449 return deferred.promise();
35450 };
35451 /**
35452 * The value indicates the percentage of data already shown
35453 * in the list view that triggers a loadMoreData call.
35454 */
35455 ListView.loadMoreDataThreshold = 0.8;
35456 ListView.defaultRowHeight = 1;
35457 return ListView;
35458 }());
35459 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
35460})(powerbi || (powerbi = {}));
35461/*
35462 * Power BI Visualizations
35463 *
35464 * Copyright (c) Microsoft Corporation
35465 * All rights reserved.
35466 * MIT License
35467 *
35468 * Permission is hereby granted, free of charge, to any person obtaining a copy
35469 * of this software and associated documentation files (the ""Software""), to deal
35470 * in the Software without restriction, including without limitation the rights
35471 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35472 * copies of the Software, and to permit persons to whom the Software is
35473 * furnished to do so, subject to the following conditions:
35474 *
35475 * The above copyright notice and this permission notice shall be included in
35476 * all copies or substantial portions of the Software.
35477 *
35478 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35479 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35480 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35481 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35482 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35483 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35484 * THE SOFTWARE.
35485 */
35486var powerbi;
35487(function (powerbi) {
35488 var visuals;
35489 (function (visuals) {
35490 var defaultLevelOfDetail = 11;
35491 var MapUtil;
35492 (function (MapUtil) {
35493 MapUtil.Settings = {
35494 /** Maximum Bing requests at once. The Bing have limit how many request at once you can do per socket. */
35495 MaxBingRequest: 6,
35496 /** Maximum cache size of cached geocode data. */
35497 MaxCacheSize: 3000,
35498 /** Maximum cache overflow of cached geocode data to kick the cache reducing. */
35499 MaxCacheSizeOverflow: 100,
35500 // Bing Keys and URL
35501 BingKey: "insert your key",
35502 BingUrl: "https://dev.virtualearth.net/REST/v1/Locations",
35503 BingUrlGeodata: "https://platform.bing.com/geo/spatial/v1/public/Geodata?",
35504 /** Switch the data result for geodata polygons to by double array instead locations array */
35505 UseDoubleArrayGeodataResult: true,
35506 UseDoubleArrayDequeueTimeout: 0,
35507 };
35508 // Bing map min/max boundaries
35509 MapUtil.MinAllowedLatitude = -85.05112878;
35510 MapUtil.MaxAllowedLatitude = 85.05112878;
35511 MapUtil.MinAllowedLongitude = -180;
35512 MapUtil.MaxAllowedLongitude = 180;
35513 MapUtil.TileSize = 256;
35514 MapUtil.MaxLevelOfDetail = 23;
35515 MapUtil.MinLevelOfDetail = 1;
35516 MapUtil.MaxAutoZoomLevel = 5;
35517 MapUtil.DefaultLevelOfDetail = 11;
35518 MapUtil.WorkerErrorName = "___error___";
35519 MapUtil.CategoryTypes = {
35520 Address: "Address",
35521 City: "City",
35522 Continent: "Continent",
35523 CountryRegion: "Country",
35524 County: "County",
35525 Longitude: "Longitude",
35526 Latitude: "Latitude",
35527 Place: "Place",
35528 PostalCode: "PostalCode",
35529 StateOrProvince: "StateOrProvince"
35530 };
35531 var safeCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
35532 function clip(n, minValue, maxValue) {
35533 return Math.min(Math.max(n, minValue), maxValue);
35534 }
35535 MapUtil.clip = clip;
35536 function getMapSize(levelOfDetail) {
35537 if (levelOfDetail === 23)
35538 return 2147483648; //256 << 23 overflow the integer and return a negative value
35539 if (Math.floor(levelOfDetail) === levelOfDetail)
35540 return 256 << levelOfDetail;
35541 return 256 * Math.pow(2, levelOfDetail);
35542 }
35543 MapUtil.getMapSize = getMapSize;
35544 /**
35545 * pointArrayChunkLength Motivation:
35546 * When the number is too small (e.g. less than 1000) the tile is rendering but VERY SLOW,
35547 * when it's too high there is a risk to get "stack overflow" error on mobile (while joining).
35548 * this is the lowest number I managed to get without any noticeable slowness.
35549 */
35550 var pointArrayChunkLength = 15000;
35551 /**
35552 * @param latLongArray - is a Float64Array as [lt0, lon0, lat1, long1, lat2, long2,....]
35553 * @param buildString - optional, if true returns also a string as "x0 y0 x1 y1 x2 y2 ...."
35554 * @returns IPixelArrayResult with Float64Array as [x0, y0, x1, y1, x2, y2,....]
35555 */
35556 function latLongToPixelXYArray(latLongArray, levelOfDetail, buildString) {
35557 if (buildString === void 0) { buildString = false; }
35558 var helperArray = [];
35559 var result = {
35560 array: new Float64Array(latLongArray.length),
35561 arrayString: ""
35562 };
35563 for (var i = 0; i < latLongArray.length; i += 2) {
35564 var latitude = clip(latLongArray[i], MapUtil.MinAllowedLatitude, MapUtil.MaxAllowedLatitude);
35565 var longitude = clip(latLongArray[i + 1], MapUtil.MinAllowedLongitude, MapUtil.MaxAllowedLongitude);
35566 var x = (longitude + 180) / 360;
35567 var sinLatitude = Math.sin(latitude * Math.PI / 180);
35568 var y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
35569 var mapSize = getMapSize(levelOfDetail);
35570 result.array[i] = clip(x * mapSize + 0.5, 0.0, mapSize - 1);
35571 result.array[i + 1] = clip(y * mapSize + 0.5, 0.0, mapSize - 1);
35572 if (buildString) {
35573 helperArray.push(result.array[i], result.array[i + 1]);
35574 if (helperArray.length >= pointArrayChunkLength) {
35575 result.arrayString += helperArray.join(" ") + " ";
35576 helperArray = [];
35577 }
35578 }
35579 }
35580 if (buildString) {
35581 result.arrayString += helperArray.join(" ") + " ";
35582 }
35583 return result;
35584 }
35585 MapUtil.latLongToPixelXYArray = latLongToPixelXYArray;
35586 function getLocationBoundaries(latLongArray) {
35587 var northWest = {
35588 latitude: -90, longitude: 180
35589 };
35590 var southEast = {
35591 latitude: 90, longitude: -180
35592 };
35593 for (var i = 0; i < latLongArray.length; i += 2) {
35594 northWest.latitude = Math.max(latLongArray[i], northWest.latitude);
35595 northWest.longitude = Math.min(latLongArray[i + 1], northWest.longitude);
35596 southEast.latitude = Math.min(latLongArray[i], southEast.latitude);
35597 southEast.longitude = Math.max(latLongArray[i + 1], southEast.longitude);
35598 }
35599 northWest.longitude = clip(northWest.longitude, -180, 180);
35600 southEast.longitude = clip(southEast.longitude, -180, 180);
35601 return Microsoft.Maps.LocationRect.fromCorners(new Microsoft.Maps.Location(northWest.latitude, northWest.longitude), new Microsoft.Maps.Location(southEast.latitude, southEast.longitude));
35602 }
35603 MapUtil.getLocationBoundaries = getLocationBoundaries;
35604 /**
35605 * Note: this code is taken from Bing.
35606 * see Point Compression Algorithm http://msdn.microsoft.com/en-us/library/jj158958.aspx
35607 * see Decompression Algorithm in http://msdn.microsoft.com/en-us/library/dn306801.aspx
35608 */
35609 function parseEncodedSpatialValueArray(value) {
35610 var list = [];
35611 var index = 0;
35612 var xsum = 0;
35613 var ysum = 0;
35614 var max = 4294967296;
35615 while (index < value.length) {
35616 var n = 0;
35617 var k = 0;
35618 while (1) {
35619 if (index >= value.length) {
35620 return null;
35621 }
35622 var b = safeCharacters.indexOf(value.charAt(index++));
35623 if (b === -1) {
35624 return null;
35625 }
35626 var tmp = ((b & 31) * (Math.pow(2, k)));
35627 var ht = tmp / max;
35628 var lt = tmp % max;
35629 var hn = n / max;
35630 var ln = n % max;
35631 var nl = (lt | ln) >>> 0;
35632 n = (ht | hn) * max + nl;
35633 k += 5;
35634 if (b < 32)
35635 break;
35636 }
35637 var diagonal = Math.floor((Math.sqrt(8 * n + 5) - 1) / 2);
35638 n -= diagonal * (diagonal + 1) / 2;
35639 var ny = Math.floor(n);
35640 var nx = diagonal - ny;
35641 nx = (nx >> 1) ^ -(nx & 1);
35642 ny = (ny >> 1) ^ -(ny & 1);
35643 xsum += nx;
35644 ysum += ny;
35645 var lat = ysum * 0.00001;
35646 var lon = xsum * 0.00001;
35647 list.push(lat);
35648 list.push(lon);
35649 }
35650 return new Float64Array(list);
35651 }
35652 MapUtil.parseEncodedSpatialValueArray = parseEncodedSpatialValueArray;
35653 function calcGeoData(data) {
35654 var locations = data.locations;
35655 for (var i = 0; i < locations.length; i++) {
35656 var location_1 = locations[i];
35657 if (!location_1.geographic) {
35658 location_1.geographic = MapUtil.parseEncodedSpatialValueArray(location_1.nativeBing);
35659 }
35660 var polygon = location_1.geographic;
35661 if (polygon) {
35662 if (!location_1.absolute) {
35663 var result = MapUtil.latLongToPixelXYArray(polygon, MapUtil.DefaultLevelOfDetail, true);
35664 location_1.absolute = result.array;
35665 location_1.absoluteString = result.arrayString;
35666 var geographicBounds = MapUtil.getLocationBoundaries(polygon);
35667 location_1.absoluteBounds = MapUtil.locationRectToRectXY(geographicBounds, MapUtil.DefaultLevelOfDetail);
35668 }
35669 }
35670 }
35671 }
35672 MapUtil.calcGeoData = calcGeoData;
35673 function locationToPixelXY(location, levelOfDetail) {
35674 return latLongToPixelXY(location.latitude, location.longitude, levelOfDetail);
35675 }
35676 MapUtil.locationToPixelXY = locationToPixelXY;
35677 function locationRectToRectXY(locationRect, levelOfDetail) {
35678 var topleft = locationToPixelXY(locationRect.getNorthwest(), levelOfDetail);
35679 var bottomRight = locationToPixelXY(locationRect.getSoutheast(), levelOfDetail);
35680 return new powerbi.visuals.Rect(topleft.x, topleft.y, bottomRight.x - topleft.x, bottomRight.y - topleft.y);
35681 }
35682 MapUtil.locationRectToRectXY = locationRectToRectXY;
35683 function latLongToPixelXY(latitude, longitude, levelOfDetail) {
35684 var array = latLongToPixelXYArray(new Float64Array([latitude, longitude]), levelOfDetail).array;
35685 return new powerbi.visuals.Point(array[0], array[1]);
35686 }
35687 MapUtil.latLongToPixelXY = latLongToPixelXY;
35688 function pixelXYToLocation(pixelX, pixelY, levelOfDetail) {
35689 var mapSize = getMapSize(levelOfDetail);
35690 var x = (clip(pixelX, 0, mapSize - 1) / mapSize) - 0.5;
35691 var y = 0.5 - (clip(pixelY, 0, mapSize - 1) / mapSize);
35692 var latitude = 90 - 360 * Math.atan(Math.exp(-y * 2 * Math.PI)) / Math.PI;
35693 var longitude = 360 * x;
35694 return new Microsoft.Maps.Location(latitude, longitude);
35695 }
35696 MapUtil.pixelXYToLocation = pixelXYToLocation;
35697 var CurrentLocation;
35698 (function (CurrentLocation) {
35699 function createPushpin(location) {
35700 var template = '<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">'
35701 + '<circle fill="#FF5F00" cx="12" cy="12" r="6"/>'
35702 + '<circle fill="none" stroke="#FF5F00" stroke-width="2" cx="12" cy="12" r="10"/>'
35703 + '</svg>';
35704 var options = {
35705 draggable: false,
35706 htmlContent: template,
35707 height: 24,
35708 width: 24
35709 };
35710 return new Microsoft.Maps.Pushpin(location, options);
35711 }
35712 CurrentLocation.createPushpin = createPushpin;
35713 })(CurrentLocation = MapUtil.CurrentLocation || (MapUtil.CurrentLocation = {}));
35714 })(MapUtil = visuals.MapUtil || (visuals.MapUtil = {}));
35715 var MapPolygonInfo = (function () {
35716 function MapPolygonInfo() {
35717 this._locationRect = new Microsoft.Maps.LocationRect(new Microsoft.Maps.Location(30, -30), 60, 60);
35718 }
35719 MapPolygonInfo.prototype.reCalc = function (mapControl, width, height) {
35720 var baseLocations = [this._locationRect.getNorthwest(), this._locationRect.getSoutheast()];
35721 width = width / 2.00;
35722 height = height / 2.00;
35723 if (!this._baseRect) {
35724 var l0 = MapUtil.locationToPixelXY(this._locationRect.getNorthwest(), defaultLevelOfDetail);
35725 var l1 = MapUtil.locationToPixelXY(this._locationRect.getSoutheast(), defaultLevelOfDetail);
35726 this._baseRect = new visuals.Rect(l0.x, l0.y, l1.x - l0.x, l1.y - l0.y);
35727 }
35728 var l = mapControl.tryLocationToPixel(baseLocations);
35729 this._currentRect = new visuals.Rect(l[0].x + width, l[0].y + height, l[1].x - l[0].x, l[1].y - l[0].y);
35730 };
35731 Object.defineProperty(MapPolygonInfo.prototype, "scale", {
35732 get: function () {
35733 if (this._baseRect) {
35734 return this._currentRect.width / this._baseRect.width;
35735 }
35736 return 1.0;
35737 },
35738 enumerable: true,
35739 configurable: true
35740 });
35741 Object.defineProperty(MapPolygonInfo.prototype, "transform", {
35742 get: function () {
35743 var base = this._baseRect;
35744 var current = this._currentRect;
35745 var transform = new visuals.Transform();
35746 transform.translate(current.left, current.top);
35747 transform.scale((current.width / base.width), (current.height / base.height));
35748 transform.translate(-base.left, -base.top);
35749 return transform;
35750 },
35751 enumerable: true,
35752 configurable: true
35753 });
35754 Object.defineProperty(MapPolygonInfo.prototype, "outherTransform", {
35755 get: function () {
35756 var base = this._baseRect;
35757 var current = this._currentRect;
35758 var transform = new visuals.Transform();
35759 transform.translate(current.left, current.top);
35760 var scale = Math.sqrt(current.width / base.width);
35761 transform.scale(scale, scale);
35762 return transform;
35763 },
35764 enumerable: true,
35765 configurable: true
35766 });
35767 MapPolygonInfo.prototype.setViewBox = function (svg) {
35768 var rect = svg.getBoundingClientRect();
35769 var current = this._currentRect;
35770 svg.setAttribute("viewBox", [-current.left, -current.top, rect.width, rect.height].join(" "));
35771 };
35772 Object.defineProperty(MapPolygonInfo.prototype, "innerTransform", {
35773 get: function () {
35774 var base = this._baseRect;
35775 var current = this._currentRect;
35776 var transform = new visuals.Transform();
35777 var scale = current.width / base.width;
35778 transform.scale(scale, scale);
35779 transform.translate(-base.left, -base.top);
35780 return transform;
35781 },
35782 enumerable: true,
35783 configurable: true
35784 });
35785 MapPolygonInfo.prototype.transformToString = function (transform) {
35786 var m = transform.matrix;
35787 return "matrix(" + m.m00 + " " + m.m10 + " " + m.m01 + " " + m.m11 + " " + m.m02 + " " + m.m12 + ")";
35788 };
35789 return MapPolygonInfo;
35790 }());
35791 visuals.MapPolygonInfo = MapPolygonInfo;
35792 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
35793})(powerbi || (powerbi = {}));
35794/*
35795* Power BI Visualizations
35796*
35797* Copyright (c) Microsoft Corporation
35798* All rights reserved.
35799* MIT License
35800*
35801* Permission is hereby granted, free of charge, to any person obtaining a copy
35802* of this software and associated documentation files (the ""Software""), to deal
35803* in the Software without restriction, including without limitation the rights
35804* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35805* copies of the Software, and to permit persons to whom the Software is
35806* furnished to do so, subject to the following conditions:
35807*
35808* The above copyright notice and this permission notice shall be included in
35809* all copies or substantial portions of the Software.
35810*
35811* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35812* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35813* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35814* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35815* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35816* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35817* THE SOFTWARE.
35818*/
35819var powerbi;
35820(function (powerbi) {
35821 var visuals;
35822 (function (visuals) {
35823 var utility;
35824 (function (utility) {
35825 ;
35826 var SelectionManager = (function () {
35827 function SelectionManager(options) {
35828 this.hostServices = options.hostServices;
35829 this.selectedIds = [];
35830 }
35831 SelectionManager.prototype.select = function (selectionId, multiSelect) {
35832 if (multiSelect === void 0) { multiSelect = false; }
35833 var deferred = $.Deferred();
35834 if (this.hostServices.shouldRetainSelection()) {
35835 this.sendSelectionToHost([selectionId]);
35836 }
35837 else {
35838 this.selectInternal(selectionId, multiSelect);
35839 this.sendSelectionToHost(this.selectedIds);
35840 }
35841 deferred.resolve(this.selectedIds);
35842 return deferred;
35843 };
35844 SelectionManager.prototype.showContextMenu = function (selectionId, position) {
35845 var deferred = $.Deferred();
35846 position = position || visuals.InteractivityUtils.getPositionOfLastInputEvent();
35847 this.sendContextMenuToHost(selectionId, position);
35848 deferred.resolve();
35849 return deferred;
35850 };
35851 SelectionManager.prototype.hasSelection = function () {
35852 return this.selectedIds.length > 0;
35853 };
35854 SelectionManager.prototype.clear = function () {
35855 var deferred = $.Deferred();
35856 this.selectedIds = [];
35857 this.sendSelectionToHost([]);
35858 deferred.resolve();
35859 return deferred;
35860 };
35861 SelectionManager.prototype.getSelectionIds = function () {
35862 return this.selectedIds;
35863 };
35864 SelectionManager.prototype.sendSelectionToHost = function (ids) {
35865 var selectArgs = {
35866 data: ids
35867 .filter(function (value) { return value.hasIdentity(); })
35868 .map(function (value) { return value.getSelector(); })
35869 };
35870 var data2 = this.getSelectorsByColumn(ids);
35871 if (!_.isEmpty(data2))
35872 selectArgs.data2 = data2;
35873 this.hostServices.onSelect(selectArgs);
35874 };
35875 SelectionManager.prototype.sendContextMenuToHost = function (selectionId, position) {
35876 var selectors = this.getSelectorsByColumn([selectionId]);
35877 if (_.isEmpty(selectors))
35878 return;
35879 var args = {
35880 data: selectors,
35881 position: position
35882 };
35883 this.hostServices.onContextMenu(args);
35884 };
35885 SelectionManager.prototype.getSelectorsByColumn = function (selectionIds) {
35886 return _(selectionIds)
35887 .filter(function (value) { return value.hasIdentity; })
35888 .map(function (value) { return value.getSelectorsByColumn(); })
35889 .compact()
35890 .value();
35891 };
35892 SelectionManager.prototype.selectInternal = function (selectionId, multiSelect) {
35893 if (SelectionManager.containsSelection(this.selectedIds, selectionId)) {
35894 this.selectedIds = multiSelect
35895 ? this.selectedIds.filter(function (d) { return !powerbi.data.Selector.equals(d, selectionId); })
35896 : this.selectedIds.length > 1
35897 ? [selectionId] : [];
35898 }
35899 else {
35900 if (multiSelect)
35901 this.selectedIds.push(selectionId);
35902 else
35903 this.selectedIds = [selectionId];
35904 }
35905 };
35906 SelectionManager.containsSelection = function (list, id) {
35907 return list.some(function (d) { return powerbi.data.Selector.equals(d.getSelector(), id.getSelector()); });
35908 };
35909 return SelectionManager;
35910 }());
35911 utility.SelectionManager = SelectionManager;
35912 })(utility = visuals.utility || (visuals.utility = {}));
35913 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
35914})(powerbi || (powerbi = {}));
35915/*
35916 * Power BI Visualizations
35917 *
35918 * Copyright (c) Microsoft Corporation
35919 * All rights reserved.
35920 * MIT License
35921 *
35922 * Permission is hereby granted, free of charge, to any person obtaining a copy
35923 * of this software and associated documentation files (the ""Software""), to deal
35924 * in the Software without restriction, including without limitation the rights
35925 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35926 * copies of the Software, and to permit persons to whom the Software is
35927 * furnished to do so, subject to the following conditions:
35928 *
35929 * The above copyright notice and this permission notice shall be included in
35930 * all copies or substantial portions of the Software.
35931 *
35932 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35933 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35934 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35935 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35936 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35937 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35938 * THE SOFTWARE.
35939 */
35940var powerbi;
35941(function (powerbi) {
35942 var visuals;
35943 (function (visuals) {
35944 "use strict";
35945 var shapes;
35946 (function (shapes) {
35947 var Utility = jsCommon.Utility;
35948 var Polygon = (function () {
35949 function Polygon(absolutePoints) {
35950 this.polygonPoints = this.convertArrayPathToPoints(absolutePoints);
35951 }
35952 Polygon.prototype.absoluteCentroid = function () {
35953 if (this._absoluteCentroid == null) {
35954 this._absoluteCentroid = this.calculatePolygonCentroid();
35955 }
35956 return this._absoluteCentroid;
35957 };
35958 Polygon.prototype.absoluteBoundingRect = function () {
35959 if (this._absoluteBoundingRect == null) {
35960 this._absoluteBoundingRect = this.calculateBoundingRect();
35961 }
35962 return this._absoluteBoundingRect;
35963 };
35964 /**
35965 * Check if label text contain in polygon shape.
35966 *
35967 * @return true/false is the label fit in polygon.
35968 * measure if rects points are inside the polygon shape
35969 * return true if there is at least 3 point inside the polygon
35970 */
35971 Polygon.prototype.contains = function (rect) {
35972 var topLeft = { x: rect.left, y: rect.top };
35973 var topRight = { x: rect.left + rect.width, y: rect.top };
35974 var bottomLeft = { x: rect.left, y: rect.top + rect.height };
35975 var bottomRight = { x: rect.left + rect.width, y: rect.top + rect.height };
35976 return (this.inside(topLeft)
35977 && this.inside(topRight)
35978 && this.inside(bottomLeft)
35979 && this.inside(bottomRight));
35980 };
35981 /**
35982 * Check if label text is outside of polygon shape.
35983 * It checks 8 points in the label. TopLeft, TopCenter, TopRight, MiddleLeft, MiddleRight, BottomLeft, BottomMiddle, BottomRight
35984 * @return true/false is there is any conflict (at least one point inside the shape).
35985 */
35986 Polygon.prototype.conflicts = function (rect) {
35987 if (!this.isConflictWithBoundingBox(rect)) {
35988 return false;
35989 }
35990 var topLeft = { x: rect.left, y: rect.top };
35991 var topCenter = { x: rect.left + rect.width / 2, y: rect.top };
35992 var topRight = { x: rect.left + rect.width, y: rect.top };
35993 var bottomLeft = { x: rect.left, y: rect.top + rect.height };
35994 var bottomCenter = { x: rect.left + rect.width / 2, y: rect.top + rect.height };
35995 var bottomRight = { x: rect.left + rect.width, y: rect.top + rect.height };
35996 var middleLeft = { x: rect.left, y: rect.top + rect.height / 2 };
35997 var middleRight = { x: rect.left + rect.width, y: rect.top + rect.height / 2 };
35998 return (this.inside(topLeft)
35999 || this.inside(topCenter)
36000 || this.inside(topRight)
36001 || this.inside(bottomLeft)
36002 || this.inside(bottomCenter)
36003 || this.inside(bottomRight)
36004 || this.inside(middleLeft)
36005 || this.inside(middleRight));
36006 };
36007 /**
36008 * returns intersection point of a line (depicted by two points) and a polygon.
36009 *
36010 * @return the point of intersection or null if there is no intersection.
36011 */
36012 Polygon.prototype.lineIntersectionPoint = function (p0, p1) {
36013 for (var i = 0; i < this.polygonPoints.length; i++) {
36014 var p2 = this.polygonPoints[i];
36015 var p3 = (i === this.polygonPoints.length - 1 ? this.polygonPoints[0] : this.polygonPoints[i + 1]);
36016 var intersection = this.getLineIntersection(p0, p1, p2, p3);
36017 if (intersection !== null) {
36018 return intersection;
36019 }
36020 }
36021 return null;
36022 };
36023 /**
36024 * calculate Polygon Area.
36025 *
36026 * @return the area of the polygon (as number).
36027 */
36028 Polygon.calculateAbsolutePolygonArea = function (polygonPoints) {
36029 var i, j = 1;
36030 var area = 0.0;
36031 for (i = 0; i < polygonPoints.length; i++) {
36032 area += polygonPoints[i].x * polygonPoints[j].y - polygonPoints[j].x * polygonPoints[i].y;
36033 j = (j + 1) % polygonPoints.length;
36034 }
36035 area *= 0.5;
36036 return area;
36037 };
36038 /**
36039 * Check if label text is outside of polygon bounding box.
36040 *
36041 * @return true/false is there is any conflict (at least one point inside the shape).
36042 */
36043 Polygon.prototype.isConflictWithBoundingBox = function (rect) {
36044 return Rect.isIntersecting(this.absoluteBoundingRect(), rect);
36045 };
36046 /**
36047 * Calculate Polygon Centroid.
36048 *
36049 * @return 'center' point of the polygon.
36050 * calculate the polygon area
36051 * calculate the average points of the polygon by x & y axis.
36052 * divided the average point by the area
36053 */
36054 Polygon.prototype.calculatePolygonCentroid = function () {
36055 var area, tempPoint, cx, cy, i, j;
36056 /* First calculate the polygon's signed area A */
36057 area = Polygon.calculateAbsolutePolygonArea(this.polygonPoints);
36058 /* Now calculate the centroid coordinates Cx and Cy */
36059 cx = cy = 0.0;
36060 j = 1;
36061 for (i = 0; i < this.polygonPoints.length; i++) {
36062 tempPoint = this.polygonPoints[i].x * this.polygonPoints[j].y - this.polygonPoints[j].x * this.polygonPoints[i].y;
36063 cx += (this.polygonPoints[i].x + this.polygonPoints[j].x) * tempPoint;
36064 cy += (this.polygonPoints[i].y + this.polygonPoints[j].y) * tempPoint;
36065 j = (j + 1) % this.polygonPoints.length;
36066 }
36067 cx = cx / (6.0 * area);
36068 cy = cy / (6.0 * area);
36069 return {
36070 x: cx,
36071 y: cy,
36072 };
36073 };
36074 Polygon.prototype.calculateBoundingRect = function () {
36075 var minX = Number.POSITIVE_INFINITY;
36076 var minY = Number.POSITIVE_INFINITY;
36077 var maxX = Number.NEGATIVE_INFINITY;
36078 var maxY = Number.NEGATIVE_INFINITY;
36079 for (var i = 0; i < this.polygonPoints.length; i++) {
36080 if (this.polygonPoints[i].x < minX) {
36081 minX = this.polygonPoints[i].x;
36082 }
36083 else if (this.polygonPoints[i].x > maxX) {
36084 maxX = this.polygonPoints[i].x;
36085 }
36086 if (this.polygonPoints[i].y < minY) {
36087 minY = this.polygonPoints[i].y;
36088 }
36089 else if (this.polygonPoints[i].y > maxY) {
36090 maxY = this.polygonPoints[i].y;
36091 }
36092 }
36093 return {
36094 left: minX,
36095 top: minY,
36096 width: maxX - minX,
36097 height: maxY - minY
36098 };
36099 };
36100 /**
36101 * Check if point exist inside polygon shape.
36102 *
36103 * @return true/false if point exist inside shape.
36104 * ray-casting algorithm based on:
36105 * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
36106 */
36107 Polygon.prototype.inside = function (point) {
36108 var x = point.x, y = point.y;
36109 var insideVar = false;
36110 for (var i = 0, j = this.polygonPoints.length - 1; i < this.polygonPoints.length; j = i++) {
36111 var xi = this.polygonPoints[i].x, yi = this.polygonPoints[i].y;
36112 var xj = this.polygonPoints[j].x, yj = this.polygonPoints[j].y;
36113 var intersect = ((yi > y) !== (yj > y))
36114 && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
36115 if (intersect) {
36116 insideVar = !insideVar;
36117 }
36118 }
36119 return insideVar;
36120 };
36121 ;
36122 /**
36123 * Checks if a line (presented as two points) intersects with a another line
36124 */
36125 Polygon.prototype.getLineIntersection = function (line0p1, line0p2, line1p1, line1p2) {
36126 var p0_x = line0p1.x;
36127 var p0_y = line0p1.y;
36128 var p1_x = line0p2.x;
36129 var p1_y = line0p2.y;
36130 var p2_x = line1p1.x;
36131 var p2_y = line1p1.y;
36132 var p3_x = line1p2.x;
36133 var p3_y = line1p2.y;
36134 var s1_x = p1_x - p0_x;
36135 var s1_y = p1_y - p0_y;
36136 var s2_x = p3_x - p2_x;
36137 var s2_y = p3_y - p2_y;
36138 //Calculating collisions using cross products
36139 var s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
36140 var t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
36141 // 0<=s<=1 and 0<=t<=1 ensures that the collision is part of the original line
36142 if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
36143 // Collision detected
36144 return { x: (p0_x + (t * s1_x)), y: (p0_y + (t * s1_y)) };
36145 }
36146 return null; // No collision
36147 };
36148 Polygon.prototype.convertArrayPathToPoints = function (path) {
36149 var pointsRes = [];
36150 for (var i = 0; i < path.length; i += 2) {
36151 var x = path[i];
36152 var y = path[i + 1];
36153 var newPoint = {
36154 x: x,
36155 y: y,
36156 };
36157 pointsRes.push(newPoint);
36158 }
36159 return pointsRes;
36160 };
36161 return Polygon;
36162 }());
36163 shapes.Polygon = Polygon;
36164 var Point;
36165 (function (Point) {
36166 function offset(point, offsetX, offsetY) {
36167 var newPointX = ((point.x + offsetX) >= 0) ? (point.x + offsetX) : 0;
36168 var newPointY = ((point.y + offsetY) >= 0) ? (point.y + offsetY) : 0;
36169 return { x: newPointX, y: newPointY };
36170 }
36171 Point.offset = offset;
36172 function equals(point, other) {
36173 return point !== undefined && point !== null && other !== undefined && other !== null && point.x === other.x && point.y === other.y;
36174 }
36175 Point.equals = equals;
36176 function clone(point) {
36177 return (point !== null) ? { x: point.x, y: point.y } : null;
36178 }
36179 Point.clone = clone;
36180 function toString(point) {
36181 return "{x:" + point.x + ", y:" + point.y + "}";
36182 }
36183 Point.toString = toString;
36184 function serialize(point) {
36185 return point.x + "," + point.y;
36186 }
36187 Point.serialize = serialize;
36188 function getDistance(point, other) {
36189 if ((point === null) || (other) === null) {
36190 return null;
36191 }
36192 var diffX = other.x - point.x;
36193 var diffY = other.y - point.y;
36194 return Math.sqrt(diffX * diffX + diffY * diffY);
36195 }
36196 Point.getDistance = getDistance;
36197 function equalWithPrecision(point1, point2) {
36198 return point1 === point2 ||
36199 (point1 !== undefined && point2 !== undefined && powerbi.Double.equalWithPrecision(point1.x, point2.x) && powerbi.Double.equalWithPrecision(point1.y, point2.y));
36200 }
36201 Point.equalWithPrecision = equalWithPrecision;
36202 function parsePoint(value, defaultValue) {
36203 if (value === null) {
36204 return (defaultValue === undefined) ? null : defaultValue;
36205 }
36206 else if (value === undefined) {
36207 return (defaultValue === undefined) ? null : defaultValue;
36208 }
36209 else {
36210 if (value.length === 2) {
36211 return { x: Utility.parseNumber(value[0]), y: Utility.parseNumber(value[1]) };
36212 }
36213 else if (typeof value === "string") {
36214 var parts = value.split(",");
36215 if (parts.length !== 2) {
36216 return (defaultValue === undefined) ? null : defaultValue;
36217 }
36218 return { x: Utility.parseNumber(parts[0]), y: Utility.parseNumber(parts[1]) };
36219 }
36220 else if ((value.length !== 2) && (typeof value !== "string")) {
36221 return (defaultValue === undefined) ? null : defaultValue;
36222 }
36223 else {
36224 return { x: Utility.parseNumber(value.x), y: Utility.parseNumber(value.y) };
36225 }
36226 }
36227 }
36228 Point.parsePoint = parsePoint;
36229 })(Point = shapes.Point || (shapes.Point = {}));
36230 var Size;
36231 (function (Size) {
36232 function isEmpty(size) {
36233 return size.width === 0 && size.height === 0;
36234 }
36235 Size.isEmpty = isEmpty;
36236 function equals(size, other) {
36237 return size !== undefined && size !== null && other !== undefined && other !== null && size.width === other.width && size.height === other.height;
36238 }
36239 Size.equals = equals;
36240 function clone(size) {
36241 return (size !== null) ? { width: size.width, height: size.height } : null;
36242 }
36243 Size.clone = clone;
36244 function inflate(size, padding) {
36245 var result = clone(size);
36246 if (padding) {
36247 result.width += padding.left + padding.right;
36248 result.height += padding.top + padding.bottom;
36249 }
36250 return result;
36251 }
36252 Size.inflate = inflate;
36253 function deflate(size, padding) {
36254 var result = clone(size);
36255 if (padding) {
36256 result.width = result.width - padding.left - padding.right;
36257 if (result.width < 0) {
36258 result.width = 0;
36259 }
36260 result.height = result.height - padding.top - padding.bottom;
36261 if (result.height < 0) {
36262 result.height = 0;
36263 }
36264 }
36265 return result;
36266 }
36267 Size.deflate = deflate;
36268 function combine(size, other) {
36269 if (other) {
36270 size.width = Math.max(size.width, other.width);
36271 size.height = Math.max(size.height, other.height);
36272 }
36273 return size;
36274 }
36275 Size.combine = combine;
36276 function toRect(size) {
36277 return { left: 0, top: 0, width: size.width, height: size.height };
36278 }
36279 Size.toRect = toRect;
36280 function toString(size) {
36281 return "{width:" + size.width + ", height:" + size.height + "}";
36282 }
36283 Size.toString = toString;
36284 function equal(size1, size2) {
36285 return size1 === size2 ||
36286 (size1 !== undefined && size2 !== undefined && size1.width === size2.width && size1.height === size2.height);
36287 }
36288 Size.equal = equal;
36289 function equalWithPrecision(size1, size2) {
36290 return size1 === size2 ||
36291 (size1 !== undefined && size2 !== undefined && powerbi.Double.equalWithPrecision(size1.width, size2.width) && powerbi.Double.equalWithPrecision(size1.height, size2.height));
36292 }
36293 Size.equalWithPrecision = equalWithPrecision;
36294 function parseSize(value, defaultValue) {
36295 if (value === null) {
36296 return (defaultValue === undefined) ? null : defaultValue;
36297 }
36298 else if (value === undefined) {
36299 return (defaultValue === undefined) ? null : defaultValue;
36300 }
36301 else {
36302 if (value.length === 2) {
36303 return { width: Utility.parseNumber(value[0]), height: Utility.parseNumber(value[1]) };
36304 }
36305 else if (typeof value === "string") {
36306 var parts = value.split(",");
36307 if (parts.length !== 2) {
36308 return (defaultValue === undefined) ? null : defaultValue;
36309 }
36310 return { width: Utility.parseNumber(parts[0]), height: Utility.parseNumber(parts[1]) };
36311 }
36312 else if ((value.length !== 2) && (typeof value !== "string")) {
36313 return (defaultValue === undefined) ? null : defaultValue;
36314 }
36315 else {
36316 return { width: Utility.parseNumber(value.width), height: Utility.parseNumber(value.height) };
36317 }
36318 }
36319 }
36320 Size.parseSize = parseSize;
36321 })(Size = shapes.Size || (shapes.Size = {}));
36322 var Rect;
36323 (function (Rect) {
36324 function getOffset(rect) {
36325 return { x: rect.left, y: rect.top };
36326 }
36327 Rect.getOffset = getOffset;
36328 function getSize(rect) {
36329 return { width: rect.width, height: rect.height };
36330 }
36331 Rect.getSize = getSize;
36332 function setSize(rect, value) {
36333 rect.width = value.width;
36334 rect.height = value.height;
36335 }
36336 Rect.setSize = setSize;
36337 function right(rect) {
36338 return rect.left + rect.width;
36339 }
36340 Rect.right = right;
36341 function bottom(rect) {
36342 return rect.top + rect.height;
36343 }
36344 Rect.bottom = bottom;
36345 function topLeft(rect) {
36346 return { x: rect.left, y: rect.top };
36347 }
36348 Rect.topLeft = topLeft;
36349 function topRight(rect) {
36350 return { x: rect.left + rect.width, y: rect.top };
36351 }
36352 Rect.topRight = topRight;
36353 function bottomLeft(rect) {
36354 return { x: rect.left, y: rect.top + rect.height };
36355 }
36356 Rect.bottomLeft = bottomLeft;
36357 function bottomRight(rect) {
36358 return { x: rect.left + rect.width, y: rect.top + rect.height };
36359 }
36360 Rect.bottomRight = bottomRight;
36361 function equals(rect, other) {
36362 return other !== undefined && other !== null &&
36363 rect.left === other.left && rect.top === other.top && rect.width === other.width && rect.height === other.height;
36364 }
36365 Rect.equals = equals;
36366 function clone(rect) {
36367 return (rect !== null) ? { left: rect.left, top: rect.top, width: rect.width, height: rect.height } : null;
36368 }
36369 Rect.clone = clone;
36370 function toString(rect) {
36371 return "{left:" + rect.left + ", top:" + rect.top + ", width:" + rect.width + ", height:" + rect.height + "}";
36372 }
36373 Rect.toString = toString;
36374 function offset(rect, offsetX, offsetY) {
36375 var newLeft = ((rect.left + offsetX) >= 0) ? rect.left + offsetX : 0;
36376 var newTop = ((rect.top + offsetY) >= 0) ? rect.top + offsetY : 0;
36377 return { left: newLeft, top: newTop, width: rect.width, height: rect.height };
36378 }
36379 Rect.offset = offset;
36380 function inflate(rect, padding) {
36381 var result = clone(rect);
36382 if (padding) {
36383 result.left -= padding.left;
36384 result.top -= padding.top;
36385 result.width += padding.left + padding.right;
36386 result.height += padding.top + padding.bottom;
36387 }
36388 return result;
36389 }
36390 Rect.inflate = inflate;
36391 function deflate(rect, padding) {
36392 var result = clone(rect);
36393 if (padding) {
36394 result.left += padding.left;
36395 result.top += padding.top;
36396 result.width -= padding.left + padding.right;
36397 result.height -= padding.top + padding.bottom;
36398 }
36399 return result;
36400 }
36401 Rect.deflate = deflate;
36402 function inflateBy(rect, padding) {
36403 return { left: rect.left - padding, top: rect.top - padding, width: rect.width + padding + padding, height: rect.height + padding + padding };
36404 }
36405 Rect.inflateBy = inflateBy;
36406 function deflateBy(rect, padding) {
36407 return { left: rect.left + padding, top: rect.top + padding, width: rect.width - padding - padding, height: rect.height - padding - padding };
36408 }
36409 Rect.deflateBy = deflateBy;
36410 /**
36411 * Get closest point.
36412 *
36413 * @return the closest point on the rect to the (x,y) point given.
36414 * In case the (x,y) given is inside the rect, (x,y) will be returned.
36415 * Otherwise, a point on a border will be returned.
36416 */
36417 function getClosestPoint(rect, x, y) {
36418 return {
36419 x: Math.min(Math.max(rect.left, x), rect.left + rect.width),
36420 y: Math.min(Math.max(rect.top, y), rect.top + rect.height)
36421 };
36422 }
36423 Rect.getClosestPoint = getClosestPoint;
36424 function equal(rect1, rect2) {
36425 return rect1 === rect2 ||
36426 (rect1 !== undefined && rect2 !== undefined && rect1.left === rect2.left && rect1.top === rect2.top && rect1.width === rect2.width && rect1.height === rect2.height);
36427 }
36428 Rect.equal = equal;
36429 function equalWithPrecision(rect1, rect2) {
36430 return rect1 === rect2 ||
36431 (rect1 !== undefined && rect2 !== undefined &&
36432 powerbi.Double.equalWithPrecision(rect1.left, rect2.left) && powerbi.Double.equalWithPrecision(rect1.top, rect2.top) &&
36433 powerbi.Double.equalWithPrecision(rect1.width, rect2.width) && powerbi.Double.equalWithPrecision(rect1.height, rect2.height));
36434 }
36435 Rect.equalWithPrecision = equalWithPrecision;
36436 function isEmpty(rect) {
36437 return rect === undefined || rect === null || (rect.width === 0 && rect.height === 0);
36438 }
36439 Rect.isEmpty = isEmpty;
36440 function containsPoint(rect, point) {
36441 if ((rect === null) || (point === null)) {
36442 return false;
36443 }
36444 return powerbi.Double.lessOrEqualWithPrecision(rect.left, point.x) &&
36445 powerbi.Double.lessOrEqualWithPrecision(point.x, rect.left + rect.width) &&
36446 powerbi.Double.lessOrEqualWithPrecision(rect.top, point.y) &&
36447 powerbi.Double.lessOrEqualWithPrecision(point.y, rect.top + rect.height);
36448 }
36449 Rect.containsPoint = containsPoint;
36450 function isIntersecting(rect1, rect2) {
36451 if (!rect1 || !rect2) {
36452 return false;
36453 }
36454 var left = Math.max(rect1.left, rect2.left);
36455 var right = Math.min(rect1.left + rect1.width, rect2.left + rect2.width);
36456 if (left > right) {
36457 return false;
36458 }
36459 var top = Math.max(rect1.top, rect2.top);
36460 var bottom = Math.min(rect1.top + rect1.height, rect2.top + rect2.height);
36461 return top <= bottom;
36462 }
36463 Rect.isIntersecting = isIntersecting;
36464 function intersect(rect1, rect2) {
36465 if (!rect1) {
36466 return rect2;
36467 }
36468 if (!rect2) {
36469 return rect1;
36470 }
36471 var left = Math.max(rect1.left, rect2.left);
36472 var top = Math.max(rect1.top, rect2.top);
36473 var right = Math.min(rect1.left + rect1.width, rect2.left + rect2.width);
36474 var bottom = Math.min(rect1.top + rect1.height, rect2.top + rect2.height);
36475 if (left <= right && top <= bottom) {
36476 return { left: left, top: top, width: right - left, height: bottom - top };
36477 }
36478 else {
36479 return { left: 0, top: 0, width: 0, height: 0 };
36480 }
36481 }
36482 Rect.intersect = intersect;
36483 function combine(rect1, rect2) {
36484 if (!rect1) {
36485 return rect2;
36486 }
36487 if (!rect2) {
36488 return rect1;
36489 }
36490 var left = Math.min(rect1.left, rect2.left);
36491 var top = Math.min(rect1.top, rect2.top);
36492 var right = Math.max(rect1.left + rect1.width, rect2.left + rect2.width);
36493 var bottom = Math.max(rect1.top + rect1.height, rect2.top + rect2.height);
36494 return { left: left, top: top, width: right - left, height: bottom - top };
36495 }
36496 Rect.combine = combine;
36497 function parseRect(value, defaultValue) {
36498 if (value === null) {
36499 return (defaultValue === undefined) ? null : defaultValue;
36500 }
36501 else if (value === undefined) {
36502 return (defaultValue === undefined) ? null : defaultValue;
36503 }
36504 else {
36505 if (value.length === 4) {
36506 return { left: Utility.parseNumber(value[0]), top: Utility.parseNumber(value[1]), width: Utility.parseNumber(value[2]), height: Utility.parseNumber(value[3]) };
36507 }
36508 else if (typeof value === "string") {
36509 var parts = value.split(",");
36510 if (parts.length !== 4) {
36511 return (defaultValue === undefined) ? null : defaultValue;
36512 }
36513 return {
36514 left: Utility.parseNumber(parts[0]), top: Utility.parseNumber(parts[1]), width: Utility.parseNumber(parts[2]), height: Utility.parseNumber(parts[3])
36515 };
36516 }
36517 else if ((value.length !== 4) && (typeof value !== "string")) {
36518 return (defaultValue === undefined) ? null : defaultValue;
36519 }
36520 else {
36521 return { left: Utility.parseNumber(value.left), top: Utility.parseNumber(value.top), width: Utility.parseNumber(value.width), height: Utility.parseNumber(value.height) };
36522 }
36523 }
36524 }
36525 Rect.parseRect = parseRect;
36526 })(Rect = shapes.Rect || (shapes.Rect = {}));
36527 var Thickness;
36528 (function (Thickness) {
36529 function inflate(thickness, other) {
36530 var result = clone(thickness);
36531 if (other) {
36532 result.left = thickness.left + other.left;
36533 result.right = thickness.right + other.right;
36534 result.bottom = thickness.bottom + other.bottom;
36535 result.top = thickness.top + other.top;
36536 }
36537 return result;
36538 }
36539 Thickness.inflate = inflate;
36540 function getWidth(thickness) {
36541 return thickness.left + thickness.right;
36542 }
36543 Thickness.getWidth = getWidth;
36544 function getHeight(thickness) {
36545 return thickness.top + thickness.bottom;
36546 }
36547 Thickness.getHeight = getHeight;
36548 function clone(thickness) {
36549 return (thickness !== null) ? { left: thickness.left, top: thickness.top, right: thickness.right, bottom: thickness.bottom } : null;
36550 }
36551 Thickness.clone = clone;
36552 function equals(thickness, other) {
36553 return thickness !== undefined && thickness !== null && other !== undefined && other !== null && thickness.left === other.left && thickness.bottom === other.bottom && thickness.right === other.right && thickness.top === other.top;
36554 }
36555 Thickness.equals = equals;
36556 function flipHorizontal(thickness) {
36557 var temp = thickness.right;
36558 thickness.right = thickness.left;
36559 thickness.left = temp;
36560 }
36561 Thickness.flipHorizontal = flipHorizontal;
36562 function flipVertical(thickness) {
36563 var top = thickness.top;
36564 thickness.top = thickness.bottom;
36565 thickness.bottom = top;
36566 }
36567 Thickness.flipVertical = flipVertical;
36568 function toString(thickness) {
36569 return "{top:" + thickness.top + ", left:" + thickness.left + ", right:" + thickness.right + ", bottom:" + thickness.bottom + "}";
36570 }
36571 Thickness.toString = toString;
36572 function toCssString(thickness) {
36573 return thickness.top + "px " + thickness.right + "px " + thickness.bottom + "px " + thickness.left + "px";
36574 }
36575 Thickness.toCssString = toCssString;
36576 function isEmpty(thickness) {
36577 return thickness.left === 0 && thickness.top === 0 && thickness.right === 0 && thickness.bottom === 0;
36578 }
36579 Thickness.isEmpty = isEmpty;
36580 function equal(thickness1, thickness2) {
36581 return thickness1 === thickness2 ||
36582 (thickness1 !== undefined && thickness2 !== undefined && thickness1.left === thickness2.left && thickness1.top === thickness2.top && thickness1.right === thickness2.right && thickness1.bottom === thickness2.bottom);
36583 }
36584 Thickness.equal = equal;
36585 function equalWithPrecision(thickness1, thickness2) {
36586 return thickness1 === thickness2 ||
36587 (thickness1 !== undefined && thickness2 !== undefined &&
36588 powerbi.Double.equalWithPrecision(thickness1.left, thickness2.left) && powerbi.Double.equalWithPrecision(thickness1.top, thickness2.top) &&
36589 powerbi.Double.equalWithPrecision(thickness1.right, thickness2.right) && powerbi.Double.equalWithPrecision(thickness1.bottom, thickness2.bottom));
36590 }
36591 Thickness.equalWithPrecision = equalWithPrecision;
36592 function parseThickness(value, defaultValue, resetValue) {
36593 if (value === null) {
36594 return (defaultValue === undefined) ? null : defaultValue;
36595 }
36596 else if (value === undefined) {
36597 return (defaultValue === undefined) ? null : defaultValue;
36598 }
36599 else {
36600 if (value.length === 4) {
36601 return { left: Utility.parseNumber(value[0]), top: Utility.parseNumber(value[1]), right: Utility.parseNumber(value[2]), bottom: Utility.parseNumber(value[3]) };
36602 }
36603 else if (typeof value === "string") {
36604 var parts = value.split(",");
36605 if (parts.length !== 4) {
36606 return (defaultValue === undefined) ? null : defaultValue;
36607 }
36608 return { left: Utility.parseNumber(parts[0]), top: Utility.parseNumber(parts[1]), right: Utility.parseNumber(parts[2]), bottom: Utility.parseNumber(parts[3]) };
36609 }
36610 else if ((value.length !== 4) && (typeof value !== "string")) {
36611 return (defaultValue === undefined) ? null : defaultValue;
36612 }
36613 else {
36614 return { left: Utility.parseNumber(value.left), top: Utility.parseNumber(value.top), right: Utility.parseNumber(value.right), bottom: Utility.parseNumber(value.bottom) };
36615 }
36616 }
36617 }
36618 Thickness.parseThickness = parseThickness;
36619 })(Thickness = shapes.Thickness || (shapes.Thickness = {}));
36620 var Vector;
36621 (function (Vector) {
36622 function isEmpty(vector) {
36623 return vector.x === 0 && vector.y === 0;
36624 }
36625 Vector.isEmpty = isEmpty;
36626 function equals(vector, other) {
36627 return vector !== undefined && vector !== null && other !== undefined && other !== null && vector.x === other.x && vector.y === other.y;
36628 }
36629 Vector.equals = equals;
36630 function clone(vector) {
36631 return (vector !== null) ? { x: vector.x, y: vector.y } : null;
36632 }
36633 Vector.clone = clone;
36634 function toString(vector) {
36635 return "{x:" + vector.x + ", y:" + vector.y + "}";
36636 }
36637 Vector.toString = toString;
36638 function getLength(vector) {
36639 return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
36640 }
36641 Vector.getLength = getLength;
36642 function getLengthSqr(vector) {
36643 return vector.x * vector.x + vector.y * vector.y;
36644 }
36645 Vector.getLengthSqr = getLengthSqr;
36646 function scale(vector, scalar) {
36647 return { x: vector.x * scalar, y: vector.y * scalar };
36648 }
36649 Vector.scale = scale;
36650 function normalize(vector) {
36651 return !isEmpty(vector) ? scale(vector, 1 / getLength(vector)) : vector;
36652 }
36653 Vector.normalize = normalize;
36654 function rotate90DegCW(vector) {
36655 return { x: vector.y, y: -vector.x };
36656 }
36657 Vector.rotate90DegCW = rotate90DegCW;
36658 function rotate90DegCCW(vector) {
36659 return { x: -vector.y, y: vector.x };
36660 }
36661 Vector.rotate90DegCCW = rotate90DegCCW;
36662 function rotate(vector, angle) {
36663 var newX = vector.x * Math.cos(angle) - vector.y * Math.sin(angle);
36664 var newY = vector.x * Math.sin(angle) + vector.y * Math.cos(angle);
36665 return { x: newX, y: newY };
36666 }
36667 Vector.rotate = rotate;
36668 function equal(vector1, vector2) {
36669 return vector1 === vector2 ||
36670 (vector1 !== undefined && vector2 !== undefined && vector1.x === vector2.x && vector1.y === vector2.y);
36671 }
36672 Vector.equal = equal;
36673 function equalWithPrecision(vector1, vector2) {
36674 return vector1 === vector2 ||
36675 (vector1 !== undefined && vector2 !== undefined && powerbi.Double.equalWithPrecision(vector1.x, vector2.x) && powerbi.Double.equalWithPrecision(vector1.y, vector2.y));
36676 }
36677 Vector.equalWithPrecision = equalWithPrecision;
36678 function add(vect1, vect2) {
36679 if (!vect1 || !vect2) {
36680 return undefined;
36681 }
36682 return { x: vect1.x + vect2.x, y: vect1.y + vect2.y };
36683 }
36684 Vector.add = add;
36685 function subtract(vect1, vect2) {
36686 if (!vect1 || !vect2) {
36687 return undefined;
36688 }
36689 return { x: vect1.x - vect2.x, y: vect1.y - vect2.y };
36690 }
36691 Vector.subtract = subtract;
36692 function dotProduct(vect1, vect2) {
36693 if (!vect1 || !vect2) {
36694 return undefined;
36695 }
36696 return vect1.x * vect2.x + vect1.y * vect2.y;
36697 }
36698 Vector.dotProduct = dotProduct;
36699 function getDeltaVector(p0, p1) {
36700 if (!p0 || !p1) {
36701 return undefined;
36702 }
36703 return { x: p1.x - p0.x, y: p1.y - p0.y };
36704 }
36705 Vector.getDeltaVector = getDeltaVector;
36706 })(Vector = shapes.Vector || (shapes.Vector = {}));
36707 })(shapes = visuals.shapes || (visuals.shapes = {}));
36708 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
36709})(powerbi || (powerbi = {}));
36710/*
36711 * Power BI Visualizations
36712 *
36713 * Copyright (c) Microsoft Corporation
36714 * All rights reserved.
36715 * MIT License
36716 *
36717 * Permission is hereby granted, free of charge, to any person obtaining a copy
36718 * of this software and associated documentation files (the ""Software""), to deal
36719 * in the Software without restriction, including without limitation the rights
36720 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36721 * copies of the Software, and to permit persons to whom the Software is
36722 * furnished to do so, subject to the following conditions:
36723 *
36724 * The above copyright notice and this permission notice shall be included in
36725 * all copies or substantial portions of the Software.
36726 *
36727 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36728 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36729 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36730 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36731 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36732 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36733 * THE SOFTWARE.
36734 */
36735var powerbi;
36736(function (powerbi) {
36737 var visuals;
36738 (function (visuals) {
36739 var PixelConverter = jsCommon.PixelConverter;
36740 /** Utility class for slicer*/
36741 var SlicerUtil;
36742 (function (SlicerUtil) {
36743 /** CSS selectors for slicer elements. */
36744 var Selectors;
36745 (function (Selectors) {
36746 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
36747 Selectors.HeaderContainer = createClassAndSelector('headerContainer');
36748 Selectors.Header = createClassAndSelector('slicerHeader');
36749 Selectors.HeaderText = createClassAndSelector('headerText');
36750 Selectors.Body = createClassAndSelector('slicerBody');
36751 Selectors.Label = createClassAndSelector('slicerLabel');
36752 Selectors.LabelText = createClassAndSelector('slicerText');
36753 Selectors.LabelImage = createClassAndSelector('slicerImage');
36754 Selectors.CountText = createClassAndSelector('slicerCountText');
36755 Selectors.Clear = createClassAndSelector('clear');
36756 Selectors.MultiSelectEnabled = createClassAndSelector('isMultiSelectEnabled');
36757 })(Selectors = SlicerUtil.Selectors || (SlicerUtil.Selectors = {}));
36758 /** Const declarations*/
36759 var DisplayNameKeys;
36760 (function (DisplayNameKeys) {
36761 DisplayNameKeys.Clear = 'Slicer_Clear';
36762 DisplayNameKeys.SelectAll = 'Slicer_SelectAll';
36763 })(DisplayNameKeys = SlicerUtil.DisplayNameKeys || (SlicerUtil.DisplayNameKeys = {}));
36764 /** Helper class for slicer settings */
36765 var SettingsHelper;
36766 (function (SettingsHelper) {
36767 function areSettingsDefined(data) {
36768 return data != null && data.slicerSettings != null;
36769 }
36770 SettingsHelper.areSettingsDefined = areSettingsDefined;
36771 })(SettingsHelper = SlicerUtil.SettingsHelper || (SlicerUtil.SettingsHelper = {}));
36772 /** Helper class for handling slicer default value */
36773 var DefaultValueHandler;
36774 (function (DefaultValueHandler) {
36775 function getIdentityFields(dataView) {
36776 if (!dataView)
36777 return;
36778 var dataViewCategorical = dataView.categorical;
36779 if (!dataViewCategorical || _.isEmpty(dataViewCategorical.categories))
36780 return;
36781 return dataViewCategorical.categories[0].identityFields;
36782 }
36783 DefaultValueHandler.getIdentityFields = getIdentityFields;
36784 })(DefaultValueHandler = SlicerUtil.DefaultValueHandler || (SlicerUtil.DefaultValueHandler = {}));
36785 // Compare the sqExpr of the scopeId with sqExprs of the retained values.
36786 // If match found, remove the item from the retainedValues list, and return true,
36787 // otherwise return false.
36788 function tryRemoveValueFromRetainedList(value, selectedScopeIds, caseInsensitive) {
36789 if (!value || _.isEmpty(selectedScopeIds))
36790 return false;
36791 for (var i = 0, len = selectedScopeIds.length; i < len; i++) {
36792 var retainedValueScopeId = selectedScopeIds[i];
36793 if (powerbi.DataViewScopeIdentity.equals(value, retainedValueScopeId, caseInsensitive)) {
36794 selectedScopeIds.splice(i, 1);
36795 return true;
36796 }
36797 }
36798 return false;
36799 }
36800 SlicerUtil.tryRemoveValueFromRetainedList = tryRemoveValueFromRetainedList;
36801 /** Helper class for creating and measuring slicer DOM elements */
36802 var DOMHelper = (function () {
36803 function DOMHelper() {
36804 }
36805 DOMHelper.prototype.createSlicerHeader = function (hostServices) {
36806 var slicerHeaderDiv = document.createElement('div');
36807 slicerHeaderDiv.className = Selectors.Header.class;
36808 var slicerHeader = d3.select(slicerHeaderDiv);
36809 slicerHeader.append('span')
36810 .classed(Selectors.Clear.class, true)
36811 .attr('title', hostServices.getLocalizedString(DisplayNameKeys.Clear));
36812 slicerHeader.append('div').classed(Selectors.HeaderText.class, true);
36813 return slicerHeaderDiv;
36814 };
36815 DOMHelper.prototype.getHeaderTextProperties = function (settings) {
36816 var headerTextProperties = {
36817 fontFamily: 'wf_segoe-ui_normal',
36818 fontSize: '10px'
36819 };
36820 if (settings.header.show) {
36821 headerTextProperties.fontSize = PixelConverter.fromPoint(settings.header.textSize);
36822 }
36823 return headerTextProperties;
36824 };
36825 DOMHelper.prototype.getSlicerBodyViewport = function (currentViewport, settings, headerTextProperties) {
36826 var headerHeight = (settings.header.show) ? this.getHeaderHeight(settings, headerTextProperties) : 0;
36827 var slicerBodyHeight = currentViewport.height - (headerHeight + settings.header.borderBottomWidth);
36828 return {
36829 height: slicerBodyHeight,
36830 width: currentViewport.width
36831 };
36832 };
36833 DOMHelper.prototype.updateSlicerBodyDimensions = function (currentViewport, slicerBody, settings) {
36834 var slicerViewport = this.getSlicerBodyViewport(currentViewport, settings, this.getHeaderTextProperties(settings));
36835 slicerBody.style({
36836 'height': PixelConverter.toString(slicerViewport.height),
36837 'width': PixelConverter.toString(slicerViewport.width),
36838 });
36839 };
36840 DOMHelper.prototype.getHeaderHeight = function (settings, textProperties) {
36841 return powerbi.TextMeasurementService.estimateSvgTextHeight(this.getTextProperties(settings.header.textSize, textProperties)) + settings.general.outlineWeight;
36842 };
36843 DOMHelper.prototype.getRowHeight = function (settings, textProperties) {
36844 return powerbi.TextMeasurementService.estimateSvgTextHeight(this.getTextProperties(settings.slicerText.textSize, textProperties)) + this.getRowsOutlineWidth(settings.slicerText.outline, settings.general.outlineWeight);
36845 };
36846 DOMHelper.prototype.styleSlicerHeader = function (slicerHeader, settings, headerText) {
36847 if (settings.header.show) {
36848 slicerHeader.style('display', 'block');
36849 var headerTextElement = slicerHeader.select(Selectors.HeaderText.selector)
36850 .text(headerText);
36851 this.setSlicerHeaderTextStyle(headerTextElement, settings);
36852 }
36853 else {
36854 slicerHeader.style('display', 'none');
36855 }
36856 };
36857 DOMHelper.prototype.setSlicerTextStyle = function (slicerText, settings) {
36858 slicerText
36859 .style({
36860 'color': settings.slicerText.color,
36861 'background-color': settings.slicerText.background,
36862 'border-style': 'solid',
36863 'border-color': settings.general.outlineColor,
36864 'border-width': visuals.VisualBorderUtil.getBorderWidth(settings.slicerText.outline, settings.general.outlineWeight),
36865 'font-size': PixelConverter.fromPoint(settings.slicerText.textSize),
36866 });
36867 };
36868 DOMHelper.prototype.getRowsOutlineWidth = function (outlineElement, outlineWeight) {
36869 switch (outlineElement) {
36870 case visuals.outline.none:
36871 case visuals.outline.leftRight:
36872 return 0;
36873 case visuals.outline.bottomOnly:
36874 case visuals.outline.topOnly:
36875 return outlineWeight;
36876 case visuals.outline.topBottom:
36877 case visuals.outline.frame:
36878 return outlineWeight * 2;
36879 default:
36880 return 0;
36881 }
36882 };
36883 DOMHelper.prototype.setSlicerHeaderTextStyle = function (slicerHeader, settings) {
36884 slicerHeader
36885 .style({
36886 'border-style': 'solid',
36887 'border-color': settings.general.outlineColor,
36888 'border-width': visuals.VisualBorderUtil.getBorderWidth(settings.header.outline, settings.general.outlineWeight),
36889 'color': settings.header.fontColor,
36890 'background-color': settings.header.background,
36891 'font-size': PixelConverter.fromPoint(settings.header.textSize),
36892 });
36893 };
36894 DOMHelper.prototype.getTextProperties = function (textSize, textProperties) {
36895 textProperties.fontSize = PixelConverter.fromPoint(textSize);
36896 return textProperties;
36897 };
36898 return DOMHelper;
36899 }());
36900 SlicerUtil.DOMHelper = DOMHelper;
36901 })(SlicerUtil = visuals.SlicerUtil || (visuals.SlicerUtil = {}));
36902 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
36903})(powerbi || (powerbi = {}));
36904var powerbi;
36905(function (powerbi) {
36906 var visuals;
36907 (function (visuals) {
36908 /**
36909 * Contains functions/constants to aid in adding tooltips.
36910 */
36911 var tooltipUtils;
36912 (function (tooltipUtils) {
36913 function tooltipUpdate(selection, tooltips) {
36914 if (tooltips.length === 0)
36915 return;
36916 debug.assert(selection.length === tooltips.length || selection[0].length === tooltips.length, 'data length should match dom element count');
36917 var titles = selection.selectAll('title');
36918 var titlesUpdate = titles.data(function (d, i) { return [tooltips[i]]; });
36919 titlesUpdate.enter().append('title');
36920 titlesUpdate.exit().remove();
36921 titlesUpdate.text(function (d) { return d; });
36922 }
36923 tooltipUtils.tooltipUpdate = tooltipUpdate;
36924 })(tooltipUtils = visuals.tooltipUtils || (visuals.tooltipUtils = {}));
36925 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
36926})(powerbi || (powerbi = {}));
36927/*
36928 * Power BI Visualizations
36929 *
36930 * Copyright (c) Microsoft Corporation
36931 * All rights reserved.
36932 * MIT License
36933 *
36934 * Permission is hereby granted, free of charge, to any person obtaining a copy
36935 * of this software and associated documentation files (the ""Software""), to deal
36936 * in the Software without restriction, including without limitation the rights
36937 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36938 * copies of the Software, and to permit persons to whom the Software is
36939 * furnished to do so, subject to the following conditions:
36940 *
36941 * The above copyright notice and this permission notice shall be included in
36942 * all copies or substantial portions of the Software.
36943 *
36944 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36945 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36946 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36947 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36948 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36949 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36950 * THE SOFTWARE.
36951 */
36952var powerbi;
36953(function (powerbi) {
36954 var visuals;
36955 (function (visuals) {
36956 /**
36957 * Contains functions/constants to aid in SVG manupilation.
36958 */
36959 var SVGUtil;
36960 (function (SVGUtil) {
36961 /**
36962 * Very small values, when stringified, may be converted to scientific notation and cause a temporarily
36963 * invalid attribute or style property value.
36964 * For example, the number 0.0000001 is converted to the string "1e-7".
36965 * This is particularly noticeable when interpolating opacity values.
36966 * To avoid scientific notation, start or end the transition at 1e-6,
36967 * which is the smallest value that is not stringified in exponential notation.
36968 */
36969 SVGUtil.AlmostZero = 1e-6;
36970 /**
36971 * Creates a translate string for use with the SVG transform call.
36972 */
36973 function translate(x, y) {
36974 debug.assertValue(x, 'x');
36975 debug.assertValue(y, 'y');
36976 return 'translate(' + x + ',' + y + ')';
36977 }
36978 SVGUtil.translate = translate;
36979 /**
36980 * Creates a translateX string for use with the SVG transform call.
36981 */
36982 function translateXWithPixels(x) {
36983 debug.assertValue(x, 'x');
36984 return 'translateX(' + x + 'px)';
36985 }
36986 SVGUtil.translateXWithPixels = translateXWithPixels;
36987 function translateWithPixels(x, y) {
36988 debug.assertValue(x, 'x');
36989 debug.assertValue(y, 'y');
36990 return 'translate(' + x + 'px,' + y + 'px)';
36991 }
36992 SVGUtil.translateWithPixels = translateWithPixels;
36993 /**
36994 * Creates a translate + rotate string for use with the SVG transform call.
36995 */
36996 function translateAndRotate(x, y, px, py, angle) {
36997 debug.assertValue(x, 'x');
36998 debug.assertValue(y, 'y');
36999 debug.assertValue(px, 'px');
37000 debug.assertValue(py, 'py');
37001 debug.assertValue(angle, 'angle');
37002 return 'transform', "translate("
37003 + x + "," + y + ")"
37004 + " rotate(" + angle + "," + px + "," + py + ")";
37005 }
37006 SVGUtil.translateAndRotate = translateAndRotate;
37007 /**
37008 * Creates a scale string for use in a CSS transform property.
37009 */
37010 function scale(scale) {
37011 debug.assertValue(scale, 'scale');
37012 return "scale(" + scale + ")";
37013 }
37014 SVGUtil.scale = scale;
37015 /**
37016 * Creates a translate + scale string for use with the SVG transform call.
37017 */
37018 function translateAndScale(x, y, ratio) {
37019 debug.assertValue(x, 'x');
37020 debug.assertValue(y, 'y');
37021 debug.assertValue(ratio, 'ratio');
37022 return 'transform', "translate("
37023 + x + "," + y + ")"
37024 + " scale(" + ratio + ")";
37025 }
37026 SVGUtil.translateAndScale = translateAndScale;
37027 /**
37028 * Creates a transform origin string for use in a CSS transform-origin property.
37029 */
37030 function transformOrigin(xOffset, yOffset) {
37031 debug.assertValue(xOffset, 'xOffset');
37032 debug.assertValue(yOffset, 'yOffset');
37033 return xOffset + " " + yOffset;
37034 }
37035 SVGUtil.transformOrigin = transformOrigin;
37036 /**
37037 * Forces all D3 transitions to complete.
37038 * Normally, zero-delay transitions are executed after an instantaneous delay (<10ms).
37039 * This can cause a brief flicker if the browser renders the page twice: once at the end of the first event loop,
37040 * then again immediately on the first timer callback. By flushing the timer queue at the end of the first event loop,
37041 * you can run any zero-delay transitions immediately and avoid the flicker.
37042 *
37043 * These flickers are noticable on IE, and with a large number of webviews(not recommend you ever do this) on iOS.
37044 */
37045 function flushAllD3Transitions() {
37046 var now = Date.now;
37047 Date.now = function () { return Infinity; };
37048 d3.timer.flush();
37049 Date.now = now;
37050 }
37051 SVGUtil.flushAllD3Transitions = flushAllD3Transitions;
37052 /**
37053 * Wrapper for flushAllD3Transitions.
37054 */
37055 function flushAllD3TransitionsIfNeeded(options) {
37056 if (!options)
37057 return;
37058 var animationOptions = options;
37059 var asVisualInitOptions = options;
37060 if (asVisualInitOptions.animation)
37061 animationOptions = asVisualInitOptions.animation;
37062 if (animationOptions && animationOptions.transitionImmediate) {
37063 flushAllD3Transitions();
37064 }
37065 }
37066 SVGUtil.flushAllD3TransitionsIfNeeded = flushAllD3TransitionsIfNeeded;
37067 /**
37068 * There is a known bug in IE10 that causes cryptic crashes for SVG elements with a null 'd' attribute:
37069 * https://github.com/mbostock/d3/issues/1737
37070 */
37071 function ensureDAttribute(pathElement) {
37072 if (!pathElement.getAttribute('d')) {
37073 pathElement.setAttribute('d', '');
37074 }
37075 }
37076 SVGUtil.ensureDAttribute = ensureDAttribute;
37077 /**
37078 * In IE10, it is possible to return SVGPoints with NaN members.
37079 */
37080 function ensureValidSVGPoint(point) {
37081 if (isNaN(point.x)) {
37082 point.x = 0;
37083 }
37084 if (isNaN(point.y)) {
37085 point.y = 0;
37086 }
37087 }
37088 SVGUtil.ensureValidSVGPoint = ensureValidSVGPoint;
37089 /**
37090 * Parse the Transform string with value 'translate(x,y)'.
37091 * In Chrome for the translate(position) string the delimiter
37092 * is a comma and in IE it is a spaceso checking for both.
37093 */
37094 function parseTranslateTransform(input) {
37095 if (!input || input.length === 0) {
37096 return {
37097 x: "0",
37098 y: "0",
37099 };
37100 }
37101 var translateCoordinates = input.split(/[\s,]+/);
37102 debug.assertValue(translateCoordinates, 'translateCoordinates');
37103 debug.assert(translateCoordinates.length > 0, 'translate array must atleast have one value');
37104 var yValue = '0';
37105 var xValue;
37106 var xCoord = translateCoordinates[0];
37107 // Y coordinate is ommited in I.E if it is 0, so need to check against that
37108 if (translateCoordinates.length === 1) {
37109 // 10 refers to the length of 'translate('
37110 xValue = xCoord.substring(10, xCoord.length - 1);
37111 }
37112 else {
37113 var yCoord = translateCoordinates[1];
37114 yValue = yCoord.substring(0, yCoord.length - 1);
37115 // 10 refers to the length of 'translate('
37116 xValue = xCoord.substring(10, xCoord.length);
37117 }
37118 return {
37119 x: xValue,
37120 y: yValue
37121 };
37122 }
37123 SVGUtil.parseTranslateTransform = parseTranslateTransform;
37124 /**
37125 * Create an arrow.
37126 */
37127 function createArrow(width, height, rotate) {
37128 var transform = "rotate(" + rotate + " " + width / 2 + " " + height / 2 + ")";
37129 var path = "M0 0";
37130 path += "L0 " + height;
37131 path += "L" + width + " " + height / 2 + " Z";
37132 return {
37133 path: path,
37134 transform: transform
37135 };
37136 }
37137 SVGUtil.createArrow = createArrow;
37138 /**
37139 * Use the ratio of the scaled bounding rect and the SVG DOM bounding box to get the x and y transform scale values
37140 * @deprecated This function is unreliable across browser implementations, prefer to use SVGScaleDetector if needed.
37141 */
37142 function getTransformScaleRatios(svgElement) {
37143 debug.assertFail('deprecated');
37144 if (svgElement != null) {
37145 var scaledRect = svgElement.getBoundingClientRect();
37146 var domRect = svgElement.getBBox();
37147 if (domRect.height > 0 && domRect.width > 0) {
37148 return {
37149 x: scaledRect.width / domRect.width,
37150 y: scaledRect.height / domRect.height
37151 };
37152 }
37153 }
37154 return { x: 1, y: 1 };
37155 }
37156 SVGUtil.getTransformScaleRatios = getTransformScaleRatios;
37157 })(SVGUtil = visuals.SVGUtil || (visuals.SVGUtil = {}));
37158 var SVGScaleDetector = (function () {
37159 function SVGScaleDetector(svgElement) {
37160 this.scaleDetectorElement = svgElement
37161 .append('rect') // Using a <rect> which should have a reliable bounding box across browser implementations.
37162 .classed('scale-detector', true)
37163 .attr({
37164 width: 1,
37165 height: 1,
37166 'stroke-width': '0px',
37167 fill: 'none',
37168 })
37169 .node();
37170 }
37171 SVGScaleDetector.prototype.getScale = function () {
37172 var scaledRect = this.scaleDetectorElement.getBoundingClientRect();
37173 var domRect = this.scaleDetectorElement.getBBox();
37174 if (domRect.height > 0 && domRect.width > 0) {
37175 return {
37176 x: scaledRect.width / domRect.width,
37177 y: scaledRect.height / domRect.height
37178 };
37179 }
37180 return {
37181 x: 1,
37182 y: 1
37183 };
37184 };
37185 return SVGScaleDetector;
37186 }());
37187 visuals.SVGScaleDetector = SVGScaleDetector;
37188 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
37189})(powerbi || (powerbi = {}));
37190/*
37191 * Power BI Visualizations
37192 *
37193 * Copyright (c) Microsoft Corporation
37194 * All rights reserved.
37195 * MIT License
37196 *
37197 * Permission is hereby granted, free of charge, to any person obtaining a copy
37198 * of this software and associated documentation files (the ""Software""), to deal
37199 * in the Software without restriction, including without limitation the rights
37200 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37201 * copies of the Software, and to permit persons to whom the Software is
37202 * furnished to do so, subject to the following conditions:
37203 *
37204 * The above copyright notice and this permission notice shall be included in
37205 * all copies or substantial portions of the Software.
37206 *
37207 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37208 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37209 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37210 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37211 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37212 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37213 * THE SOFTWARE.
37214 */
37215var powerbi;
37216(function (powerbi) {
37217 var visuals;
37218 (function (visuals) {
37219 /**
37220 * Contains functions/constants to aid in text manupilation.
37221 */
37222 var TextUtil;
37223 (function (TextUtil) {
37224 /**
37225 * Remove breaking spaces from given string and replace by none breaking space (&nbsp).
37226 */
37227 function removeBreakingSpaces(str) {
37228 return str.toString().replace(new RegExp(' ', 'g'), '&nbsp');
37229 }
37230 TextUtil.removeBreakingSpaces = removeBreakingSpaces;
37231 /**
37232 * Remove ellipses from a given string
37233 */
37234 function removeEllipses(str) {
37235 return str.replace(/…/g, '');
37236 }
37237 TextUtil.removeEllipses = removeEllipses;
37238 /**
37239 * Replace every whitespace (0x20) with Non-Breaking Space (0xA0)
37240 * @param {string} txt String to replace White spaces
37241 * @returns Text after replcing white spaces
37242 */
37243 function replaceSpaceWithNBSP(txt) {
37244 if (txt != null)
37245 return txt.replace(/ /g, "\xA0");
37246 }
37247 TextUtil.replaceSpaceWithNBSP = replaceSpaceWithNBSP;
37248 })(TextUtil = visuals.TextUtil || (visuals.TextUtil = {}));
37249 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
37250})(powerbi || (powerbi = {}));
37251/*
37252 * Power BI Visualizations
37253 *
37254 * Copyright (c) Microsoft Corporation
37255 * All rights reserved.
37256 * MIT License
37257 *
37258 * Permission is hereby granted, free of charge, to any person obtaining a copy
37259 * of this software and associated documentation files (the ""Software""), to deal
37260 * in the Software without restriction, including without limitation the rights
37261 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37262 * copies of the Software, and to permit persons to whom the Software is
37263 * furnished to do so, subject to the following conditions:
37264 *
37265 * The above copyright notice and this permission notice shall be included in
37266 * all copies or substantial portions of the Software.
37267 *
37268 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37269 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37270 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37271 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37272 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37273 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37274 * THE SOFTWARE.
37275 */
37276var powerbi;
37277(function (powerbi) {
37278 var visuals;
37279 (function (visuals) {
37280 var DataRoleHelper = powerbi.data.DataRoleHelper;
37281 ;
37282 var GradientUtils;
37283 (function (GradientUtils) {
37284 var SQExprBuilder = powerbi.data.SQExprBuilder;
37285 var DefaultMidColor = "#ffffff";
37286 var DataPointPropertyIdentifier = "dataPoint";
37287 var FillRulePropertyIdentifier = "fillRule";
37288 function getFillRuleRole(objectDescs) {
37289 if (!objectDescs)
37290 return;
37291 for (var objectName in objectDescs) {
37292 var objectDesc = objectDescs[objectName];
37293 for (var propertyName in objectDesc.properties) {
37294 var propertyDesc = objectDesc.properties[propertyName];
37295 if (propertyDesc.type && propertyDesc.type[FillRulePropertyIdentifier]) {
37296 return propertyDesc.rule.inputRole;
37297 }
37298 }
37299 }
37300 }
37301 GradientUtils.getFillRuleRole = getFillRuleRole;
37302 function shouldShowGradient(visualConfig) {
37303 var isShowGradienCard = visualConfig && visualConfig.query && visualConfig.query.projections && visualConfig.query.projections['Gradient'] ? true : false;
37304 return isShowGradienCard;
37305 }
37306 GradientUtils.shouldShowGradient = shouldShowGradient;
37307 function getUpdatedGradientSettings(gradientObject) {
37308 var gradientSettings;
37309 if (gradientObject && !$.isEmptyObject(gradientObject)) {
37310 gradientSettings = getDefaultGradientSettings();
37311 for (var propertyName in gradientSettings) {
37312 var hasProperty = gradientObject.hasOwnProperty(propertyName);
37313 if (hasProperty) {
37314 var value = gradientObject[propertyName];
37315 if (value && value.solid && value.solid.color) {
37316 value = value.solid.color;
37317 }
37318 gradientSettings[propertyName] = value;
37319 }
37320 }
37321 }
37322 return gradientSettings;
37323 }
37324 GradientUtils.getUpdatedGradientSettings = getUpdatedGradientSettings;
37325 function getGradientMeasureIndex(dataViewCategorical) {
37326 if (dataViewCategorical && dataViewCategorical.values && dataViewCategorical.values.grouped) {
37327 var grouped = dataViewCategorical.values.grouped();
37328 return DataRoleHelper.getMeasureIndexOfRole(grouped, 'Gradient');
37329 }
37330 return -1;
37331 }
37332 GradientUtils.getGradientMeasureIndex = getGradientMeasureIndex;
37333 function getGradientValueColumn(dataViewCategorical) {
37334 if (dataViewCategorical == null)
37335 return null;
37336 // check for gradient measure index
37337 var gradientMeasureIndex = GradientUtils.getGradientMeasureIndex(dataViewCategorical);
37338 var gradientValueColumn = gradientMeasureIndex === -1 ? null : dataViewCategorical.values[gradientMeasureIndex];
37339 return gradientValueColumn;
37340 }
37341 GradientUtils.getGradientValueColumn = getGradientValueColumn;
37342 function hasGradientRole(dataViewCategorical) {
37343 var gradientMeasureIndex = getGradientMeasureIndex(dataViewCategorical);
37344 return gradientMeasureIndex >= 0;
37345 }
37346 GradientUtils.hasGradientRole = hasGradientRole;
37347 function getDefaultGradientSettings() {
37348 var colors = getDefaultColors();
37349 var gradientSettings = {
37350 diverging: false,
37351 minColor: colors.minColor,
37352 midColor: DefaultMidColor,
37353 maxColor: colors.maxColor,
37354 minValue: undefined,
37355 midValue: undefined,
37356 maxValue: undefined,
37357 };
37358 return gradientSettings;
37359 }
37360 GradientUtils.getDefaultGradientSettings = getDefaultGradientSettings;
37361 function getDefaultFillRuleDefinition() {
37362 return getLinearGradien2FillRuleDefinition();
37363 }
37364 GradientUtils.getDefaultFillRuleDefinition = getDefaultFillRuleDefinition;
37365 function updateFillRule(propertyName, propertyValue, definitions) {
37366 var dataPointObjectDefinition = powerbi.data.DataViewObjectDefinitions.ensure(definitions, DataPointPropertyIdentifier, null);
37367 var fillRule = getFillRule(definitions);
37368 var numericValueExpr;
37369 var colorValueExpr;
37370 if (!fillRule) {
37371 return;
37372 }
37373 if ($.isNumeric(propertyValue)) {
37374 numericValueExpr = propertyValue !== undefined ? SQExprBuilder.double(+propertyValue) : undefined;
37375 ;
37376 }
37377 if (propertyName === "minColor" || propertyName === "midColor" || propertyName === "maxColor") {
37378 colorValueExpr = getColorExpressionValue(fillRule, propertyName, propertyValue);
37379 }
37380 if (propertyName === "minColor") {
37381 updateMinColor(fillRule, colorValueExpr);
37382 }
37383 else if (propertyName === "midColor") {
37384 updateMidColor(fillRule, colorValueExpr);
37385 }
37386 else if (propertyName === "maxColor") {
37387 updateMaxColor(fillRule, colorValueExpr);
37388 }
37389 else if (propertyName === "minValue") {
37390 updateMinValue(fillRule, numericValueExpr);
37391 }
37392 else if (propertyName === "midValue") {
37393 updateMidValue(fillRule, numericValueExpr);
37394 }
37395 else if (propertyName === "maxValue") {
37396 updateMaxValue(fillRule, numericValueExpr);
37397 }
37398 else if (propertyName === "diverging") {
37399 if (propertyValue) {
37400 fillRule = getLinearGradien3FillRuleDefinition(fillRule);
37401 }
37402 else {
37403 fillRule = getLinearGradien2FillRuleDefinition(fillRule);
37404 }
37405 dataPointObjectDefinition.properties[FillRulePropertyIdentifier] = fillRule;
37406 }
37407 else if (propertyName === "revertToDefault") {
37408 fillRule = this.getDefaultFillRuleDefinition();
37409 dataPointObjectDefinition.properties[FillRulePropertyIdentifier] = fillRule;
37410 }
37411 }
37412 GradientUtils.updateFillRule = updateFillRule;
37413 function getGradientSettings(baseFillRule) {
37414 if (baseFillRule) {
37415 return getGradientSettingsFromRule(baseFillRule);
37416 }
37417 else {
37418 return getDefaultGradientSettings();
37419 }
37420 }
37421 GradientUtils.getGradientSettings = getGradientSettings;
37422 function getFillRule(objectDefinitions) {
37423 var fillRuleDefinition = powerbi.data.DataViewObjectDefinitions.getValue(objectDefinitions, { objectName: DataPointPropertyIdentifier, propertyName: FillRulePropertyIdentifier }, null);
37424 return fillRuleDefinition;
37425 }
37426 GradientUtils.getFillRule = getFillRule;
37427 function getDefaultColors() {
37428 var dataColors = new powerbi.visuals.DataColorPalette();
37429 var maxColorInfo = dataColors.getColorByIndex(0);
37430 var colors = d3.scale.linear()
37431 .domain([0, 100])
37432 .range(["#ffffff", maxColorInfo.value]);
37433 var maxColor = maxColorInfo.value;
37434 var minColor = colors(20);
37435 var midColor = DefaultMidColor;
37436 return {
37437 minColor: minColor,
37438 midColor: midColor,
37439 maxColor: maxColor,
37440 };
37441 }
37442 function getGradientSettingsFromRule(fillRule) {
37443 var maxColor;
37444 var minColor;
37445 var midColor = DefaultMidColor;
37446 var maxValue;
37447 var midValue;
37448 var minValue;
37449 var diverging = fillRule.linearGradient3 !== undefined;
37450 if (fillRule.linearGradient2) {
37451 var maxColorExpr = fillRule.linearGradient2.max.color;
37452 var minColorExpr = fillRule.linearGradient2.min.color;
37453 var maxValueExpr = fillRule.linearGradient2.max.value;
37454 var minValueExpr = fillRule.linearGradient2.min.value;
37455 maxColor = maxColorExpr.value;
37456 minColor = minColorExpr.value;
37457 if (maxValueExpr) {
37458 maxValue = maxValueExpr.value;
37459 }
37460 if (minValueExpr) {
37461 minValue = minValueExpr.value;
37462 }
37463 }
37464 else if (fillRule.linearGradient3) {
37465 var maxColorExpr = fillRule.linearGradient3.max.color;
37466 var midColorExpr = fillRule.linearGradient3.mid.color;
37467 var minColorExpr = fillRule.linearGradient3.min.color;
37468 var maxValueExpr = fillRule.linearGradient3.max.value;
37469 var midValueExpr = fillRule.linearGradient3.mid.value;
37470 var minValueExpr = fillRule.linearGradient3.min.value;
37471 maxColor = maxColorExpr.value;
37472 midColor = midColorExpr.value;
37473 minColor = minColorExpr.value;
37474 if (maxValueExpr) {
37475 maxValue = maxValueExpr.value;
37476 }
37477 if (midValueExpr) {
37478 midValue = midValueExpr.value;
37479 }
37480 if (minValueExpr) {
37481 minValue = minValueExpr.value;
37482 }
37483 }
37484 return {
37485 diverging: diverging,
37486 minColor: minColor,
37487 midColor: midColor,
37488 maxColor: maxColor,
37489 minValue: minValue,
37490 midValue: midValue,
37491 maxValue: maxValue,
37492 };
37493 }
37494 GradientUtils.getGradientSettingsFromRule = getGradientSettingsFromRule;
37495 /** Returns a string representing the gradient to be used for the GradientBar directive. */
37496 function getGradientBarColors(gradientSettings) {
37497 var colors = [];
37498 colors.push(gradientSettings.minColor);
37499 if (gradientSettings.diverging) {
37500 colors.push(gradientSettings.midColor);
37501 }
37502 colors.push(gradientSettings.maxColor);
37503 return colors.join(",");
37504 }
37505 GradientUtils.getGradientBarColors = getGradientBarColors;
37506 function getLinearGradien2FillRuleDefinition(baseFillRule) {
37507 var gradientSettings = getGradientSettings(baseFillRule);
37508 var fillRuleDefinition = {
37509 linearGradient2: {
37510 max: { color: SQExprBuilder.text(gradientSettings.maxColor) },
37511 min: { color: SQExprBuilder.text(gradientSettings.minColor) },
37512 }
37513 };
37514 return fillRuleDefinition;
37515 }
37516 function getLinearGradien3FillRuleDefinition(baseFillRule) {
37517 var gradientSettings = getGradientSettings(baseFillRule);
37518 var fillRuleDefinition = {
37519 linearGradient3: {
37520 max: { color: SQExprBuilder.text(gradientSettings.maxColor) },
37521 mid: { color: SQExprBuilder.text(gradientSettings.midColor) },
37522 min: { color: SQExprBuilder.text(gradientSettings.minColor) },
37523 }
37524 };
37525 return fillRuleDefinition;
37526 }
37527 function getDefaultColorExpression(fillRule, propertyName) {
37528 var defaultColor;
37529 var defaultFillRule;
37530 if (fillRule.linearGradient3) {
37531 defaultFillRule = getLinearGradien3FillRuleDefinition();
37532 if (propertyName === "minColor") {
37533 defaultColor = defaultFillRule.linearGradient3.min.color;
37534 }
37535 else if (propertyName === "midColor") {
37536 defaultColor = defaultFillRule.linearGradient3.mid.color;
37537 }
37538 else if (propertyName === "maxColor") {
37539 defaultColor = defaultFillRule.linearGradient3.max.color;
37540 }
37541 }
37542 else if (fillRule.linearGradient2) {
37543 defaultFillRule = getLinearGradien2FillRuleDefinition();
37544 if (propertyName === "minColor") {
37545 defaultColor = defaultFillRule.linearGradient2.min.color;
37546 }
37547 else if (propertyName === "maxColor") {
37548 defaultColor = defaultFillRule.linearGradient2.max.color;
37549 }
37550 }
37551 return defaultColor;
37552 }
37553 function getColorExpressionValue(fillRule, propertyName, propertyValue) {
37554 var colorExpressionValue;
37555 if (propertyValue) {
37556 colorExpressionValue = SQExprBuilder.text(propertyValue);
37557 }
37558 else {
37559 colorExpressionValue = getDefaultColorExpression(fillRule, propertyName);
37560 }
37561 return colorExpressionValue;
37562 }
37563 function updateMinColor(fillRule, colorExpressionValue) {
37564 if (fillRule.linearGradient2) {
37565 fillRule.linearGradient2.min.color = colorExpressionValue;
37566 }
37567 else if (fillRule.linearGradient3) {
37568 fillRule.linearGradient3.min.color = colorExpressionValue;
37569 }
37570 }
37571 function updateMidColor(fillRule, colorExpressionValue) {
37572 if (fillRule.linearGradient3) {
37573 fillRule.linearGradient3.mid.color = colorExpressionValue;
37574 }
37575 }
37576 function updateMaxColor(fillRule, colorExpressionValue) {
37577 if (fillRule.linearGradient2) {
37578 fillRule.linearGradient2.max.color = colorExpressionValue;
37579 }
37580 else if (fillRule.linearGradient3) {
37581 fillRule.linearGradient3.max.color = colorExpressionValue;
37582 }
37583 }
37584 function updateMinValue(fillRule, value) {
37585 if (fillRule.linearGradient2) {
37586 fillRule.linearGradient2.min.value = value;
37587 }
37588 else if (fillRule.linearGradient3) {
37589 fillRule.linearGradient3.min.value = value;
37590 }
37591 }
37592 function updateMidValue(fillRule, value) {
37593 if (fillRule.linearGradient3) {
37594 fillRule.linearGradient3.mid.value = value;
37595 }
37596 }
37597 function updateMaxValue(fillRule, value) {
37598 if (fillRule.linearGradient2) {
37599 fillRule.linearGradient2.max.value = value;
37600 }
37601 else if (fillRule.linearGradient3) {
37602 fillRule.linearGradient3.max.value = value;
37603 }
37604 }
37605 })(GradientUtils = visuals.GradientUtils || (visuals.GradientUtils = {}));
37606 ;
37607 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
37608})(powerbi || (powerbi = {}));
37609/*
37610 * Power BI Visualizations
37611 *
37612 * Copyright (c) Microsoft Corporation
37613 * All rights reserved.
37614 * MIT License
37615 *
37616 * Permission is hereby granted, free of charge, to any person obtaining a copy
37617 * of this software and associated documentation files (the ""Software""), to deal
37618 * in the Software without restriction, including without limitation the rights
37619 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37620 * copies of the Software, and to permit persons to whom the Software is
37621 * furnished to do so, subject to the following conditions:
37622 *
37623 * The above copyright notice and this permission notice shall be included in
37624 * all copies or substantial portions of the Software.
37625 *
37626 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37627 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37628 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37629 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37630 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37631 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37632 * THE SOFTWARE.
37633 */
37634var powerbi;
37635(function (powerbi) {
37636 var visuals;
37637 (function (visuals) {
37638 var visualBackgroundHelper;
37639 (function (visualBackgroundHelper) {
37640 function getDefaultColor() {
37641 return '#FFF';
37642 }
37643 visualBackgroundHelper.getDefaultColor = getDefaultColor;
37644 function getDefaultTransparency() {
37645 return 50;
37646 }
37647 visualBackgroundHelper.getDefaultTransparency = getDefaultTransparency;
37648 function getDefaultShow() {
37649 return false;
37650 }
37651 visualBackgroundHelper.getDefaultShow = getDefaultShow;
37652 function getDefaultValues() {
37653 return {
37654 color: getDefaultColor(),
37655 transparency: getDefaultTransparency(),
37656 show: getDefaultShow()
37657 };
37658 }
37659 visualBackgroundHelper.getDefaultValues = getDefaultValues;
37660 function enumeratePlot(enumeration, background) {
37661 var transparency = (background && background.transparency);
37662 if (transparency == null)
37663 transparency = getDefaultTransparency();
37664 var backgroundObject = {
37665 selector: null,
37666 properties: {
37667 transparency: transparency,
37668 image: (background && background.image)
37669 },
37670 objectName: 'plotArea',
37671 };
37672 enumeration.pushInstance(backgroundObject);
37673 }
37674 visualBackgroundHelper.enumeratePlot = enumeratePlot;
37675 function renderBackgroundImage(background, visualElement, layout) {
37676 var image = background && background.image;
37677 var imageUrl = image && image.url;
37678 var imageFit = image && image.scaling;
37679 var imageTransparency = background && background.transparency;
37680 var backgroundImage = visualElement.children('.background-image');
37681 // If there were image and it was removed
37682 if (!imageUrl) {
37683 if (backgroundImage.length !== 0)
37684 backgroundImage.remove();
37685 return;
37686 }
37687 // If this is the first edit of the image
37688 if (backgroundImage.length === 0) {
37689 // Place the div only if the image exists in order to keep the html as clean as possible
37690 visualElement.prepend('<div class="background-image"></div>');
37691 backgroundImage = visualElement.children('.background-image');
37692 // the div should be positioned absolute in order to get on top of the sibling svg
37693 backgroundImage.css('position', 'absolute');
37694 }
37695 // Get the size and margins from the visual for the div will placed inside the plot area
37696 backgroundImage.css({
37697 'width': layout.width,
37698 'height': layout.height,
37699 'margin-left': layout.left,
37700 'margin-top': layout.top,
37701 });
37702 // Background properties
37703 backgroundImage.css({
37704 'background-image': 'url(' + imageUrl + ')',
37705 'background-repeat': 'no-repeat',
37706 'opacity': (100 - imageTransparency) / 100,
37707 });
37708 switch (imageFit) {
37709 // The image will be centered in its initial size
37710 case visuals.imageScalingType.normal: {
37711 backgroundImage.css({
37712 'background-size': '',
37713 'background-position': '50% 50%',
37714 });
37715 break;
37716 }
37717 // The image will be streched all over the background
37718 case visuals.imageScalingType.fit: {
37719 backgroundImage.css({
37720 'background-size': '100% 100%',
37721 'background-position': '',
37722 });
37723 break;
37724 }
37725 // The image will stretch on the width and the height will scale accordingly
37726 case visuals.imageScalingType.fill: {
37727 backgroundImage.css({
37728 'background-size': '100%',
37729 'background-position': '50% 50%',
37730 });
37731 break;
37732 }
37733 default: {
37734 backgroundImage.css({
37735 'background-size': '',
37736 'background-position': '50% 50%',
37737 });
37738 break;
37739 }
37740 }
37741 }
37742 visualBackgroundHelper.renderBackgroundImage = renderBackgroundImage;
37743 })(visualBackgroundHelper = visuals.visualBackgroundHelper || (visuals.visualBackgroundHelper = {}));
37744 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
37745})(powerbi || (powerbi = {}));
37746/*
37747 * Power BI Visualizations
37748 *
37749 * Copyright (c) Microsoft Corporation
37750 * All rights reserved.
37751 * MIT License
37752 *
37753 * Permission is hereby granted, free of charge, to any person obtaining a copy
37754 * of this software and associated documentation files (the ""Software""), to deal
37755 * in the Software without restriction, including without limitation the rights
37756 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37757 * copies of the Software, and to permit persons to whom the Software is
37758 * furnished to do so, subject to the following conditions:
37759 *
37760 * The above copyright notice and this permission notice shall be included in
37761 * all copies or substantial portions of the Software.
37762 *
37763 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37764 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37765 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37766 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37767 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37768 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37769 * THE SOFTWARE.
37770 */
37771var powerbi;
37772(function (powerbi) {
37773 var visuals;
37774 (function (visuals) {
37775 var Selector = powerbi.data.Selector;
37776 /**
37777 * A helper class for building a VisualObjectInstanceEnumerationObject:
37778 * - Allows call chaining (e.g., builder.pushInstance({...}).pushInstance({...})
37779 * - Allows creating of containers (via pushContainer/popContainer)
37780 */
37781 var ObjectEnumerationBuilder = (function () {
37782 function ObjectEnumerationBuilder() {
37783 }
37784 ObjectEnumerationBuilder.prototype.pushInstance = function (instance) {
37785 debug.assertValue(instance, 'instance');
37786 var instances = this.instances;
37787 if (!instances) {
37788 instances = this.instances = [];
37789 }
37790 var containerIdx = this.containerIdx;
37791 if (containerIdx != null) {
37792 instance.containerIdx = containerIdx;
37793 }
37794 // Attempt to merge with an existing item if possible.
37795 for (var _i = 0, instances_1 = instances; _i < instances_1.length; _i++) {
37796 var existingInstance = instances_1[_i];
37797 if (this.canMerge(existingInstance, instance)) {
37798 this.extend(existingInstance, instance, 'properties');
37799 this.extend(existingInstance, instance, 'validValues');
37800 return this;
37801 }
37802 }
37803 instances.push(instance);
37804 return this;
37805 };
37806 ObjectEnumerationBuilder.prototype.pushContainer = function (container) {
37807 debug.assertValue(container, 'container');
37808 var containers = this.containers;
37809 if (!containers) {
37810 containers = this.containers = [];
37811 }
37812 var updatedLen = containers.push(container);
37813 this.containerIdx = updatedLen - 1;
37814 return this;
37815 };
37816 ObjectEnumerationBuilder.prototype.popContainer = function () {
37817 this.containerIdx = undefined;
37818 return this;
37819 };
37820 ObjectEnumerationBuilder.prototype.complete = function () {
37821 if (!this.instances)
37822 return;
37823 var result = {
37824 instances: this.instances,
37825 };
37826 var containers = this.containers;
37827 if (containers) {
37828 result.containers = containers;
37829 }
37830 return result;
37831 };
37832 ObjectEnumerationBuilder.prototype.canMerge = function (x, y) {
37833 debug.assertValue(x, 'x');
37834 debug.assertValue(y, 'y');
37835 return x.objectName === y.objectName &&
37836 x.containerIdx === y.containerIdx &&
37837 Selector.equals(x.selector, y.selector);
37838 };
37839 ObjectEnumerationBuilder.prototype.extend = function (target, source, propertyName) {
37840 debug.assertValue(target, 'target');
37841 debug.assertValue(source, 'source');
37842 debug.assertValue(propertyName, 'propertyName');
37843 var sourceValues = source[propertyName];
37844 if (!sourceValues)
37845 return;
37846 var targetValues = target[propertyName];
37847 if (!targetValues)
37848 targetValues = target[propertyName] = {};
37849 for (var valuePropertyName in sourceValues) {
37850 if (targetValues[valuePropertyName]) {
37851 // Properties have first-writer-wins semantics.
37852 continue;
37853 }
37854 targetValues[valuePropertyName] = sourceValues[valuePropertyName];
37855 }
37856 };
37857 ObjectEnumerationBuilder.merge = function (x, y) {
37858 var xNormalized = ObjectEnumerationBuilder.normalize(x);
37859 var yNormalized = ObjectEnumerationBuilder.normalize(y);
37860 if (!xNormalized || !yNormalized)
37861 return xNormalized || yNormalized;
37862 debug.assertValue(xNormalized, 'xNormalized');
37863 debug.assertValue(yNormalized, 'yNormalized');
37864 var xCategoryCount = xNormalized.containers ? xNormalized.containers.length : 0;
37865 for (var _i = 0, _a = yNormalized.instances; _i < _a.length; _i++) {
37866 var yInstance = _a[_i];
37867 xNormalized.instances.push(yInstance);
37868 if (yInstance.containerIdx != null)
37869 yInstance.containerIdx += xCategoryCount;
37870 }
37871 var yContainers = yNormalized.containers;
37872 if (!_.isEmpty(yContainers)) {
37873 if (xNormalized.containers)
37874 Array.prototype.push.apply(xNormalized.containers, yContainers);
37875 else
37876 xNormalized.containers = yContainers;
37877 }
37878 return xNormalized;
37879 };
37880 ObjectEnumerationBuilder.normalize = function (x) {
37881 debug.assertAnyValue(x, 'x');
37882 if (_.isArray(x)) {
37883 return { instances: x };
37884 }
37885 return x;
37886 };
37887 ObjectEnumerationBuilder.getContainerForInstance = function (enumeration, instance) {
37888 debug.assertValue(enumeration, "enumeration");
37889 debug.assertValue(instance, "instance");
37890 debug.assertValue(enumeration.containers, "containers");
37891 debug.assert(enumeration.containers.length > instance.containerIdx, "no container found in containers collection");
37892 return enumeration.containers[instance.containerIdx];
37893 };
37894 return ObjectEnumerationBuilder;
37895 }());
37896 visuals.ObjectEnumerationBuilder = ObjectEnumerationBuilder;
37897 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
37898})(powerbi || (powerbi = {}));
37899/*
37900 * Power BI Visualizations
37901 *
37902 * Copyright (c) Microsoft Corporation
37903 * All rights reserved.
37904 * MIT License
37905 *
37906 * Permission is hereby granted, free of charge, to any person obtaining a copy
37907 * of this software and associated documentation files (the ""Software""), to deal
37908 * in the Software without restriction, including without limitation the rights
37909 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37910 * copies of the Software, and to permit persons to whom the Software is
37911 * furnished to do so, subject to the following conditions:
37912 *
37913 * The above copyright notice and this permission notice shall be included in
37914 * all copies or substantial portions of the Software.
37915 *
37916 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37917 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37918 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37919 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37920 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37921 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37922 * THE SOFTWARE.
37923 */
37924var powerbi;
37925(function (powerbi) {
37926 var visuals;
37927 (function (visuals) {
37928 /** Helper class for Visual border styles */
37929 var VisualBorderUtil;
37930 (function (VisualBorderUtil) {
37931 /**
37932 * Gets The Boder Width string (e.g. 0px 1px 2px 3px)
37933 * @param {OutlineType} string Type of the Outline, one of Visuals.outline.<XX> const strings
37934 * @param {number} outlineWeight Weight of the outline in pixels
37935 * @returns String representing the Border Width
37936 */
37937 function getBorderWidth(outlineType, outlineWeight) {
37938 switch (outlineType) {
37939 case visuals.outline.none:
37940 return '0px';
37941 case visuals.outline.bottomOnly:
37942 return '0px 0px ' + outlineWeight + 'px 0px';
37943 case visuals.outline.topOnly:
37944 return outlineWeight + 'px 0px 0px 0px';
37945 case visuals.outline.leftOnly:
37946 return '0px 0px 0px ' + outlineWeight + 'px';
37947 case visuals.outline.rightOnly:
37948 return '0px ' + outlineWeight + 'px 0px 0px';
37949 case visuals.outline.topBottom:
37950 return outlineWeight + 'px 0px';
37951 case visuals.outline.leftRight:
37952 return '0px ' + outlineWeight + 'px';
37953 case visuals.outline.frame:
37954 return outlineWeight + 'px';
37955 default:
37956 debug.assertFail('Unexpected OutlineType value: ' + outlineType);
37957 return '0px';
37958 }
37959 }
37960 VisualBorderUtil.getBorderWidth = getBorderWidth;
37961 })(VisualBorderUtil = visuals.VisualBorderUtil || (visuals.VisualBorderUtil = {}));
37962 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
37963})(powerbi || (powerbi = {}));
37964/*
37965 * Power BI Visualizations
37966 *
37967 * Copyright (c) Microsoft Corporation
37968 * All rights reserved.
37969 * MIT License
37970 *
37971 * Permission is hereby granted, free of charge, to any person obtaining a copy
37972 * of this software and associated documentation files (the ""Software""), to deal
37973 * in the Software without restriction, including without limitation the rights
37974 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37975 * copies of the Software, and to permit persons to whom the Software is
37976 * furnished to do so, subject to the following conditions:
37977 *
37978 * The above copyright notice and this permission notice shall be included in
37979 * all copies or substantial portions of the Software.
37980 *
37981 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37982 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37983 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37984 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37985 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37986 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37987 * THE SOFTWARE.
37988 */
37989var powerbi;
37990(function (powerbi) {
37991 var visuals;
37992 (function (visuals) {
37993 /** Transformation matrix math wrapper */
37994 var Transform = (function () {
37995 // Constructor
37996 function Transform(m) {
37997 this.matrix = m || {
37998 m00: 1, m01: 0, m02: 0,
37999 m10: 0, m11: 1, m12: 0,
38000 };
38001 }
38002 // Methods
38003 Transform.prototype.applyToPoint = function (point) {
38004 if (!point) {
38005 return point;
38006 }
38007 var m = this.matrix;
38008 return {
38009 x: m.m00 * point.x + m.m01 * point.y + m.m02,
38010 y: m.m10 * point.x + m.m11 * point.y + m.m12,
38011 };
38012 };
38013 Transform.prototype.applyToRect = function (rect) {
38014 if (!rect) {
38015 return rect;
38016 }
38017 var x0 = rect.left;
38018 var y0 = rect.top;
38019 var m = this.matrix;
38020 var isScaled = m.m00 !== 1 || m.m11 !== 1;
38021 var isRotated = m.m01 !== 0 || m.m10 !== 0;
38022 if (!isRotated && !isScaled) {
38023 // Optimize for the translation only case
38024 return { left: x0 + m.m02, top: y0 + m.m12, width: rect.width, height: rect.height };
38025 }
38026 var x1 = rect.left + rect.width;
38027 var y1 = rect.top + rect.height;
38028 var minX;
38029 var maxX;
38030 var minY;
38031 var maxY;
38032 if (isRotated) {
38033 var p0x = m.m00 * x0 + m.m01 * y0 + m.m02;
38034 var p0y = m.m10 * x0 + m.m11 * y0 + m.m12;
38035 var p1x = m.m00 * x0 + m.m01 * y1 + m.m02;
38036 var p1y = m.m10 * x0 + m.m11 * y1 + m.m12;
38037 var p2x = m.m00 * x1 + m.m01 * y0 + m.m02;
38038 var p2y = m.m10 * x1 + m.m11 * y0 + m.m12;
38039 var p3x = m.m00 * x1 + m.m01 * y1 + m.m02;
38040 var p3y = m.m10 * x1 + m.m11 * y1 + m.m12;
38041 minX = Math.min(p0x, p1x, p2x, p3x);
38042 maxX = Math.max(p0x, p1x, p2x, p3x);
38043 minY = Math.min(p0y, p1y, p2y, p3y);
38044 maxY = Math.max(p0y, p1y, p2y, p3y);
38045 }
38046 else {
38047 var p0x = m.m00 * x0 + m.m02;
38048 var p0y = m.m11 * y0 + m.m12;
38049 var p3x = m.m00 * x1 + m.m02;
38050 var p3y = m.m11 * y1 + m.m12;
38051 minX = Math.min(p0x, p3x);
38052 maxX = Math.max(p0x, p3x);
38053 minY = Math.min(p0y, p3y);
38054 maxY = Math.max(p0y, p3y);
38055 }
38056 return { left: minX, top: minY, width: maxX - minX, height: maxY - minY };
38057 };
38058 Transform.prototype.translate = function (xOffset, yOffset) {
38059 if (xOffset !== 0 || yOffset !== 0) {
38060 var m = createTranslateMatrix(xOffset, yOffset);
38061 this.matrix = multiplyMatrices(this.matrix, m);
38062 this._inverse = null;
38063 }
38064 };
38065 Transform.prototype.scale = function (xScale, yScale) {
38066 if (xScale !== 1 || yScale !== 1) {
38067 var m = createScaleMatrix(xScale, yScale);
38068 this.matrix = multiplyMatrices(this.matrix, m);
38069 this._inverse = null;
38070 }
38071 };
38072 Transform.prototype.rotate = function (angleInRadians) {
38073 if (angleInRadians !== 0) {
38074 var m = createRotationMatrix(angleInRadians);
38075 this.matrix = multiplyMatrices(this.matrix, m);
38076 this._inverse = null;
38077 }
38078 };
38079 Transform.prototype.add = function (other) {
38080 if (other) {
38081 this.matrix = multiplyMatrices(this.matrix, other.matrix);
38082 this._inverse = null;
38083 }
38084 };
38085 Transform.prototype.getInverse = function () {
38086 if (!this._inverse) {
38087 this._inverse = new Transform(createInverseMatrix(this.matrix));
38088 }
38089 return this._inverse;
38090 };
38091 return Transform;
38092 }());
38093 visuals.Transform = Transform;
38094 function createTranslateMatrix(xOffset, yOffset) {
38095 return {
38096 m00: 1, m01: 0, m02: xOffset,
38097 m10: 0, m11: 1, m12: yOffset,
38098 };
38099 }
38100 visuals.createTranslateMatrix = createTranslateMatrix;
38101 function createScaleMatrix(xScale, yScale) {
38102 return {
38103 m00: xScale, m01: 0, m02: 0,
38104 m10: 0, m11: yScale, m12: 0
38105 };
38106 }
38107 visuals.createScaleMatrix = createScaleMatrix;
38108 function createRotationMatrix(angleInRads) {
38109 var a = angleInRads;
38110 var sinA = Math.sin(a);
38111 var cosA = Math.cos(a);
38112 return {
38113 m00: cosA, m01: -sinA, m02: 0,
38114 m10: sinA, m11: cosA, m12: 0,
38115 };
38116 }
38117 visuals.createRotationMatrix = createRotationMatrix;
38118 function createInverseMatrix(m) {
38119 var determinant = m.m00 * m.m11 - m.m01 * m.m10;
38120 var invdet = 1 / determinant;
38121 return {
38122 m00: m.m11 * invdet,
38123 m01: -m.m01 * invdet,
38124 m02: (m.m01 * m.m12 - m.m02 * m.m11) * invdet,
38125 m10: -m.m10 * invdet,
38126 m11: m.m00 * invdet,
38127 m12: -(m.m00 * m.m12 - m.m10 * m.m02) * invdet
38128 };
38129 }
38130 visuals.createInverseMatrix = createInverseMatrix;
38131 function multiplyMatrices(a, b) {
38132 return {
38133 m00: a.m00 * b.m00 + a.m01 * b.m10,
38134 m01: a.m00 * b.m01 + a.m01 * b.m11,
38135 m02: a.m00 * b.m02 + a.m01 * b.m12 + a.m02,
38136 m10: a.m10 * b.m00 + a.m11 * b.m10,
38137 m11: a.m10 * b.m01 + a.m11 * b.m11,
38138 m12: a.m10 * b.m02 + a.m11 * b.m12 + a.m12,
38139 };
38140 }
38141 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
38142})(powerbi || (powerbi = {}));
38143/*
38144 * Power BI Visualizations
38145 *
38146 * Copyright (c) Microsoft Corporation
38147 * All rights reserved.
38148 * MIT License
38149 *
38150 * Permission is hereby granted, free of charge, to any person obtaining a copy
38151 * of this software and associated documentation files (the ""Software""), to deal
38152 * in the Software without restriction, including without limitation the rights
38153 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38154 * copies of the Software, and to permit persons to whom the Software is
38155 * furnished to do so, subject to the following conditions:
38156 *
38157 * The above copyright notice and this permission notice shall be included in
38158 * all copies or substantial portions of the Software.
38159 *
38160 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38161 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38162 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38163 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38164 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38165 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38166 * THE SOFTWARE.
38167 */
38168var powerbi;
38169(function (powerbi) {
38170 var visuals;
38171 (function (visuals) {
38172 var Color = jsCommon.Color;
38173 var DataRoleHelper = powerbi.data.DataRoleHelper;
38174 var TrendLineHelper;
38175 (function (TrendLineHelper) {
38176 var trendLinePropertyNames = {
38177 show: 'show',
38178 lineColor: 'lineColor',
38179 transparency: 'transparency',
38180 style: 'style',
38181 combineSeries: 'combineSeries',
38182 useHighlightValues: 'useHighlightValues',
38183 };
38184 var trendObjectName = 'trend';
38185 TrendLineHelper.defaults = {
38186 lineColor: { solid: { color: '#000' } },
38187 lineStyle: visuals.lineStyle.dashed,
38188 transparency: 0,
38189 combineSeries: true,
38190 useHighlightValues: true,
38191 };
38192 var TrendLineClassSelector = jsCommon.CssConstants.createClassAndSelector('trend-line');
38193 var TrendLineLayerClassSelector = jsCommon.CssConstants.createClassAndSelector('trend-line-layer');
38194 function enumerateObjectInstances(enumeration, trendLines) {
38195 debug.assertValue(enumeration, 'enumeration');
38196 if (_.isEmpty(trendLines)) {
38197 enumeration.pushInstance({
38198 selector: null,
38199 properties: {
38200 show: false,
38201 lineColor: TrendLineHelper.defaults.lineColor,
38202 transparency: TrendLineHelper.defaults.transparency,
38203 style: TrendLineHelper.defaults.lineStyle,
38204 combineSeries: TrendLineHelper.defaults.combineSeries,
38205 },
38206 objectName: trendObjectName,
38207 });
38208 return;
38209 }
38210 var trendLine = trendLines[0];
38211 var properties = {};
38212 properties['show'] = trendLine.show;
38213 if (trendLine.combineSeries)
38214 properties['lineColor'] = trendLine.lineColor;
38215 properties['transparency'] = trendLine.transparency;
38216 properties['style'] = trendLine.style;
38217 properties['combineSeries'] = trendLine.combineSeries;
38218 properties['useHighlightValues'] = trendLine.useHighlightValues;
38219 enumeration.pushInstance({
38220 selector: null,
38221 properties: properties,
38222 objectName: trendObjectName,
38223 });
38224 }
38225 TrendLineHelper.enumerateObjectInstances = enumerateObjectInstances;
38226 function isDataViewForRegression(dataView) {
38227 return DataRoleHelper.hasRoleInDataView(dataView, 'regression.X');
38228 }
38229 TrendLineHelper.isDataViewForRegression = isDataViewForRegression;
38230 function readDataView(dataView, sourceDataView, y2, colors) {
38231 if (!dataView || !dataView.categorical)
38232 return;
38233 var categorical = dataView.categorical;
38234 if (_.isEmpty(categorical.categories) || _.isEmpty(categorical.values))
38235 return;
38236 var categories = categorical.categories[0].values;
38237 var groups = categorical.values.grouped();
38238 if (!categories || !groups)
38239 return;
38240 var trendProperties = powerbi.DataViewObjects.getObject(dataView.metadata.objects, trendObjectName, {});
38241 var show = powerbi.DataViewObject.getValue(trendProperties, trendLinePropertyNames.show, false);
38242 var lineColor = powerbi.DataViewObject.getValue(trendProperties, trendLinePropertyNames.lineColor);
38243 var transparency = powerbi.DataViewObject.getValue(trendProperties, trendLinePropertyNames.transparency, TrendLineHelper.defaults.transparency);
38244 var style = powerbi.DataViewObject.getValue(trendProperties, trendLinePropertyNames.style, TrendLineHelper.defaults.lineStyle);
38245 var combineSeries = powerbi.DataViewObject.getValue(trendProperties, trendLinePropertyNames.combineSeries, TrendLineHelper.defaults.combineSeries);
38246 var useHighlightValues = powerbi.DataViewObject.getValue(trendProperties, trendLinePropertyNames.useHighlightValues, TrendLineHelper.defaults.useHighlightValues);
38247 // Trend lines generated by Insights will be putting line color here, we should convert the Insights code to create
38248 // "trend" objects like above and write the upgrade code to handle pinned tiles with trend lines before removing any feature switch.
38249 var legacyColor = powerbi.DataViewObjects.getValue(categorical.values[0].source.objects, visuals.lineChartProps.dataPoint.fill);
38250 if (legacyColor)
38251 lineColor = legacyColor;
38252 var objects = sourceDataView.metadata.objects;
38253 var defaultColor = powerbi.DataViewObjects.getFillColor(objects, { objectName: 'dataPoint', propertyName: 'defaultColor' });
38254 var colorHelper = new visuals.ColorHelper(colors, { objectName: 'dataPoint', propertyName: 'fill' }, defaultColor);
38255 var trendLines = [];
38256 for (var groupIndex = 0; groupIndex < groups.length; groupIndex++) {
38257 var group = groups[groupIndex];
38258 var points = [];
38259 for (var i = 0; i < categories.length; i++) {
38260 var x = visuals.AxisHelper.normalizeNonFiniteNumber(categories[i]);
38261 // There is a assumption here that the group only has 1 set of values in it. Once we add more things like confidence bands,
38262 // this assumption will not be true. This assumption comes from the way dataViewRegresion generates the dataView
38263 var valueColumn = group.values[0];
38264 var values = void 0;
38265 if (useHighlightValues && valueColumn.highlights) {
38266 values = valueColumn.highlights;
38267 }
38268 else {
38269 values = valueColumn.values;
38270 }
38271 var y = visuals.AxisHelper.normalizeNonFiniteNumber(values[i]);
38272 if (x != null && y != null) {
38273 points.push({
38274 x: x,
38275 y: y,
38276 });
38277 }
38278 }
38279 var seriesLineColor = void 0;
38280 if (combineSeries) {
38281 seriesLineColor = lineColor || TrendLineHelper.defaults.lineColor;
38282 }
38283 else {
38284 // TODO: This should likely be delegated to the layer which knows how to choose the correct color for any given situation.
38285 if (sourceDataView.categorical.values.source) {
38286 // Dynamic series
38287 var sourceGroups = sourceDataView.categorical.values.grouped();
38288 var color = colorHelper.getColorForSeriesValue(sourceGroups[groupIndex].objects, sourceDataView.categorical.values.identityFields, group.name);
38289 color = darkenTrendLineColor(color);
38290 seriesLineColor = { solid: { color: color } };
38291 }
38292 else {
38293 // Static series
38294 var matchingMeasure = sourceDataView.categorical.values[groupIndex];
38295 var color = colorHelper.getColorForMeasure(matchingMeasure.source.objects, group.name);
38296 color = darkenTrendLineColor(color);
38297 seriesLineColor = { solid: { color: color } };
38298 }
38299 }
38300 trendLines.push({
38301 points: points,
38302 show: show,
38303 lineColor: seriesLineColor,
38304 transparency: transparency,
38305 style: style,
38306 combineSeries: combineSeries,
38307 useHighlightValues: useHighlightValues,
38308 y2Axis: y2,
38309 });
38310 }
38311 return trendLines;
38312 }
38313 TrendLineHelper.readDataView = readDataView;
38314 function darkenTrendLineColor(color) {
38315 var rgb = Color.parseColorString(color);
38316 rgb = Color.darken(rgb, 20);
38317 return Color.rgbString(rgb);
38318 }
38319 TrendLineHelper.darkenTrendLineColor = darkenTrendLineColor;
38320 function render(trendLines, graphicsContext, axes, viewport) {
38321 var layer = graphicsContext.select(TrendLineLayerClassSelector.selector);
38322 if (layer.empty()) {
38323 layer = graphicsContext.append('svg').classed(TrendLineLayerClassSelector.class, true);
38324 }
38325 layer.attr({
38326 height: viewport.height,
38327 width: viewport.width
38328 });
38329 var lines = layer.selectAll(TrendLineClassSelector.selector).data(trendLines || []);
38330 lines.enter().append('path').classed(TrendLineClassSelector.class, true);
38331 lines
38332 .attr('d', function (d) {
38333 var xScale = axes.x.scale;
38334 var yScale = (d.y2Axis && axes.y2) ? axes.y2.scale : axes.y1.scale;
38335 var pathGen = d3.svg.line()
38336 .x(function (point) { return xScale(point.x); })
38337 .y(function (point) { return yScale(point.y); });
38338 return pathGen(_.filter(d.points, function (point) { return point.x != null && point.y != null; }));
38339 });
38340 lines.each(function (d) {
38341 var line = d3.select(this);
38342 var style = {};
38343 style.stroke = d.lineColor.solid.color;
38344 if (d.transparency != null) {
38345 style['stroke-opacity'] = (100 - d.transparency) / 100;
38346 }
38347 if (d.style === visuals.lineStyle.dashed) {
38348 style['stroke-dasharray'] = "5, 5";
38349 }
38350 else if (d.style === visuals.lineStyle.dotted) {
38351 style['stroke-dasharray'] = "1, 5";
38352 style['stroke-linecap'] = "round";
38353 }
38354 else if (d.style === visuals.lineStyle.solid) {
38355 style['stroke-dasharray'] = null;
38356 style['stroke-linecap'] = null;
38357 }
38358 line.style(style);
38359 });
38360 lines.exit().remove();
38361 }
38362 TrendLineHelper.render = render;
38363 })(TrendLineHelper = visuals.TrendLineHelper || (visuals.TrendLineHelper = {}));
38364 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
38365})(powerbi || (powerbi = {}));
38366/*
38367 * Power BI Visualizations
38368 *
38369 * Copyright (c) Microsoft Corporation
38370 * All rights reserved.
38371 * MIT License
38372 *
38373 * Permission is hereby granted, free of charge, to any person obtaining a copy
38374 * of this software and associated documentation files (the ""Software""), to deal
38375 * in the Software without restriction, including without limitation the rights
38376 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38377 * copies of the Software, and to permit persons to whom the Software is
38378 * furnished to do so, subject to the following conditions:
38379 *
38380 * The above copyright notice and this permission notice shall be included in
38381 * all copies or substantial portions of the Software.
38382 *
38383 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38384 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38385 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38386 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38387 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38388 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38389 * THE SOFTWARE.
38390 */
38391var powerbi;
38392(function (powerbi) {
38393 var visuals;
38394 (function (visuals) {
38395 var visibilityHelper;
38396 (function (visibilityHelper) {
38397 /** Helper method that uses jQuery :visible selector to determine if visual is visible.
38398 Elements are considered visible if they consume space in the document. Visible elements have a width or height that is greater than zero.
38399 Elements with visibility: hidden or opacity: 0 are considered visible, since they still consume space in the layout.
38400 */
38401 function partiallyVisible(element) {
38402 return element.is(":visible");
38403 }
38404 visibilityHelper.partiallyVisible = partiallyVisible;
38405 })(visibilityHelper = visuals.visibilityHelper || (visuals.visibilityHelper = {}));
38406 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
38407})(powerbi || (powerbi = {}));
38408/*
38409 * Power BI Visualizations
38410 *
38411 * Copyright (c) Microsoft Corporation
38412 * All rights reserved.
38413 * MIT License
38414 *
38415 * Permission is hereby granted, free of charge, to any person obtaining a copy
38416 * of this software and associated documentation files (the ""Software""), to deal
38417 * in the Software without restriction, including without limitation the rights
38418 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38419 * copies of the Software, and to permit persons to whom the Software is
38420 * furnished to do so, subject to the following conditions:
38421 *
38422 * The above copyright notice and this permission notice shall be included in
38423 * all copies or substantial portions of the Software.
38424 *
38425 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38426 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38427 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38428 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38429 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38430 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38431 * THE SOFTWARE.
38432 */
38433var powerbi;
38434(function (powerbi) {
38435 var Selector = powerbi.data.Selector;
38436 var VisualObjectRepetition;
38437 (function (VisualObjectRepetition) {
38438 /** Determines whether two repetitions are equal. */
38439 function equals(x, y) {
38440 // Normalize falsy to null
38441 x = x || null;
38442 y = y || null;
38443 if (x === y)
38444 return true;
38445 if (!x !== !y)
38446 return false;
38447 debug.assertValue(x, 'x');
38448 debug.assertValue(y, 'y');
38449 if (!Selector.equals(x.selector, y.selector))
38450 return false;
38451 return _.isEqual(x.objects, y.objects);
38452 }
38453 VisualObjectRepetition.equals = equals;
38454 })(VisualObjectRepetition = powerbi.VisualObjectRepetition || (powerbi.VisualObjectRepetition = {}));
38455})(powerbi || (powerbi = {}));
38456/*
38457 * Power BI Visualizations
38458 *
38459 * Copyright (c) Microsoft Corporation
38460 * All rights reserved.
38461 * MIT License
38462 *
38463 * Permission is hereby granted, free of charge, to any person obtaining a copy
38464 * of this software and associated documentation files (the ""Software""), to deal
38465 * in the Software without restriction, including without limitation the rights
38466 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38467 * copies of the Software, and to permit persons to whom the Software is
38468 * furnished to do so, subject to the following conditions:
38469 *
38470 * The above copyright notice and this permission notice shall be included in
38471 * all copies or substantial portions of the Software.
38472 *
38473 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38474 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38475 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38476 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38477 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38478 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38479 * THE SOFTWARE.
38480 */
38481var powerbi;
38482(function (powerbi) {
38483 var visuals;
38484 (function (visuals) {
38485 var SemanticFilter = powerbi.data.SemanticFilter;
38486 var UrlUtils = jsCommon.UrlUtils;
38487 /** Helper module for converting a DataView into SlicerData. */
38488 var DataConversion;
38489 (function (DataConversion) {
38490 function convert(dataView, localizedSelectAllText, interactivityService, hostServices) {
38491 debug.assertValue(hostServices, 'hostServices');
38492 if (!dataView || !dataView.categorical || _.isEmpty(dataView.categorical.categories))
38493 return;
38494 var identityFields = dataView.categorical.categories[0].identityFields;
38495 if (!identityFields)
38496 return;
38497 var filter = (dataView.metadata &&
38498 dataView.metadata.objects &&
38499 powerbi.DataViewObjects.getValue(dataView.metadata.objects, visuals.slicerProps.filterPropertyIdentifier));
38500 var analyzer = hostServices.analyzeFilter({
38501 dataView: dataView,
38502 defaultValuePropertyId: visuals.slicerProps.defaultValue,
38503 filter: filter,
38504 fieldSQExprs: identityFields
38505 });
38506 if (!analyzer)
38507 return;
38508 var analyzedSemanticFilter = analyzer.filter;
38509 if (analyzedSemanticFilter && !SemanticFilter.isSameFilter(analyzedSemanticFilter, filter)) {
38510 interactivityService.handleClearSelection();
38511 var filterPropertyIdentifier = visuals.slicerProps.filterPropertyIdentifier;
38512 var properties = {};
38513 properties[filterPropertyIdentifier.propertyName] = analyzer.filter;
38514 var instance = {
38515 objectName: filterPropertyIdentifier.objectName,
38516 selector: undefined,
38517 properties: properties
38518 };
38519 var changes = {
38520 merge: [instance]
38521 };
38522 hostServices.persistProperties(changes);
38523 }
38524 var slicerData = getSlicerData(analyzer, dataView.metadata, dataView.categorical, localizedSelectAllText, interactivityService, hostServices);
38525 return slicerData;
38526 }
38527 DataConversion.convert = convert;
38528 function getSlicerData(analyzer, dataViewMetadata, categorical, localizedSelectAllText, interactivityService, hostServices) {
38529 var isInvertedSelectionMode = interactivityService && interactivityService.isSelectionModeInverted();
38530 var selectedScopeIds = analyzer.selectedIdentities;
38531 var hasSelectionOverride = !_.isEmpty(selectedScopeIds) || isInvertedSelectionMode === true;
38532 if (!isInvertedSelectionMode && analyzer.filter)
38533 isInvertedSelectionMode = analyzer.isNotFilter;
38534 if (interactivityService) {
38535 // To indicate whether the selection is Not selected items
38536 interactivityService.setSelectionModeInverted(isInvertedSelectionMode);
38537 // defaultValueMode will be used when determine show/hide clear button.
38538 interactivityService.setDefaultValueMode(SemanticFilter.isDefaultFilter(analyzer.filter));
38539 }
38540 var category = categorical.categories[0];
38541 var categoryValuesLen = category && category.values ? category.values.length : 0;
38542 var slicerDataPoints = [];
38543 var formatString = visuals.valueFormatter.getFormatString(category.source, visuals.slicerProps.formatString);
38544 var numOfSelected = 0;
38545 var valueCounts = categorical.values && categorical.values[0] && categorical.values[0].values;
38546 if (valueCounts && _.isEmpty(valueCounts))
38547 valueCounts = undefined;
38548 debug.assert(!valueCounts || valueCounts.length === categoryValuesLen, "valueCounts doesn't match values");
38549 var isImageData = dataViewMetadata &&
38550 !_.isEmpty(dataViewMetadata.columns) && visuals.converterHelper.isImageUrlColumn(dataViewMetadata.columns[0]);
38551 var displayNameIdentityPairs = [];
38552 for (var i = 0; i < categoryValuesLen; i++) {
38553 var scopeId = category.identity && category.identity[i];
38554 var value = category.values && category.values[i];
38555 var count = valueCounts && valueCounts[i];
38556 var isRetained = hasSelectionOverride ? visuals.SlicerUtil.tryRemoveValueFromRetainedList(scopeId, selectedScopeIds) : false;
38557 var label = visuals.valueFormatter.format(value, formatString);
38558 var isImage = isImageData === true && UrlUtils.isValidImageUrl(label);
38559 var slicerData_1 = {
38560 value: label,
38561 tooltip: label,
38562 identity: visuals.SelectionId.createWithId(scopeId),
38563 selected: isRetained,
38564 count: count,
38565 isImage: isImage,
38566 };
38567 if (isRetained) {
38568 var displayNameIdentityPair = {
38569 displayName: label,
38570 identity: scopeId
38571 };
38572 displayNameIdentityPairs.push(displayNameIdentityPair);
38573 }
38574 slicerDataPoints.push(slicerData_1);
38575 if (slicerData_1.selected)
38576 numOfSelected++;
38577 }
38578 if (!_.isEmpty(displayNameIdentityPairs))
38579 hostServices.setIdentityDisplayNames(displayNameIdentityPairs);
38580 // Add retained values that are not in the returned dataview to the value list.
38581 if (hasSelectionOverride && !_.isEmpty(selectedScopeIds)) {
38582 var displayNamesIdentityPairs = hostServices.getIdentityDisplayNames(selectedScopeIds);
38583 if (!_.isEmpty(displayNamesIdentityPairs)) {
38584 for (var _i = 0, displayNamesIdentityPairs_1 = displayNamesIdentityPairs; _i < displayNamesIdentityPairs_1.length; _i++) {
38585 var pair = displayNamesIdentityPairs_1[_i];
38586 // When there is no valueCounts, set count to be undefined, otherwise use 0 as the count for retained values
38587 var slicerData_2 = {
38588 value: pair.displayName,
38589 tooltip: pair.displayName,
38590 identity: visuals.SelectionId.createWithId(pair.identity),
38591 selected: true,
38592 count: valueCounts != null ? 0 : undefined,
38593 };
38594 slicerDataPoints.push(slicerData_2);
38595 numOfSelected++;
38596 }
38597 }
38598 }
38599 var defaultSettings = createDefaultSettings(dataViewMetadata);
38600 if (defaultSettings.selection.selectAllCheckboxEnabled) {
38601 //If selectAllCheckboxEnabled, and all the items are selected and there is no more data to request, then unselect all and toggle the invertedSelectionMode
38602 if (numOfSelected > 0 && !dataViewMetadata.segment && numOfSelected === slicerDataPoints.length) {
38603 isInvertedSelectionMode = !isInvertedSelectionMode;
38604 interactivityService.setSelectionModeInverted(isInvertedSelectionMode);
38605 for (var _a = 0, slicerDataPoints_1 = slicerDataPoints; _a < slicerDataPoints_1.length; _a++) {
38606 var item = slicerDataPoints_1[_a];
38607 item.selected = false;
38608 }
38609 hasSelectionOverride = false;
38610 numOfSelected = 0;
38611 }
38612 slicerDataPoints.unshift({
38613 value: localizedSelectAllText,
38614 tooltip: localizedSelectAllText,
38615 identity: visuals.SelectionId.createWithMeasure(localizedSelectAllText),
38616 selected: !!isInvertedSelectionMode && numOfSelected === 0,
38617 isSelectAllDataPoint: true,
38618 count: undefined,
38619 });
38620 }
38621 var slicerData = {
38622 categorySourceName: category.source.displayName,
38623 slicerSettings: defaultSettings,
38624 slicerDataPoints: slicerDataPoints,
38625 hasSelectionOverride: hasSelectionOverride,
38626 defaultValue: analyzer.defaultValue,
38627 };
38628 return slicerData;
38629 }
38630 function createDefaultSettings(dataViewMetadata) {
38631 var defaultSettings = visuals.Slicer.DefaultStyleProperties();
38632 var objects = dataViewMetadata.objects;
38633 var forceSingleSelect = dataViewMetadata.columns && _.some(dataViewMetadata.columns, function (column) { return column.discourageAggregationAcrossGroups; });
38634 if (objects) {
38635 defaultSettings.general.outlineColor = powerbi.DataViewObjects.getFillColor(objects, visuals.slicerProps.general.outlineColor, defaultSettings.general.outlineColor);
38636 defaultSettings.general.outlineWeight = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.general.outlineWeight, defaultSettings.general.outlineWeight);
38637 defaultSettings.general.orientation = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.general.orientation, defaultSettings.general.orientation);
38638 defaultSettings.header.show = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.header.show, defaultSettings.header.show);
38639 defaultSettings.header.fontColor = powerbi.DataViewObjects.getFillColor(objects, visuals.slicerProps.header.fontColor, defaultSettings.header.fontColor);
38640 var headerBackground = powerbi.DataViewObjects.getFillColor(objects, visuals.slicerProps.header.background);
38641 if (headerBackground)
38642 defaultSettings.header.background = headerBackground;
38643 defaultSettings.header.outline = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.header.outline, defaultSettings.header.outline);
38644 defaultSettings.header.textSize = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.header.textSize, defaultSettings.header.textSize);
38645 defaultSettings.slicerText.color = powerbi.DataViewObjects.getFillColor(objects, visuals.slicerProps.items.fontColor, defaultSettings.slicerText.color);
38646 var textBackground = powerbi.DataViewObjects.getFillColor(objects, visuals.slicerProps.items.background);
38647 if (textBackground)
38648 defaultSettings.slicerText.background = textBackground;
38649 defaultSettings.slicerText.outline = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.items.outline, defaultSettings.slicerText.outline);
38650 defaultSettings.slicerText.textSize = powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.items.textSize, defaultSettings.slicerText.textSize);
38651 defaultSettings.selection.selectAllCheckboxEnabled = !forceSingleSelect && powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.selection.selectAllCheckboxEnabled, defaultSettings.selection.selectAllCheckboxEnabled);
38652 defaultSettings.selection.singleSelect = forceSingleSelect || powerbi.DataViewObjects.getValue(objects, visuals.slicerProps.selection.singleSelect, defaultSettings.selection.singleSelect);
38653 }
38654 return defaultSettings;
38655 }
38656 })(DataConversion = visuals.DataConversion || (visuals.DataConversion = {}));
38657 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
38658})(powerbi || (powerbi = {}));
38659/*
38660 * Power BI Visualizations
38661 *
38662 * Copyright (c) Microsoft Corporation
38663 * All rights reserved.
38664 * MIT License
38665 *
38666 * Permission is hereby granted, free of charge, to any person obtaining a copy
38667 * of this software and associated documentation files (the ""Software""), to deal
38668 * in the Software without restriction, including without limitation the rights
38669 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38670 * copies of the Software, and to permit persons to whom the Software is
38671 * furnished to do so, subject to the following conditions:
38672 *
38673 * The above copyright notice and this permission notice shall be included in
38674 * all copies or substantial portions of the Software.
38675 *
38676 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38677 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38678 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38679 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38680 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38681 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38682 * THE SOFTWARE.
38683 */
38684var powerbi;
38685(function (powerbi) {
38686 var shapes = powerbi.visuals.shapes;
38687 /**
38688 * Rectangle orientation. Rectangle orientation is used to define vertical or horizontal orientation
38689 * and starting/ending side of the rectangle.
38690 */
38691 (function (RectOrientation) {
38692 /** Rectangle with no specific orientation. */
38693 RectOrientation[RectOrientation["None"] = 0] = "None";
38694 /** Vertical rectangle with base at the bottom. */
38695 RectOrientation[RectOrientation["VerticalBottomTop"] = 1] = "VerticalBottomTop";
38696 /** Vertical rectangle with base at the top. */
38697 RectOrientation[RectOrientation["VerticalTopBottom"] = 2] = "VerticalTopBottom";
38698 /** Horizontal rectangle with base at the left. */
38699 RectOrientation[RectOrientation["HorizontalLeftRight"] = 3] = "HorizontalLeftRight";
38700 /** Horizontal rectangle with base at the right. */
38701 RectOrientation[RectOrientation["HorizontalRightLeft"] = 4] = "HorizontalRightLeft";
38702 })(powerbi.RectOrientation || (powerbi.RectOrientation = {}));
38703 var RectOrientation = powerbi.RectOrientation;
38704 /**
38705 * Defines if panel elements are allowed to be positioned
38706 * outside of the panel boundaries.
38707 */
38708 (function (OutsidePlacement) {
38709 /** Elements can be positioned outside of the panel. */
38710 OutsidePlacement[OutsidePlacement["Allowed"] = 0] = "Allowed";
38711 /** Elements can not be positioned outside of the panel. */
38712 OutsidePlacement[OutsidePlacement["Disallowed"] = 1] = "Disallowed";
38713 /** Elements can be partially outside of the panel. */
38714 OutsidePlacement[OutsidePlacement["Partial"] = 2] = "Partial";
38715 })(powerbi.OutsidePlacement || (powerbi.OutsidePlacement = {}));
38716 var OutsidePlacement = powerbi.OutsidePlacement;
38717 /**
38718 * Arranges label elements using the anchor point or rectangle. Collisions
38719 * between elements can be automatically detected and as a result elements
38720 * can be repositioned or get hidden.
38721 */
38722 var DataLabelManager = (function () {
38723 function DataLabelManager() {
38724 this.movingStep = 3;
38725 this.hideOverlapped = true;
38726 // The global settings for all labels.
38727 // They can be oweridden by each label we add into the panel, because contains same properties.
38728 this.defaultDataLabelSettings = {
38729 anchorMargin: DataLabelManager.DefaultAnchorMargin,
38730 anchorRectOrientation: RectOrientation.None,
38731 contentPosition: 128 /* BottomCenter */,
38732 outsidePlacement: OutsidePlacement.Disallowed,
38733 maximumMovingDistance: DataLabelManager.DefaultMaximumMovingDistance,
38734 minimumMovingDistance: DataLabelManager.DefaultMinimumMovingDistance,
38735 validContentPositions: 128 /* BottomCenter */,
38736 opacity: 1
38737 };
38738 }
38739 Object.defineProperty(DataLabelManager.prototype, "defaultSettings", {
38740 get: function () {
38741 return this.defaultDataLabelSettings;
38742 },
38743 enumerable: true,
38744 configurable: true
38745 });
38746 /** Arranges the lables position and visibility*/
38747 DataLabelManager.prototype.hideCollidedLabels = function (viewport, data, layout, addTransform) {
38748 if (addTransform === void 0) { addTransform = false; }
38749 // Split size into a grid
38750 var arrangeGrid = new DataLabelArrangeGrid(viewport, data, layout);
38751 var filteredData = [];
38752 var transform = { x: 0, y: 0 };
38753 if (addTransform) {
38754 transform.x = viewport.width / 2;
38755 transform.y = viewport.height / 2;
38756 }
38757 for (var i = 0, len = data.length; i < len; i++) {
38758 // Filter unwanted data points
38759 if (!layout.filter(data[i]))
38760 continue;
38761 // Set default values where properties values are undefined
38762 var info = this.getLabelInfo(data[i]);
38763 info.anchorPoint = {
38764 x: layout.labelLayout.x(data[i]) + transform.x,
38765 y: layout.labelLayout.y(data[i]) + transform.y,
38766 };
38767 var position = this.calculateContentPosition(info, info.contentPosition, data[i].size, info.anchorMargin);
38768 if (DataLabelManager.isValid(position) && !this.hasCollisions(arrangeGrid, info, position, viewport)) {
38769 data[i].labelX = position.left - transform.x;
38770 data[i].labelY = position.top - transform.y;
38771 // Keep track of all panel elements positions.
38772 arrangeGrid.add(info, position);
38773 // Save all data points to display
38774 filteredData.push(data[i]);
38775 }
38776 }
38777 return filteredData;
38778 };
38779 /**
38780 * Merges the label element info with the panel element info and returns correct label info.
38781 * @param source The label info.
38782 */
38783 DataLabelManager.prototype.getLabelInfo = function (source) {
38784 var settings = this.defaultDataLabelSettings;
38785 source.anchorMargin = source.anchorMargin !== undefined ? source.anchorMargin : settings.anchorMargin;
38786 source.anchorRectOrientation = source.anchorRectOrientation !== undefined ? source.anchorRectOrientation : settings.anchorRectOrientation;
38787 source.contentPosition = source.contentPosition !== undefined ? source.contentPosition : settings.contentPosition;
38788 source.maximumMovingDistance = source.maximumMovingDistance !== undefined ? source.maximumMovingDistance : settings.maximumMovingDistance;
38789 source.minimumMovingDistance = source.minimumMovingDistance !== undefined ? source.minimumMovingDistance : settings.minimumMovingDistance;
38790 source.outsidePlacement = source.outsidePlacement !== undefined ? source.outsidePlacement : settings.outsidePlacement;
38791 source.validContentPositions = source.validContentPositions !== undefined ? source.validContentPositions : settings.validContentPositions;
38792 source.opacity = source.opacity !== undefined ? source.opacity : settings.opacity;
38793 source.maximumMovingDistance += source.anchorMargin;
38794 return source;
38795 };
38796 /**
38797 * (Private) Calculates element position using anchor point..
38798 */
38799 DataLabelManager.prototype.calculateContentPositionFromPoint = function (anchorPoint, contentPosition, contentSize, offset) {
38800 var position = { x: 0, y: 0 };
38801 if (anchorPoint) {
38802 if (anchorPoint.x !== undefined && isFinite(anchorPoint.x)) {
38803 position.x = anchorPoint.x;
38804 switch (contentPosition) {
38805 // D3 positions the label in the middle by default.
38806 // The algorithem asumed the label was positioned in right so this is why we add/substract half width
38807 case 1 /* TopLeft */:
38808 case 8 /* MiddleLeft */:
38809 case 64 /* BottomLeft */:
38810 position.x -= contentSize.width / 2.0;
38811 break;
38812 case 4 /* TopRight */:
38813 case 32 /* MiddleRight */:
38814 case 256 /* BottomRight */:
38815 position.x += contentSize.width / 2.0;
38816 break;
38817 }
38818 }
38819 if (anchorPoint.y !== undefined && isFinite(anchorPoint.y)) {
38820 position.y = anchorPoint.y;
38821 switch (contentPosition) {
38822 case 8 /* MiddleLeft */:
38823 case 16 /* MiddleCenter */:
38824 case 32 /* MiddleRight */:
38825 position.y -= contentSize.height / 2.0;
38826 break;
38827 case 4 /* TopRight */:
38828 case 1 /* TopLeft */:
38829 case 2 /* TopCenter */:
38830 position.y -= contentSize.height;
38831 break;
38832 }
38833 }
38834 if (offset !== undefined && isFinite(offset)) {
38835 switch (contentPosition) {
38836 case 1 /* TopLeft */:
38837 position.x -= offset;
38838 position.y -= offset;
38839 break;
38840 case 8 /* MiddleLeft */:
38841 position.x -= offset;
38842 break;
38843 case 64 /* BottomLeft */:
38844 position.x -= offset;
38845 position.y += offset;
38846 break;
38847 case 2 /* TopCenter */:
38848 position.y -= offset;
38849 break;
38850 case 16 /* MiddleCenter */:
38851 // Offset is not applied
38852 break;
38853 case 128 /* BottomCenter */:
38854 position.y += offset;
38855 break;
38856 case 4 /* TopRight */:
38857 position.x += offset;
38858 position.y -= offset;
38859 break;
38860 case 32 /* MiddleRight */:
38861 position.x += offset;
38862 break;
38863 case 256 /* BottomRight */:
38864 position.x += offset;
38865 position.y += offset;
38866 break;
38867 default:
38868 debug.assertFail("Unsupported content position.");
38869 break;
38870 }
38871 }
38872 }
38873 return { left: position.x, top: position.y, width: contentSize.width, height: contentSize.height };
38874 };
38875 /** (Private) Calculates element position using anchor rect. */
38876 DataLabelManager.prototype.calculateContentPositionFromRect = function (anchorRect, anchorRectOrientation, contentPosition, contentSize, offset) {
38877 switch (contentPosition) {
38878 case 512 /* InsideCenter */:
38879 return this.handleInsideCenterPosition(anchorRectOrientation, contentSize, anchorRect, offset);
38880 case 2048 /* InsideEnd */:
38881 return this.handleInsideEndPosition(anchorRectOrientation, contentSize, anchorRect, offset);
38882 case 1024 /* InsideBase */:
38883 return this.handleInsideBasePosition(anchorRectOrientation, contentSize, anchorRect, offset);
38884 case 8192 /* OutsideEnd */:
38885 return this.handleOutsideEndPosition(anchorRectOrientation, contentSize, anchorRect, offset);
38886 case 4096 /* OutsideBase */:
38887 return this.handleOutsideBasePosition(anchorRectOrientation, contentSize, anchorRect, offset);
38888 default:
38889 debug.assertFail("Unsupported ContentPosition.");
38890 }
38891 return { left: 0, top: 0, width: -1, height: -1 };
38892 };
38893 /** (Private) Calculates element inside center position using anchor rect. */
38894 DataLabelManager.prototype.handleInsideCenterPosition = function (anchorRectOrientation, contentSize, anchorRect, offset) {
38895 switch (anchorRectOrientation) {
38896 case RectOrientation.VerticalBottomTop:
38897 case RectOrientation.VerticalTopBottom:
38898 return LocationConverter.middleVertical(contentSize, anchorRect, offset);
38899 case RectOrientation.HorizontalLeftRight:
38900 case RectOrientation.HorizontalRightLeft:
38901 default:
38902 return LocationConverter.middleHorizontal(contentSize, anchorRect, offset);
38903 }
38904 };
38905 /** (Private) Calculates element inside end position using anchor rect. */
38906 DataLabelManager.prototype.handleInsideEndPosition = function (anchorRectOrientation, contentSize, anchorRect, offset) {
38907 switch (anchorRectOrientation) {
38908 case RectOrientation.VerticalBottomTop:
38909 return LocationConverter.topInside(contentSize, anchorRect, offset);
38910 case RectOrientation.VerticalTopBottom:
38911 return LocationConverter.bottomInside(contentSize, anchorRect, offset);
38912 case RectOrientation.HorizontalRightLeft:
38913 return LocationConverter.leftInside(contentSize, anchorRect, offset);
38914 case RectOrientation.HorizontalLeftRight:
38915 default:
38916 return LocationConverter.rightInside(contentSize, anchorRect, offset);
38917 }
38918 };
38919 /** (Private) Calculates element inside base position using anchor rect. */
38920 DataLabelManager.prototype.handleInsideBasePosition = function (anchorRectOrientation, contentSize, anchorRect, offset) {
38921 switch (anchorRectOrientation) {
38922 case RectOrientation.VerticalBottomTop:
38923 return LocationConverter.bottomInside(contentSize, anchorRect, offset);
38924 case RectOrientation.VerticalTopBottom:
38925 return LocationConverter.topInside(contentSize, anchorRect, offset);
38926 case RectOrientation.HorizontalRightLeft:
38927 return LocationConverter.rightInside(contentSize, anchorRect, offset);
38928 case RectOrientation.HorizontalLeftRight:
38929 default:
38930 return LocationConverter.leftInside(contentSize, anchorRect, offset);
38931 }
38932 };
38933 /** (Private) Calculates element outside end position using anchor rect. */
38934 DataLabelManager.prototype.handleOutsideEndPosition = function (anchorRectOrientation, contentSize, anchorRect, offset) {
38935 switch (anchorRectOrientation) {
38936 case RectOrientation.VerticalBottomTop:
38937 return LocationConverter.topOutside(contentSize, anchorRect, offset);
38938 case RectOrientation.VerticalTopBottom:
38939 return LocationConverter.bottomOutside(contentSize, anchorRect, offset);
38940 case RectOrientation.HorizontalRightLeft:
38941 return LocationConverter.leftOutside(contentSize, anchorRect, offset);
38942 case RectOrientation.HorizontalLeftRight:
38943 default:
38944 return LocationConverter.rightOutside(contentSize, anchorRect, offset);
38945 }
38946 };
38947 /** (Private) Calculates element outside base position using anchor rect. */
38948 DataLabelManager.prototype.handleOutsideBasePosition = function (anchorRectOrientation, contentSize, anchorRect, offset) {
38949 switch (anchorRectOrientation) {
38950 case RectOrientation.VerticalBottomTop:
38951 return LocationConverter.bottomOutside(contentSize, anchorRect, offset);
38952 case RectOrientation.VerticalTopBottom:
38953 return LocationConverter.topOutside(contentSize, anchorRect, offset);
38954 case RectOrientation.HorizontalRightLeft:
38955 return LocationConverter.rightOutside(contentSize, anchorRect, offset);
38956 case RectOrientation.HorizontalLeftRight:
38957 default:
38958 return LocationConverter.leftOutside(contentSize, anchorRect, offset);
38959 }
38960 };
38961 /** (Private) Calculates element position. */
38962 DataLabelManager.prototype.calculateContentPosition = function (anchoredElementInfo, contentPosition, contentSize, offset) {
38963 if (contentPosition !== 2048 /* InsideEnd */ &&
38964 contentPosition !== 512 /* InsideCenter */ &&
38965 contentPosition !== 1024 /* InsideBase */ &&
38966 contentPosition !== 4096 /* OutsideBase */ &&
38967 contentPosition !== 8192 /* OutsideEnd */) {
38968 // Determine position using anchor point.
38969 return this.calculateContentPositionFromPoint(anchoredElementInfo.anchorPoint, contentPosition, contentSize, offset);
38970 }
38971 // Determine position using anchor rectangle.
38972 return this.calculateContentPositionFromRect(anchoredElementInfo.anchorRect, anchoredElementInfo.anchorRectOrientation, contentPosition, contentSize, offset);
38973 };
38974 /** (Private) Check for collisions. */
38975 DataLabelManager.prototype.hasCollisions = function (arrangeGrid, info, position, size) {
38976 var rect = shapes.Rect;
38977 if (arrangeGrid.hasConflict(position)) {
38978 return true;
38979 }
38980 // Since we divide the height by 2 we add it back to the top of the view port so labels won't be cut off
38981 var intersection = { left: 0, top: position.height / 2, width: size.width, height: size.height };
38982 intersection = rect.inflate(intersection, { left: DataLabelManager.InflateAmount, top: 0, right: DataLabelManager.InflateAmount, bottom: 0 });
38983 intersection = rect.intersect(intersection, position);
38984 if (rect.isEmpty(intersection))
38985 // Empty rectangle means there is a collision
38986 return true;
38987 var lessWithPrecision = powerbi.Double.lessWithPrecision;
38988 switch (info.outsidePlacement) {
38989 // D3 positions the label in the middle by default.
38990 // The algorithem asumed the label was positioned in right so this is why we devide by 2 or 4
38991 case OutsidePlacement.Disallowed:
38992 return lessWithPrecision(intersection.width, position.width) ||
38993 lessWithPrecision(intersection.height, position.height / 2);
38994 case OutsidePlacement.Partial:
38995 return lessWithPrecision(intersection.width, position.width / 2) ||
38996 lessWithPrecision(intersection.height, position.height / 4);
38997 }
38998 return false;
38999 };
39000 DataLabelManager.isValid = function (rect) {
39001 return !shapes.Rect.isEmpty(rect) && (rect.width > 0 && rect.height > 0);
39002 };
39003 DataLabelManager.DefaultAnchorMargin = 0; // For future use
39004 DataLabelManager.DefaultMaximumMovingDistance = 12;
39005 DataLabelManager.DefaultMinimumMovingDistance = 3;
39006 DataLabelManager.InflateAmount = 5;
39007 return DataLabelManager;
39008 }());
39009 powerbi.DataLabelManager = DataLabelManager;
39010 /**
39011 * Utility class to speed up the conflict detection by collecting the arranged items in the DataLabelsPanel.
39012 */
39013 var DataLabelArrangeGrid = (function () {
39014 /**
39015 * Creates new ArrangeGrid.
39016 * @param size The available size
39017 */
39018 function DataLabelArrangeGrid(size, elements, layout) {
39019 this.grid = [];
39020 if (size.width === 0 || size.height === 0) {
39021 this.cellSize = size;
39022 this.rowCount = this.colCount = 0;
39023 }
39024 var baseProperties = {
39025 fontFamily: powerbi.visuals.dataLabelUtils.LabelTextProperties.fontFamily,
39026 fontSize: powerbi.visuals.dataLabelUtils.LabelTextProperties.fontSize,
39027 fontWeight: powerbi.visuals.dataLabelUtils.LabelTextProperties.fontWeight,
39028 };
39029 //sets the cell size to be twice of the Max with and Max height of the elements
39030 this.cellSize = { width: 0, height: 0 };
39031 for (var i = 0, len = elements.length; i < len; i++) {
39032 var child = elements[i];
39033 // Fill label field
39034 child.labeltext = layout.labelText(child);
39035 var properties = powerbi.Prototype.inherit(baseProperties);
39036 properties.text = child.labeltext;
39037 properties.fontSize = (child.data) ? child.data.labelFontSize :
39038 child.labelFontSize ? child.labelFontSize : powerbi.visuals.dataLabelUtils.LabelTextProperties.fontSize;
39039 child.size = {
39040 width: powerbi.TextMeasurementService.measureSvgTextWidth(properties),
39041 height: powerbi.TextMeasurementService.estimateSvgTextHeight(properties),
39042 };
39043 var w = child.size.width * 2;
39044 var h = child.size.height * 2;
39045 if (w > this.cellSize.width)
39046 this.cellSize.width = w;
39047 if (h > this.cellSize.height)
39048 this.cellSize.height = h;
39049 }
39050 if (this.cellSize.width === 0)
39051 this.cellSize.width = size.width;
39052 if (this.cellSize.height === 0)
39053 this.cellSize.height = size.height;
39054 this.colCount = this.getGridRowColCount(this.cellSize.width, size.width, DataLabelArrangeGrid.ARRANGEGRID_MIN_COUNT, DataLabelArrangeGrid.ARRANGEGRID_MAX_COUNT);
39055 this.rowCount = this.getGridRowColCount(this.cellSize.height, size.height, DataLabelArrangeGrid.ARRANGEGRID_MIN_COUNT, DataLabelArrangeGrid.ARRANGEGRID_MAX_COUNT);
39056 this.cellSize.width = size.width / this.colCount;
39057 this.cellSize.height = size.height / this.rowCount;
39058 var grid = this.grid;
39059 for (var x = 0; x < this.colCount; x++) {
39060 grid[x] = [];
39061 for (var y = 0; y < this.rowCount; y++) {
39062 grid[x][y] = [];
39063 }
39064 }
39065 }
39066 /**
39067 * Register a new label element.
39068 * @param element The label element to register.
39069 * @param rect The label element position rectangle.
39070 */
39071 DataLabelArrangeGrid.prototype.add = function (element, rect) {
39072 var indexRect = this.getGridIndexRect(rect);
39073 var grid = this.grid;
39074 for (var x = indexRect.left; x < indexRect.right; x++) {
39075 for (var y = indexRect.top; y < indexRect.bottom; y++) {
39076 grid[x][y].push({ element: element, rect: rect });
39077 }
39078 }
39079 };
39080 /**
39081 * Checks for conflict of given rectangle in registered elements.
39082 * @param rect The rectengle to check.
39083 * @return True if conflict is detected.
39084 */
39085 DataLabelArrangeGrid.prototype.hasConflict = function (rect) {
39086 var indexRect = this.getGridIndexRect(rect);
39087 var grid = this.grid;
39088 var isIntersecting = shapes.Rect.isIntersecting;
39089 for (var x = indexRect.left; x < indexRect.right; x++) {
39090 for (var y = indexRect.top; y < indexRect.bottom; y++) {
39091 for (var z = 0; z < grid[x][y].length; z++) {
39092 var item = grid[x][y][z];
39093 if (isIntersecting(item.rect, rect)) {
39094 return true;
39095 }
39096 }
39097 }
39098 }
39099 return false;
39100 };
39101 /**
39102 * Calculates the number of rows or columns in a grid
39103 * @param step is the largest label size (width or height)
39104 * @param length is the grid size (width or height)
39105 * @param minCount is the minimum allowed size
39106 * @param maxCount is the maximum allowed size
39107 * @return the number of grid rows or columns
39108 */
39109 DataLabelArrangeGrid.prototype.getGridRowColCount = function (step, length, minCount, maxCount) {
39110 return Math.min(Math.max(Math.ceil(length / step), minCount), maxCount);
39111 };
39112 /**
39113 * Returns the grid index of a given recangle
39114 * @param rect The rectengle to check.
39115 * @return grid index as a thickness object.
39116 */
39117 DataLabelArrangeGrid.prototype.getGridIndexRect = function (rect) {
39118 var restrict = function (n, min, max) { return Math.min(Math.max(n, min), max); };
39119 return {
39120 left: restrict(Math.floor(rect.left / this.cellSize.width), 0, this.colCount),
39121 top: restrict(Math.floor(rect.top / this.cellSize.height), 0, this.rowCount),
39122 right: restrict(Math.ceil((rect.left + rect.width) / this.cellSize.width), 0, this.colCount),
39123 bottom: restrict(Math.ceil((rect.top + rect.height) / this.cellSize.height), 0, this.rowCount)
39124 };
39125 };
39126 DataLabelArrangeGrid.ARRANGEGRID_MIN_COUNT = 1;
39127 DataLabelArrangeGrid.ARRANGEGRID_MAX_COUNT = 100;
39128 return DataLabelArrangeGrid;
39129 }());
39130 powerbi.DataLabelArrangeGrid = DataLabelArrangeGrid;
39131 /**
39132 * (Private) Contains methods for calculating the top-left coordinate of rectangle based on content size and anchor rect.
39133 */
39134 var LocationConverter;
39135 (function (LocationConverter) {
39136 function topInside(size, rect, offset) {
39137 return {
39138 left: rect.left + rect.width / 2.0 - size.width / 2.0,
39139 top: rect.top + offset,
39140 width: size.width,
39141 height: size.height
39142 };
39143 }
39144 LocationConverter.topInside = topInside;
39145 function bottomInside(size, rect, offset) {
39146 return {
39147 left: rect.left + rect.width / 2.0 - size.width / 2.0,
39148 top: (rect.top + rect.height) - size.height - offset,
39149 width: size.width,
39150 height: size.height
39151 };
39152 }
39153 LocationConverter.bottomInside = bottomInside;
39154 function rightInside(size, rect, offset) {
39155 return {
39156 left: (rect.left + rect.width) - size.width - offset,
39157 top: rect.top + rect.height / 2.0 - size.height / 2.0,
39158 width: size.width,
39159 height: size.height
39160 };
39161 }
39162 LocationConverter.rightInside = rightInside;
39163 function leftInside(size, rect, offset) {
39164 return {
39165 left: rect.left + offset,
39166 top: rect.top + rect.height / 2.0 - size.height / 2.0,
39167 width: size.width,
39168 height: size.height
39169 };
39170 }
39171 LocationConverter.leftInside = leftInside;
39172 function topOutside(size, rect, offset) {
39173 return {
39174 left: rect.left + rect.width / 2.0 - size.width / 2.0,
39175 top: rect.top - size.height - offset,
39176 width: size.width,
39177 height: size.height
39178 };
39179 }
39180 LocationConverter.topOutside = topOutside;
39181 function bottomOutside(size, rect, offset) {
39182 return {
39183 left: rect.left + rect.width / 2.0 - size.width / 2.0,
39184 top: (rect.top + rect.height) + offset,
39185 width: size.width,
39186 height: size.height
39187 };
39188 }
39189 LocationConverter.bottomOutside = bottomOutside;
39190 function rightOutside(size, rect, offset) {
39191 return {
39192 left: (rect.left + rect.width) + offset,
39193 top: rect.top + rect.height / 2.0 - size.height / 2.0,
39194 width: size.width,
39195 height: size.height
39196 };
39197 }
39198 LocationConverter.rightOutside = rightOutside;
39199 function leftOutside(size, rect, offset) {
39200 return {
39201 left: rect.left - size.width - offset,
39202 top: rect.top + rect.height / 2.0 - size.height / 2.0,
39203 width: size.width,
39204 height: size.height
39205 };
39206 }
39207 LocationConverter.leftOutside = leftOutside;
39208 function middleHorizontal(size, rect, offset) {
39209 return {
39210 left: rect.left + rect.width / 2.0 - size.width / 2.0 + offset,
39211 top: rect.top + rect.height / 2.0 - size.height / 2.0,
39212 width: size.width,
39213 height: size.height
39214 };
39215 }
39216 LocationConverter.middleHorizontal = middleHorizontal;
39217 function middleVertical(size, rect, offset) {
39218 return {
39219 left: rect.left + rect.width / 2.0 - size.width / 2.0,
39220 top: rect.top + rect.height / 2.0 - size.height / 2.0 + offset,
39221 width: size.width,
39222 height: size.height
39223 };
39224 }
39225 LocationConverter.middleVertical = middleVertical;
39226 })(LocationConverter || (LocationConverter = {}));
39227})(powerbi || (powerbi = {}));
39228/*
39229 * Power BI Visualizations
39230 *
39231 * Copyright (c) Microsoft Corporation
39232 * All rights reserved.
39233 * MIT License
39234 *
39235 * Permission is hereby granted, free of charge, to any person obtaining a copy
39236 * of this software and associated documentation files (the ""Software""), to deal
39237 * in the Software without restriction, including without limitation the rights
39238 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39239 * copies of the Software, and to permit persons to whom the Software is
39240 * furnished to do so, subject to the following conditions:
39241 *
39242 * The above copyright notice and this permission notice shall be included in
39243 * all copies or substantial portions of the Software.
39244 *
39245 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39246 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39247 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39248 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39249 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39250 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39251 * THE SOFTWARE.
39252 */
39253var powerbi;
39254(function (powerbi) {
39255 var shapes = powerbi.visuals.shapes;
39256 var Rect = powerbi.visuals.shapes.Rect;
39257 var NewDataLabelUtils = powerbi.visuals.NewDataLabelUtils;
39258 var LabelArrangeGrid = (function () {
39259 function LabelArrangeGrid(labelDataPointsGroups, viewport) {
39260 this.viewport = viewport;
39261 var maxLabelWidth = 0;
39262 var maxLabelHeight = 0;
39263 for (var _i = 0, labelDataPointsGroups_1 = labelDataPointsGroups; _i < labelDataPointsGroups_1.length; _i++) {
39264 var labelDataPointsGroup = labelDataPointsGroups_1[_i];
39265 for (var _a = 0, _b = labelDataPointsGroup.labelDataPoints; _a < _b.length; _a++) {
39266 var labelDataPoint = _b[_a];
39267 if (labelDataPoint.isPreferred) {
39268 var dataLabelSize = labelDataPoint.labelSize;
39269 if (dataLabelSize.width > maxLabelWidth) {
39270 maxLabelWidth = dataLabelSize.width;
39271 }
39272 if (dataLabelSize.height > maxLabelHeight) {
39273 maxLabelHeight = dataLabelSize.height;
39274 }
39275 }
39276 }
39277 }
39278 if (maxLabelWidth === 0) {
39279 maxLabelWidth = viewport.width;
39280 }
39281 if (maxLabelHeight === 0) {
39282 maxLabelHeight = viewport.height;
39283 }
39284 var cellSize = this.cellSize = { width: maxLabelWidth * LabelArrangeGrid.cellSizeMultiplier, height: maxLabelHeight * LabelArrangeGrid.cellSizeMultiplier };
39285 this.columnCount = LabelArrangeGrid.getCellCount(cellSize.width, viewport.width, 1, 100);
39286 this.rowCount = LabelArrangeGrid.getCellCount(cellSize.height, viewport.height, 1, 100);
39287 var grid = [];
39288 for (var i = 0, ilen = this.columnCount; i < ilen; i++) {
39289 grid[i] = [];
39290 for (var j = 0, jlen = this.rowCount; j < jlen; j++) {
39291 grid[i][j] = [];
39292 }
39293 }
39294 this.grid = grid;
39295 }
39296 /**
39297 * Add a rectangle to check collision against
39298 */
39299 LabelArrangeGrid.prototype.add = function (rect) {
39300 var containingIndexRect = this.getContainingGridSubsection(rect);
39301 for (var x = containingIndexRect.xMin; x < containingIndexRect.xMax; x++) {
39302 for (var y = containingIndexRect.yMin; y < containingIndexRect.yMax; y++) {
39303 this.grid[x][y].push(rect);
39304 }
39305 }
39306 };
39307 /**
39308 * Check whether the rect conflicts with the grid, either bleeding outside the
39309 * viewport or colliding with another rect added to the grid.
39310 */
39311 LabelArrangeGrid.prototype.hasConflict = function (rect) {
39312 if (!this.isWithinGridViewport(rect)) {
39313 return true;
39314 }
39315 return this.hasCollision(rect);
39316 };
39317 /**
39318 * Attempt to position the given rect within the viewport. Returns
39319 * the adjusted rectangle or null if the rectangle couldn't fit,
39320 * conflicts with the viewport, or is too far outside the viewport
39321 */
39322 LabelArrangeGrid.prototype.tryPositionInViewport = function (rect) {
39323 // If it's too far outside the viewport, return null
39324 if (!this.isCloseToGridViewport(rect)) {
39325 return;
39326 }
39327 if (!this.isWithinGridViewport(rect)) {
39328 rect = this.tryMoveInsideViewport(rect);
39329 }
39330 if (rect && !this.hasCollision(rect)) {
39331 return rect;
39332 }
39333 };
39334 /**
39335 * Checks for a collision between the given rect and others in the grid.
39336 * Returns true if there is a collision.
39337 */
39338 LabelArrangeGrid.prototype.hasCollision = function (rect) {
39339 var containingIndexRect = this.getContainingGridSubsection(rect);
39340 var grid = this.grid;
39341 var isIntersecting = shapes.Rect.isIntersecting;
39342 for (var x = containingIndexRect.xMin; x < containingIndexRect.xMax; x++) {
39343 for (var y = containingIndexRect.yMin; y < containingIndexRect.yMax; y++) {
39344 for (var _i = 0, _a = grid[x][y]; _i < _a.length; _i++) {
39345 var currentGridRect = _a[_i];
39346 if (isIntersecting(currentGridRect, rect)) {
39347 return true;
39348 }
39349 }
39350 }
39351 }
39352 return false;
39353 };
39354 /**
39355 * Check to see if the given rect is inside the grid's viewport
39356 */
39357 LabelArrangeGrid.prototype.isWithinGridViewport = function (rect) {
39358 return rect.left >= 0 &&
39359 rect.top >= 0 &&
39360 rect.left + rect.width <= this.viewport.width &&
39361 rect.top + rect.height <= this.viewport.height;
39362 };
39363 /**
39364 * Checks to see if the rect is close enough to the viewport to be moved inside.
39365 * "Close" here is determined by the distance between the edge of the viewport
39366 * and the closest edge of the rect; if that distance is less than the appropriate
39367 * dimension of the rect, we will reposition the rect.
39368 */
39369 LabelArrangeGrid.prototype.isCloseToGridViewport = function (rect) {
39370 return rect.left + rect.width >= 0 - rect.width &&
39371 rect.top + rect.height >= -rect.height &&
39372 rect.left <= this.viewport.width + rect.width &&
39373 rect.top <= this.viewport.height + rect.height;
39374 };
39375 /**
39376 * Attempt to move the rect inside the grid's viewport. Returns the resulting
39377 * rectangle with the same width/height adjusted to be inside the viewport or
39378 * null if it couldn't fit regardless.
39379 */
39380 LabelArrangeGrid.prototype.tryMoveInsideViewport = function (rect) {
39381 var result = Rect.clone(rect);
39382 var viewport = this.viewport;
39383 // Return null if it's too big to fit regardless of positioning
39384 if (rect.width > viewport.width || rect.height > viewport.height) {
39385 return;
39386 }
39387 // Only one movement should be made in each direction, because we are only moving it inside enough for it to fit; there should be no overshooting.
39388 // Outside to the left
39389 if (rect.left < 0) {
39390 result.left = 0;
39391 }
39392 else if (rect.left + rect.width > viewport.width) {
39393 result.left -= (rect.left + rect.width) - viewport.width;
39394 }
39395 // Outside above
39396 if (rect.top < 0) {
39397 result.top = 0;
39398 }
39399 else if (rect.top + rect.height > viewport.height) {
39400 result.top -= (rect.top + rect.height) - viewport.height;
39401 }
39402 return result;
39403 };
39404 LabelArrangeGrid.prototype.getContainingGridSubsection = function (rect) {
39405 return {
39406 xMin: LabelArrangeGrid.bound(Math.floor(rect.left / this.cellSize.width), 0, this.columnCount),
39407 xMax: LabelArrangeGrid.bound(Math.ceil((rect.left + rect.width) / this.cellSize.width), 0, this.columnCount),
39408 yMin: LabelArrangeGrid.bound(Math.floor(rect.top / this.cellSize.height), 0, this.rowCount),
39409 yMax: LabelArrangeGrid.bound(Math.ceil((rect.top + rect.height) / this.cellSize.height), 0, this.rowCount),
39410 };
39411 };
39412 LabelArrangeGrid.getCellCount = function (step, length, minCount, maxCount) {
39413 return LabelArrangeGrid.bound(Math.ceil(length / step), minCount, maxCount);
39414 };
39415 LabelArrangeGrid.bound = function (value, min, max) {
39416 return Math.max(Math.min(value, max), min);
39417 };
39418 /**
39419 * A multiplier applied to the largest width height to attempt to balance # of
39420 * labels in each cell and number of cells each label belongs to
39421 */
39422 LabelArrangeGrid.cellSizeMultiplier = 2;
39423 return LabelArrangeGrid;
39424 }());
39425 powerbi.LabelArrangeGrid = LabelArrangeGrid;
39426 var LabelLayout = (function () {
39427 function LabelLayout(options) {
39428 this.startingOffset = options.startingOffset;
39429 this.maximumOffset = options.maximumOffset;
39430 if (options.offsetIterationDelta != null) {
39431 debug.assert(options.offsetIterationDelta > 0, "label offset delta must be greater than 0");
39432 this.offsetIterationDelta = options.offsetIterationDelta;
39433 }
39434 else {
39435 this.offsetIterationDelta = LabelLayout.defaultOffsetIterationDelta;
39436 }
39437 if (options.horizontalPadding != null) {
39438 this.horizontalPadding = options.horizontalPadding;
39439 }
39440 else {
39441 this.horizontalPadding = LabelLayout.defaultHorizontalPadding;
39442 }
39443 if (options.verticalPadding != null) {
39444 this.verticalPadding = options.verticalPadding;
39445 }
39446 else {
39447 this.verticalPadding = LabelLayout.defaultVerticalPadding;
39448 }
39449 this.allowLeaderLines = !!options.allowLeaderLines;
39450 this.attemptToMoveLabelsIntoViewport = !!options.attemptToMoveLabelsIntoViewport;
39451 }
39452 /**
39453 * Arrange takes a set of data labels and lays them out in order, assuming that
39454 * the given array has already been sorted with the most preferred labels at the
39455 * front, taking into considiration a maximum number of labels that are alowed
39456 * to display.
39457 *
39458 * Details:
39459 * - We iterate over offsets from the target position, increasing from 0 while
39460 * verifiying the maximum number of labels to display hasn't been reached
39461 * - For each offset, we iterate over each data label
39462 * - For each data label, we iterate over each position that is valid for
39463 * both the specific label and this layout
39464 * - When a valid position is found, we position the label there and no longer
39465 * reposition it.
39466 * - This prioritizes the earlier labels to be positioned closer to their
39467 * target points in the position they prefer.
39468 * - This prioritizes putting data labels close to a valid position over
39469 * placing them at their preferred position (it will place it at a less
39470 * preferred position if it will be a smaller offset)
39471 */
39472 LabelLayout.prototype.layout = function (labelDataPointsGroups, viewport) {
39473 // Clear data labels for a new layout
39474 for (var _i = 0, labelDataPointsGroups_2 = labelDataPointsGroups; _i < labelDataPointsGroups_2.length; _i++) {
39475 var labelDataPointsGroup = labelDataPointsGroups_2[_i];
39476 for (var _a = 0, _b = labelDataPointsGroup.labelDataPoints; _a < _b.length; _a++) {
39477 var labelPoint = _b[_a];
39478 labelPoint.hasBeenRendered = false;
39479 if (labelPoint.hasBackground) {
39480 labelPoint.labelSize = {
39481 width: labelPoint.textSize.width + 2 * NewDataLabelUtils.horizontalLabelBackgroundPadding,
39482 height: labelPoint.textSize.height + 2 * NewDataLabelUtils.verticalLabelBackgroundPadding,
39483 };
39484 }
39485 else {
39486 labelPoint.labelSize = labelPoint.textSize;
39487 }
39488 }
39489 }
39490 var resultingDataLabels = [];
39491 var grid = new LabelArrangeGrid(labelDataPointsGroups, viewport);
39492 // Iterates on every series
39493 for (var _c = 0, labelDataPointsGroups_3 = labelDataPointsGroups; _c < labelDataPointsGroups_3.length; _c++) {
39494 var labelDataPointsGroup = labelDataPointsGroups_3[_c];
39495 var maxLabelsToRender = labelDataPointsGroup.maxNumberOfLabels;
39496 // NOTE: we create a copy and modify the copy to keep track of preferred vs. non-preferred labels.
39497 var labelDataPoints = _.clone(labelDataPointsGroup.labelDataPoints);
39498 var preferredLabels = [];
39499 // Exclude preferred labels
39500 for (var j = labelDataPoints.length - 1, localMax = maxLabelsToRender; j >= 0 && localMax > 0; j--) {
39501 var labelPoint = labelDataPoints[j];
39502 if (labelPoint.isPreferred) {
39503 preferredLabels.unshift(labelDataPoints.splice(j, 1)[0]);
39504 localMax--;
39505 }
39506 }
39507 // First iterate all the preferred labels
39508 if (preferredLabels.length > 0) {
39509 var positionedLabels = this.positionDataLabels(preferredLabels, viewport, grid, maxLabelsToRender);
39510 maxLabelsToRender -= positionedLabels.length;
39511 resultingDataLabels = resultingDataLabels.concat(positionedLabels);
39512 }
39513 // While there are invisible not preferred labels and label distance is less than the max
39514 // allowed distance
39515 if (labelDataPoints.length > 0) {
39516 var labels = this.positionDataLabels(labelDataPoints, viewport, grid, maxLabelsToRender);
39517 resultingDataLabels = resultingDataLabels.concat(labels);
39518 }
39519 }
39520 return resultingDataLabels;
39521 };
39522 LabelLayout.prototype.positionDataLabels = function (labelDataPoints, viewport, grid, maxLabelsToRender) {
39523 var resultingDataLabels = [];
39524 var offsetDelta = this.offsetIterationDelta;
39525 var currentOffset = this.startingOffset;
39526 var currentCenteredOffset = 0;
39527 var drawLeaderLinesOnIteration;
39528 while (currentOffset <= this.maximumOffset && maxLabelsToRender > 0) {
39529 drawLeaderLinesOnIteration = this.allowLeaderLines && currentOffset > this.startingOffset;
39530 for (var _i = 0, labelDataPoints_2 = labelDataPoints; _i < labelDataPoints_2.length; _i++) {
39531 var labelPoint = labelDataPoints_2[_i];
39532 // Check if maximum number of labels to display has been reached
39533 if (maxLabelsToRender === 0)
39534 break;
39535 if (labelPoint.hasBeenRendered) {
39536 continue;
39537 }
39538 var dataLabel = void 0;
39539 if (labelPoint.parentType === 1 /* Rectangle */) {
39540 dataLabel = this.tryPositionForRectPositions(labelPoint, grid, currentOffset, currentCenteredOffset);
39541 }
39542 else {
39543 dataLabel = this.tryPositionForPointPositions(labelPoint, grid, currentOffset, drawLeaderLinesOnIteration);
39544 }
39545 if (dataLabel) {
39546 resultingDataLabels.push(dataLabel);
39547 maxLabelsToRender--;
39548 }
39549 }
39550 currentOffset += offsetDelta;
39551 currentCenteredOffset += offsetDelta;
39552 }
39553 return resultingDataLabels;
39554 };
39555 LabelLayout.prototype.tryPositionForRectPositions = function (labelPoint, grid, currentLabelOffset, currentCenteredLabelOffset) {
39556 var _this = this;
39557 // Function declared and reused to reduce code duplication
39558 var tryPosition = function (position, adjustForViewport) {
39559 var isPositionInside = position & 7 /* InsideAll */;
39560 if (isPositionInside && !DataLabelRectPositioner.canFitWithinParent(labelPoint, _this.horizontalPadding, _this.verticalPadding)) {
39561 return;
39562 }
39563 var resultingBoundingBox = LabelLayout.tryPositionRect(grid, position, labelPoint, currentLabelOffset, currentCenteredLabelOffset, adjustForViewport);
39564 if (resultingBoundingBox) {
39565 if (isPositionInside && !DataLabelRectPositioner.isLabelWithinParent(resultingBoundingBox, labelPoint, _this.horizontalPadding, _this.verticalPadding)) {
39566 return;
39567 }
39568 grid.add(resultingBoundingBox);
39569 labelPoint.hasBeenRendered = true;
39570 return {
39571 boundingBox: resultingBoundingBox,
39572 text: labelPoint.text,
39573 tooltip: labelPoint.tooltip,
39574 isVisible: true,
39575 fill: isPositionInside ? labelPoint.insideFill : labelPoint.outsideFill,
39576 identity: labelPoint.identity,
39577 key: labelPoint.key,
39578 fontSize: labelPoint.fontSize,
39579 selected: false,
39580 hasBackground: !!labelPoint.hasBackground,
39581 };
39582 }
39583 };
39584 // Iterate over all positions that are valid for the data point
39585 for (var _i = 0, _a = labelPoint.parentShape.validPositions; _i < _a.length; _i++) {
39586 var position = _a[_i];
39587 var label = tryPosition(position, false /* adjustForViewport */);
39588 if (label)
39589 return label;
39590 }
39591 // If no position has been found and the option is enabled, try any outside positions while moving the label inside the viewport
39592 if (this.attemptToMoveLabelsIntoViewport) {
39593 for (var _b = 0, _c = labelPoint.parentShape.validPositions; _b < _c.length; _b++) {
39594 var position = _c[_b];
39595 var label = tryPosition(position, true /* adjustForViewport */);
39596 if (label)
39597 return label;
39598 }
39599 }
39600 return null;
39601 };
39602 /**
39603 * Tests a particular position/offset combination for the given data label.
39604 * If the label can be placed, returns the resulting bounding box for the data
39605 * label. If not, returns null.
39606 */
39607 LabelLayout.tryPositionRect = function (grid, position, labelDataPoint, offset, centerOffset, adjustForViewport) {
39608 var offsetForPosition = offset;
39609 if (position & 1 /* InsideCenter */) {
39610 offsetForPosition = centerOffset;
39611 }
39612 var labelRect = DataLabelRectPositioner.getLabelRect(labelDataPoint, position, offsetForPosition);
39613 if (position !== 1 /* InsideCenter */ || labelDataPoint.parentShape.orientation === 0 /* None */) {
39614 if (!grid.hasConflict(labelRect)) {
39615 return labelRect;
39616 }
39617 if (adjustForViewport) {
39618 return grid.tryPositionInViewport(labelRect);
39619 }
39620 }
39621 else {
39622 // If the position is centered, attempt to offset in both a positive and negative direction
39623 if (!grid.hasConflict(labelRect)) {
39624 return labelRect;
39625 }
39626 labelRect = DataLabelRectPositioner.getLabelRect(labelDataPoint, position, -offsetForPosition);
39627 if (!grid.hasConflict(labelRect)) {
39628 return labelRect;
39629 }
39630 }
39631 return null;
39632 };
39633 LabelLayout.prototype.tryPositionForPointPositions = function (labelPoint, grid, currentLabelOffset, drawLeaderLines) {
39634 // Function declared and reused to reduce code duplication
39635 var tryPosition = function (position, parentShape, adjustForViewport) {
39636 var resultingBoundingBox = LabelLayout.tryPositionPoint(grid, position, labelPoint, currentLabelOffset, adjustForViewport);
39637 if (resultingBoundingBox) {
39638 grid.add(resultingBoundingBox);
39639 labelPoint.hasBeenRendered = true;
39640 return {
39641 boundingBox: resultingBoundingBox,
39642 text: labelPoint.text,
39643 tooltip: labelPoint.tooltip,
39644 isVisible: true,
39645 fill: position === 256 /* Center */ ? labelPoint.insideFill : labelPoint.outsideFill,
39646 isInsideParent: position === 256 /* Center */,
39647 identity: labelPoint.identity,
39648 key: labelPoint.key,
39649 fontSize: labelPoint.fontSize,
39650 selected: false,
39651 leaderLinePoints: drawLeaderLines ? DataLabelPointPositioner.getLabelLeaderLineEndingPoint(resultingBoundingBox, position, parentShape) : null,
39652 hasBackground: !!labelPoint.hasBackground,
39653 };
39654 }
39655 };
39656 // Iterate over all positions that are valid for the data point
39657 var parentShape = labelPoint.parentShape;
39658 var validPositions = parentShape.validPositions;
39659 for (var _i = 0, validPositions_1 = validPositions; _i < validPositions_1.length; _i++) {
39660 var position = validPositions_1[_i];
39661 var label = tryPosition(position, parentShape, false /* adjustForViewport */);
39662 if (label)
39663 return label;
39664 }
39665 // Attempt to position at the most preferred position by simply moving it inside the viewport
39666 if (this.attemptToMoveLabelsIntoViewport && !_.isEmpty(validPositions)) {
39667 var label = tryPosition(validPositions[0], parentShape, true /* adjustForViewport */);
39668 if (label)
39669 return label;
39670 }
39671 return null;
39672 };
39673 LabelLayout.tryPositionPoint = function (grid, position, labelDataPoint, offset, adjustForViewport) {
39674 var labelRect = DataLabelPointPositioner.getLabelRect(labelDataPoint.labelSize, labelDataPoint.parentShape, position, offset);
39675 if (!grid.hasConflict(labelRect)) {
39676 return labelRect;
39677 }
39678 if (adjustForViewport) {
39679 return grid.tryPositionInViewport(labelRect);
39680 }
39681 return null;
39682 };
39683 // Default values
39684 LabelLayout.defaultOffsetIterationDelta = 2;
39685 LabelLayout.defaultHorizontalPadding = 2;
39686 LabelLayout.defaultVerticalPadding = 2;
39687 return LabelLayout;
39688 }());
39689 powerbi.LabelLayout = LabelLayout;
39690 /**
39691 * (Private) Contains methods for calculating the bounding box of a data label
39692 */
39693 var DataLabelRectPositioner;
39694 (function (DataLabelRectPositioner) {
39695 function getLabelRect(labelDataPoint, position, offset) {
39696 var parentRect = labelDataPoint.parentShape;
39697 if (parentRect != null) {
39698 // Each combination of position and orientation results in a different actual positioning, which is then called.
39699 switch (position) {
39700 case 1 /* InsideCenter */:
39701 switch (parentRect.orientation) {
39702 case 1 /* VerticalBottomBased */:
39703 case 2 /* VerticalTopBased */:
39704 return DataLabelRectPositioner.middleVertical(labelDataPoint.labelSize, parentRect.rect, offset);
39705 case 3 /* HorizontalLeftBased */:
39706 case 4 /* HorizontalRightBased */:
39707 return DataLabelRectPositioner.middleHorizontal(labelDataPoint.labelSize, parentRect.rect, offset);
39708 case 0 /* None */:
39709 }
39710 case 2 /* InsideBase */:
39711 switch (parentRect.orientation) {
39712 case 1 /* VerticalBottomBased */:
39713 return DataLabelRectPositioner.bottomInside(labelDataPoint.labelSize, parentRect.rect, offset);
39714 case 2 /* VerticalTopBased */:
39715 return DataLabelRectPositioner.topInside(labelDataPoint.labelSize, parentRect.rect, offset);
39716 case 3 /* HorizontalLeftBased */:
39717 return DataLabelRectPositioner.leftInside(labelDataPoint.labelSize, parentRect.rect, offset);
39718 case 4 /* HorizontalRightBased */:
39719 return DataLabelRectPositioner.rightInside(labelDataPoint.labelSize, parentRect.rect, offset);
39720 case 0 /* None */:
39721 }
39722 case 4 /* InsideEnd */:
39723 switch (parentRect.orientation) {
39724 case 1 /* VerticalBottomBased */:
39725 return DataLabelRectPositioner.topInside(labelDataPoint.labelSize, parentRect.rect, offset);
39726 case 2 /* VerticalTopBased */:
39727 return DataLabelRectPositioner.bottomInside(labelDataPoint.labelSize, parentRect.rect, offset);
39728 case 3 /* HorizontalLeftBased */:
39729 return DataLabelRectPositioner.rightInside(labelDataPoint.labelSize, parentRect.rect, offset);
39730 case 4 /* HorizontalRightBased */:
39731 return DataLabelRectPositioner.leftInside(labelDataPoint.labelSize, parentRect.rect, offset);
39732 case 0 /* None */:
39733 }
39734 case 8 /* OutsideBase */:
39735 switch (parentRect.orientation) {
39736 case 1 /* VerticalBottomBased */:
39737 return DataLabelRectPositioner.bottomOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39738 case 2 /* VerticalTopBased */:
39739 return DataLabelRectPositioner.topOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39740 case 3 /* HorizontalLeftBased */:
39741 return DataLabelRectPositioner.leftOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39742 case 4 /* HorizontalRightBased */:
39743 return DataLabelRectPositioner.rightOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39744 case 0 /* None */:
39745 }
39746 case 16 /* OutsideEnd */:
39747 switch (parentRect.orientation) {
39748 case 1 /* VerticalBottomBased */:
39749 return DataLabelRectPositioner.topOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39750 case 2 /* VerticalTopBased */:
39751 return DataLabelRectPositioner.bottomOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39752 case 3 /* HorizontalLeftBased */:
39753 return DataLabelRectPositioner.rightOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39754 case 4 /* HorizontalRightBased */:
39755 return DataLabelRectPositioner.leftOutside(labelDataPoint.labelSize, parentRect.rect, offset);
39756 case 0 /* None */:
39757 }
39758 default:
39759 debug.assertFail("Unsupported label position");
39760 }
39761 }
39762 else {
39763 }
39764 return null;
39765 }
39766 DataLabelRectPositioner.getLabelRect = getLabelRect;
39767 function canFitWithinParent(labelDataPoint, horizontalPadding, verticalPadding) {
39768 return (labelDataPoint.labelSize.width + 2 * horizontalPadding < labelDataPoint.parentShape.rect.width) ||
39769 (labelDataPoint.labelSize.height + 2 * verticalPadding < labelDataPoint.parentShape.rect.height);
39770 }
39771 DataLabelRectPositioner.canFitWithinParent = canFitWithinParent;
39772 function isLabelWithinParent(labelRect, labelPoint, horizontalPadding, verticalPadding) {
39773 var parentRect = labelPoint.parentShape.rect;
39774 var labelRectWithPadding = shapes.Rect.inflate(labelRect, { left: horizontalPadding, right: horizontalPadding, top: verticalPadding, bottom: verticalPadding });
39775 return shapes.Rect.containsPoint(parentRect, {
39776 x: labelRectWithPadding.left,
39777 y: labelRectWithPadding.top,
39778 }) && shapes.Rect.containsPoint(parentRect, {
39779 x: labelRectWithPadding.left + labelRectWithPadding.width,
39780 y: labelRectWithPadding.top + labelRectWithPadding.height,
39781 });
39782 }
39783 DataLabelRectPositioner.isLabelWithinParent = isLabelWithinParent;
39784 function topInside(labelSize, parentRect, offset) {
39785 return {
39786 left: parentRect.left + parentRect.width / 2.0 - labelSize.width / 2.0,
39787 top: parentRect.top + offset,
39788 width: labelSize.width,
39789 height: labelSize.height
39790 };
39791 }
39792 DataLabelRectPositioner.topInside = topInside;
39793 function bottomInside(labelSize, parentRect, offset) {
39794 return {
39795 left: parentRect.left + parentRect.width / 2.0 - labelSize.width / 2.0,
39796 top: (parentRect.top + parentRect.height) - offset - labelSize.height,
39797 width: labelSize.width,
39798 height: labelSize.height
39799 };
39800 }
39801 DataLabelRectPositioner.bottomInside = bottomInside;
39802 function rightInside(labelSize, parentRect, offset) {
39803 return {
39804 left: (parentRect.left + parentRect.width) - labelSize.width - offset,
39805 top: parentRect.top + parentRect.height / 2.0 - labelSize.height / 2.0,
39806 width: labelSize.width,
39807 height: labelSize.height
39808 };
39809 }
39810 DataLabelRectPositioner.rightInside = rightInside;
39811 function leftInside(labelSize, parentRect, offset) {
39812 return {
39813 left: parentRect.left + offset,
39814 top: parentRect.top + parentRect.height / 2.0 - labelSize.height / 2.0,
39815 width: labelSize.width,
39816 height: labelSize.height
39817 };
39818 }
39819 DataLabelRectPositioner.leftInside = leftInside;
39820 function topOutside(labelSize, parentRect, offset) {
39821 return {
39822 left: parentRect.left + parentRect.width / 2.0 - labelSize.width / 2.0,
39823 top: parentRect.top - labelSize.height - offset,
39824 width: labelSize.width,
39825 height: labelSize.height
39826 };
39827 }
39828 DataLabelRectPositioner.topOutside = topOutside;
39829 function bottomOutside(labelSize, parentRect, offset) {
39830 return {
39831 left: parentRect.left + parentRect.width / 2.0 - labelSize.width / 2.0,
39832 top: (parentRect.top + parentRect.height) + offset,
39833 width: labelSize.width,
39834 height: labelSize.height
39835 };
39836 }
39837 DataLabelRectPositioner.bottomOutside = bottomOutside;
39838 function rightOutside(labelSize, parentRect, offset) {
39839 return {
39840 left: (parentRect.left + parentRect.width) + offset,
39841 top: parentRect.top + parentRect.height / 2.0 - labelSize.height / 2.0,
39842 width: labelSize.width,
39843 height: labelSize.height
39844 };
39845 }
39846 DataLabelRectPositioner.rightOutside = rightOutside;
39847 function leftOutside(labelSize, parentRect, offset) {
39848 return {
39849 left: parentRect.left - labelSize.width - offset,
39850 top: parentRect.top + parentRect.height / 2.0 - labelSize.height / 2.0,
39851 width: labelSize.width,
39852 height: labelSize.height
39853 };
39854 }
39855 DataLabelRectPositioner.leftOutside = leftOutside;
39856 function middleHorizontal(labelSize, parentRect, offset) {
39857 return {
39858 left: parentRect.left + parentRect.width / 2.0 - labelSize.width / 2.0 + offset,
39859 top: parentRect.top + parentRect.height / 2.0 - labelSize.height / 2.0,
39860 width: labelSize.width,
39861 height: labelSize.height
39862 };
39863 }
39864 DataLabelRectPositioner.middleHorizontal = middleHorizontal;
39865 function middleVertical(labelSize, parentRect, offset) {
39866 return {
39867 left: parentRect.left + parentRect.width / 2.0 - labelSize.width / 2.0,
39868 top: parentRect.top + parentRect.height / 2.0 - labelSize.height / 2.0 + offset,
39869 width: labelSize.width,
39870 height: labelSize.height
39871 };
39872 }
39873 DataLabelRectPositioner.middleVertical = middleVertical;
39874 })(DataLabelRectPositioner = powerbi.DataLabelRectPositioner || (powerbi.DataLabelRectPositioner = {}));
39875 var DataLabelPointPositioner;
39876 (function (DataLabelPointPositioner) {
39877 DataLabelPointPositioner.cos45 = Math.cos(45);
39878 DataLabelPointPositioner.sin45 = Math.sin(45);
39879 function getLabelRect(labelSize, parentPoint, position, offset) {
39880 switch (position) {
39881 case 1 /* Above */: {
39882 return DataLabelPointPositioner.above(labelSize, parentPoint.point, parentPoint.radius + offset);
39883 }
39884 case 2 /* Below */: {
39885 return DataLabelPointPositioner.below(labelSize, parentPoint.point, parentPoint.radius + offset);
39886 }
39887 case 4 /* Left */: {
39888 return DataLabelPointPositioner.left(labelSize, parentPoint.point, parentPoint.radius + offset);
39889 }
39890 case 8 /* Right */: {
39891 return DataLabelPointPositioner.right(labelSize, parentPoint.point, parentPoint.radius + offset);
39892 }
39893 case 32 /* BelowLeft */: {
39894 return DataLabelPointPositioner.belowLeft(labelSize, parentPoint.point, parentPoint.radius + offset);
39895 }
39896 case 16 /* BelowRight */: {
39897 return DataLabelPointPositioner.belowRight(labelSize, parentPoint.point, parentPoint.radius + offset);
39898 }
39899 case 128 /* AboveLeft */: {
39900 return DataLabelPointPositioner.aboveLeft(labelSize, parentPoint.point, parentPoint.radius + offset);
39901 }
39902 case 64 /* AboveRight */: {
39903 return DataLabelPointPositioner.aboveRight(labelSize, parentPoint.point, parentPoint.radius + offset);
39904 }
39905 case 256 /* Center */: {
39906 return DataLabelPointPositioner.center(labelSize, parentPoint.point);
39907 }
39908 default: {
39909 debug.assertFail("Unsupported label position");
39910 }
39911 }
39912 return null;
39913 }
39914 DataLabelPointPositioner.getLabelRect = getLabelRect;
39915 function above(labelSize, parentPoint, offset) {
39916 return {
39917 left: parentPoint.x - (labelSize.width / 2),
39918 top: parentPoint.y - offset - labelSize.height,
39919 width: labelSize.width,
39920 height: labelSize.height
39921 };
39922 }
39923 DataLabelPointPositioner.above = above;
39924 function below(labelSize, parentPoint, offset) {
39925 return {
39926 left: parentPoint.x - (labelSize.width / 2),
39927 top: parentPoint.y + offset,
39928 width: labelSize.width,
39929 height: labelSize.height
39930 };
39931 }
39932 DataLabelPointPositioner.below = below;
39933 function left(labelSize, parentPoint, offset) {
39934 return {
39935 left: parentPoint.x - offset - labelSize.width,
39936 top: parentPoint.y - (labelSize.height / 2),
39937 width: labelSize.width,
39938 height: labelSize.height
39939 };
39940 }
39941 DataLabelPointPositioner.left = left;
39942 function right(labelSize, parentPoint, offset) {
39943 return {
39944 left: parentPoint.x + offset,
39945 top: parentPoint.y - (labelSize.height / 2),
39946 width: labelSize.width,
39947 height: labelSize.height
39948 };
39949 }
39950 DataLabelPointPositioner.right = right;
39951 function belowLeft(labelSize, parentPoint, offset) {
39952 return {
39953 left: parentPoint.x - (DataLabelPointPositioner.sin45 * offset) - labelSize.width,
39954 top: parentPoint.y + (DataLabelPointPositioner.cos45 * offset),
39955 width: labelSize.width,
39956 height: labelSize.height
39957 };
39958 }
39959 DataLabelPointPositioner.belowLeft = belowLeft;
39960 function belowRight(labelSize, parentPoint, offset) {
39961 return {
39962 left: parentPoint.x + (DataLabelPointPositioner.sin45 * offset),
39963 top: parentPoint.y + (DataLabelPointPositioner.cos45 * offset),
39964 width: labelSize.width,
39965 height: labelSize.height
39966 };
39967 }
39968 DataLabelPointPositioner.belowRight = belowRight;
39969 function aboveLeft(labelSize, parentPoint, offset) {
39970 return {
39971 left: parentPoint.x - (DataLabelPointPositioner.sin45 * offset) - labelSize.width,
39972 top: parentPoint.y - (DataLabelPointPositioner.cos45 * offset) - labelSize.height,
39973 width: labelSize.width,
39974 height: labelSize.height
39975 };
39976 }
39977 DataLabelPointPositioner.aboveLeft = aboveLeft;
39978 function aboveRight(labelSize, parentPoint, offset) {
39979 return {
39980 left: parentPoint.x + (DataLabelPointPositioner.sin45 * offset),
39981 top: parentPoint.y - (DataLabelPointPositioner.cos45 * offset) - labelSize.height,
39982 width: labelSize.width,
39983 height: labelSize.height
39984 };
39985 }
39986 DataLabelPointPositioner.aboveRight = aboveRight;
39987 function center(labelSize, parentPoint) {
39988 return {
39989 left: parentPoint.x - (labelSize.width / 2),
39990 top: parentPoint.y - (labelSize.height / 2),
39991 width: labelSize.width,
39992 height: labelSize.height
39993 };
39994 }
39995 DataLabelPointPositioner.center = center;
39996 function getLabelLeaderLineEndingPoint(boundingBox, position, parentShape) {
39997 var x = boundingBox.left;
39998 var y = boundingBox.top;
39999 switch (position) {
40000 case 1 /* Above */:
40001 x += (boundingBox.width / 2);
40002 y += boundingBox.height;
40003 break;
40004 case 2 /* Below */:
40005 x += (boundingBox.width / 2);
40006 break;
40007 case 4 /* Left */:
40008 x += boundingBox.width;
40009 y += ((boundingBox.height * 2) / 3);
40010 break;
40011 case 8 /* Right */:
40012 y += ((boundingBox.height * 2) / 3);
40013 break;
40014 case 32 /* BelowLeft */:
40015 x += boundingBox.width;
40016 y += (boundingBox.height / 2);
40017 break;
40018 case 16 /* BelowRight */:
40019 y += (boundingBox.height / 2);
40020 break;
40021 case 128 /* AboveLeft */:
40022 x += boundingBox.width;
40023 y += boundingBox.height;
40024 break;
40025 case 64 /* AboveRight */:
40026 y += boundingBox.height;
40027 break;
40028 }
40029 return [[parentShape.point.x, parentShape.point.y], [x, y]];
40030 }
40031 DataLabelPointPositioner.getLabelLeaderLineEndingPoint = getLabelLeaderLineEndingPoint;
40032 })(DataLabelPointPositioner = powerbi.DataLabelPointPositioner || (powerbi.DataLabelPointPositioner = {}));
40033})(powerbi || (powerbi = {}));
40034/*
40035 * Power BI Visualizations
40036 *
40037 * Copyright (c) Microsoft Corporation
40038 * All rights reserved.
40039 * MIT License
40040 *
40041 * Permission is hereby granted, free of charge, to any person obtaining a copy
40042 * of this software and associated documentation files (the ""Software""), to deal
40043 * in the Software without restriction, including without limitation the rights
40044 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40045 * copies of the Software, and to permit persons to whom the Software is
40046 * furnished to do so, subject to the following conditions:
40047 *
40048 * The above copyright notice and this permission notice shall be included in
40049 * all copies or substantial portions of the Software.
40050 *
40051 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40052 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40053 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40054 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40055 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40056 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40057 * THE SOFTWARE.
40058 */
40059var powerbi;
40060(function (powerbi) {
40061 var NewDataLabelUtils = powerbi.visuals.NewDataLabelUtils;
40062 var labelStyle = powerbi.visuals.labelStyle;
40063 var DonutLabelUtils = powerbi.visuals.DonutLabelUtils;
40064 var DonutLabelLayout = (function () {
40065 function DonutLabelLayout(options, donutChartProperties) {
40066 this.startingOffset = options.startingOffset;
40067 this.maximumOffset = options.maximumOffset;
40068 if (options.offsetIterationDelta != null) {
40069 debug.assert(options.offsetIterationDelta > 0, "label offset delta must be greater than 0");
40070 this.offsetIterationDelta = options.offsetIterationDelta;
40071 }
40072 this.donutChartProperties = donutChartProperties;
40073 this.center = {
40074 x: donutChartProperties.viewport.width / 2,
40075 y: donutChartProperties.viewport.height / 2,
40076 };
40077 this.outerRadius = this.donutChartProperties.radius * this.donutChartProperties.outerArcRadiusRatio;
40078 this.innerRadius = (this.donutChartProperties.radius / 2) * this.donutChartProperties.innerArcRadiusRatio;
40079 this.additionalCharsWidth = powerbi.TextMeasurementService.measureSvgTextWidth({
40080 text: " ()",
40081 fontFamily: NewDataLabelUtils.LabelTextProperties.fontFamily,
40082 fontSize: jsCommon.PixelConverter.fromPoint(donutChartProperties.dataLabelsSettings.fontSize),
40083 fontWeight: NewDataLabelUtils.LabelTextProperties.fontWeight,
40084 });
40085 }
40086 /**
40087 * Arrange takes a set of data labels and lays them out them in order, assuming that
40088 * the given array has already been sorted with the most preferred labels at the
40089 * front.
40090 *
40091 * Details:
40092 * - We iterate over offsets from the target position, increasing from 0
40093 * - For each offset, we iterate over each data label
40094 * - For each data label, we iterate over each position that is valid for
40095 * both the specific label and this layout
40096 * - When a valid position is found, we position the label there and no longer
40097 * reposition it.
40098 * - This prioritizes the earlier labels to be positioned closer to their
40099 * target points in the position they prefer.
40100 * - This prioritizes putting data labels close to a valid position over
40101 * placing them at their preferred position (it will place it at a less
40102 * preferred position if it will be a smaller offset)
40103 */
40104 DonutLabelLayout.prototype.layout = function (labelDataPoints) {
40105 // Clear data labels for a new layout
40106 for (var _i = 0, labelDataPoints_3 = labelDataPoints; _i < labelDataPoints_3.length; _i++) {
40107 var donutLabel = labelDataPoints_3[_i];
40108 donutLabel.hasBeenRendered = false;
40109 donutLabel.labelSize = donutLabel.textSize;
40110 }
40111 var resultingLabels = [];
40112 var preferredLabels = [];
40113 var viewport = this.donutChartProperties.viewport;
40114 var labelDataPointsGroup = {
40115 labelDataPoints: labelDataPoints,
40116 maxNumberOfLabels: labelDataPoints.length
40117 };
40118 var grid = new powerbi.LabelArrangeGrid([labelDataPointsGroup], viewport);
40119 for (var i = labelDataPoints.length - 1; i >= 0; i--) {
40120 var labelPoint = labelDataPoints[i];
40121 if (labelPoint.isPreferred) {
40122 var label = labelDataPoints.splice(i, 1);
40123 preferredLabels = label.concat(preferredLabels);
40124 }
40125 }
40126 // first iterate all the preferred labels
40127 if (preferredLabels.length > 0)
40128 resultingLabels = this.positionLabels(preferredLabels, grid);
40129 // While there are invisible not preferred labels and label distance is less than the max
40130 // allowed distance
40131 if (labelDataPoints.length > 0) {
40132 var labels = this.positionLabels(labelDataPoints, grid);
40133 resultingLabels = resultingLabels.concat(labels);
40134 }
40135 return resultingLabels;
40136 };
40137 DonutLabelLayout.prototype.positionLabels = function (labelDataPoints, grid) {
40138 var resultingLabels = [];
40139 var offsetDelta = this.offsetIterationDelta;
40140 var currentOffset = this.startingOffset;
40141 var currentCenteredOffset = 0;
40142 while (currentOffset <= this.maximumOffset) {
40143 for (var _i = 0, labelDataPoints_4 = labelDataPoints; _i < labelDataPoints_4.length; _i++) {
40144 var labelPoint = labelDataPoints_4[_i];
40145 if (labelPoint.hasBeenRendered)
40146 continue;
40147 var label = this.tryPositionForDonut(labelPoint, grid, currentOffset);
40148 if (label)
40149 resultingLabels.push(label);
40150 }
40151 currentOffset += offsetDelta;
40152 currentCenteredOffset += offsetDelta;
40153 }
40154 return resultingLabels;
40155 };
40156 /**
40157 * We try to move the label 25% up/down if the label is truncated or it collides with other labels.
40158 * after we moved it once we check that the new position doesn't failed (collides with other labels).
40159 */
40160 DonutLabelLayout.prototype.tryPositionForDonut = function (labelPoint, grid, currentLabelOffset) {
40161 var parentShape = labelPoint.parentShape;
40162 if (_.isEmpty(parentShape.validPositions) || parentShape.validPositions[0] === 0 /* None */)
40163 return;
40164 var defaultPosition = parentShape.validPositions[0];
40165 var bestCandidate = this.tryAllPositions(labelPoint, grid, defaultPosition, currentLabelOffset);
40166 if (bestCandidate && bestCandidate.score === 0) {
40167 return this.buildLabel(bestCandidate, grid);
40168 }
40169 // If we haven't found a non-truncated label, try to split into 2 lines.
40170 if (this.donutChartProperties.dataLabelsSettings.labelStyle === labelStyle.both) {
40171 // Try to split the label to two lines if both data and category label are on
40172 var splitLabelDataPoint = this.splitDonutDataPoint(labelPoint);
40173 var bestSplitCandidate = this.tryAllPositions(splitLabelDataPoint, grid, defaultPosition, currentLabelOffset);
40174 // If the best candidate with a split line is better than the best candidate with a single line, return the former.
40175 if (bestSplitCandidate && (!bestCandidate || (bestSplitCandidate.score < bestCandidate.score))) {
40176 return this.buildLabel(bestSplitCandidate, grid);
40177 }
40178 }
40179 // We didn't find a better candidate by splitting the label lines, so return our best single-line candidate.
40180 if (bestCandidate) {
40181 return this.buildLabel(bestCandidate, grid);
40182 }
40183 };
40184 DonutLabelLayout.prototype.generateCandidate = function (labelDataPoint, candidatePosition, grid, currentLabelOffset) {
40185 var angle = this.generateCandidateAngleForPosition(labelDataPoint.donutArcDescriptor, candidatePosition);
40186 var parentShape = this.getPointPositionForAngle(angle);
40187 var parentPoint = parentShape.point;
40188 var score = this.score(labelDataPoint, parentPoint);
40189 var leaderLinePoints = DonutLabelUtils.getLabelLeaderLineForDonutChart(labelDataPoint.donutArcDescriptor, this.donutChartProperties, parentPoint, angle);
40190 var leaderLinesSize = DonutLabelUtils.getLabelLeaderLinesSizeForDonutChart(leaderLinePoints);
40191 var newLabelDataPoint = _.clone(labelDataPoint);
40192 newLabelDataPoint.angle = angle;
40193 newLabelDataPoint.parentShape = parentShape;
40194 newLabelDataPoint.leaderLinePoints = leaderLinePoints;
40195 newLabelDataPoint.linesSize = leaderLinesSize;
40196 var boundingBoxs = DonutLabelLayout.tryPositionPoint(grid, parentShape.validPositions[0], newLabelDataPoint, currentLabelOffset, this.center, this.donutChartProperties.viewport);
40197 return {
40198 angle: angle,
40199 point: parentShape,
40200 score: score,
40201 labelRects: boundingBoxs,
40202 labelDataPoint: newLabelDataPoint,
40203 };
40204 };
40205 DonutLabelLayout.prototype.tryAllPositions = function (labelDataPoint, grid, defaultPosition, currentLabelOffset) {
40206 var boundingBoxs = DonutLabelLayout.tryPositionPoint(grid, defaultPosition, labelDataPoint, currentLabelOffset, this.center, this.donutChartProperties.viewport);
40207 var originalPoint = labelDataPoint.parentShape;
40208 var originalCandidate = {
40209 point: originalPoint,
40210 angle: labelDataPoint.angle,
40211 score: this.score(labelDataPoint, originalPoint.point),
40212 labelRects: boundingBoxs,
40213 labelDataPoint: labelDataPoint,
40214 };
40215 if (boundingBoxs && boundingBoxs.textRect && originalCandidate.score === 0) {
40216 return originalCandidate;
40217 }
40218 var positions = [];
40219 var bestCandidate;
40220 if (boundingBoxs && boundingBoxs.textRect) {
40221 // We have a truncated label here, otherwised we would have returned already
40222 positions = this.getLabelPointPositions(labelDataPoint, /* isTruncated */ true);
40223 bestCandidate = originalCandidate;
40224 }
40225 else {
40226 positions = this.getLabelPointPositions(labelDataPoint, /* isTruncated */ false);
40227 }
40228 // Try to reposition the label if necessary
40229 for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) {
40230 var position = positions_1[_i];
40231 var candidate = this.generateCandidate(labelDataPoint, position, grid, currentLabelOffset);
40232 if (candidate.labelRects && candidate.labelRects.textRect) {
40233 if (bestCandidate == null || candidate.score < bestCandidate.score) {
40234 bestCandidate = candidate;
40235 if (bestCandidate.score === 0)
40236 return bestCandidate;
40237 }
40238 }
40239 }
40240 return bestCandidate;
40241 };
40242 DonutLabelLayout.prototype.buildLabel = function (labelLayout, grid) {
40243 var resultingBoundingBox = labelLayout.labelRects.textRect;
40244 var labelPoint = labelLayout.labelDataPoint;
40245 grid.add(resultingBoundingBox);
40246 grid.add(labelLayout.labelRects.horizontalLineRect);
40247 grid.add(labelLayout.labelRects.diagonalLineRect);
40248 labelPoint.hasBeenRendered = true;
40249 var left = resultingBoundingBox.left - this.center.x;
40250 //We need to add or subtract half resultingBoundingBox.width because Donut chart labels get text anchor start/end
40251 if (left < 0)
40252 left += resultingBoundingBox.width / 2;
40253 else
40254 left -= resultingBoundingBox.width / 2;
40255 var textAnchor = labelPoint.parentShape.validPositions[0] === 8 /* Right */ ? 'start' : 'end';
40256 var boundingBox = {
40257 left: left,
40258 top: resultingBoundingBox.top - this.center.y,
40259 height: resultingBoundingBox.height,
40260 width: resultingBoundingBox.width,
40261 };
40262 // After repositioning the label we need to recalculate its size and format it according to the current available space
40263 var labelSettingsStyle = this.donutChartProperties.dataLabelsSettings.labelStyle;
40264 var spaceAvailableForLabels = DonutLabelUtils.getSpaceAvailableForDonutLabels(labelPoint.parentShape.point.x, this.donutChartProperties.viewport);
40265 var formattedDataLabel;
40266 var formattedCategoryLabel;
40267 var text;
40268 var getLabelFormattedText = powerbi.visuals.dataLabelUtils.getLabelFormattedText;
40269 var fontSize = labelPoint.fontSize;
40270 var hasOneLabelRow = labelSettingsStyle === labelStyle.both && labelPoint.secondRowText == null;
40271 // Giving 50/50 space when both category and measure are on
40272 if (hasOneLabelRow) {
40273 labelPoint.dataLabel = " (" + labelPoint.dataLabel + ")";
40274 spaceAvailableForLabels /= 2;
40275 }
40276 if (labelSettingsStyle === labelStyle.both || labelSettingsStyle === labelStyle.data) {
40277 formattedDataLabel = getLabelFormattedText({
40278 label: labelPoint.dataLabel,
40279 maxWidth: spaceAvailableForLabels,
40280 fontSize: fontSize
40281 });
40282 }
40283 if (labelSettingsStyle === labelStyle.both || labelSettingsStyle === labelStyle.category) {
40284 formattedCategoryLabel = getLabelFormattedText({
40285 label: labelPoint.categoryLabel,
40286 maxWidth: spaceAvailableForLabels,
40287 fontSize: fontSize
40288 });
40289 }
40290 switch (labelSettingsStyle) {
40291 case labelStyle.both:
40292 if (labelPoint.secondRowText == null) {
40293 text = formattedCategoryLabel + formattedDataLabel;
40294 }
40295 else {
40296 text = formattedDataLabel;
40297 labelPoint.secondRowText = formattedCategoryLabel;
40298 }
40299 break;
40300 case labelStyle.data:
40301 text = formattedDataLabel;
40302 break;
40303 case labelStyle.category:
40304 text = formattedCategoryLabel;
40305 break;
40306 }
40307 // Limit text size width for correct leader line calculation
40308 labelPoint.textSize.width = Math.min(labelPoint.textSize.width, hasOneLabelRow ? spaceAvailableForLabels * 2 : spaceAvailableForLabels);
40309 return {
40310 boundingBox: boundingBox,
40311 text: text,
40312 tooltip: labelPoint.tooltip,
40313 isVisible: true,
40314 fill: labelPoint.outsideFill,
40315 identity: labelPoint.identity,
40316 fontSize: fontSize,
40317 selected: false,
40318 textAnchor: textAnchor,
40319 leaderLinePoints: labelPoint.leaderLinePoints,
40320 hasBackground: false,
40321 secondRowText: labelPoint.secondRowText,
40322 };
40323 };
40324 DonutLabelLayout.tryPositionPoint = function (grid, position, labelDataPoint, offset, center, viewport) {
40325 var parentPoint = labelDataPoint.parentShape;
40326 // Limit label width to fit the availabe space for labels
40327 var textSize = _.clone(labelDataPoint.textSize);
40328 textSize.width = Math.min(textSize.width, DonutLabelUtils.getSpaceAvailableForDonutLabels(parentPoint.point.x, viewport));
40329 // Create label rectangle
40330 var labelRect = powerbi.DataLabelPointPositioner.getLabelRect(textSize, parentPoint, position, offset);
40331 // Create label diagonal line rectangle
40332 var diagonalLineParentPoint = {
40333 point: {
40334 x: labelDataPoint.leaderLinePoints[0][0],
40335 y: labelDataPoint.leaderLinePoints[0][1] < 0 ? labelDataPoint.leaderLinePoints[1][1] : labelDataPoint.leaderLinePoints[0][1]
40336 },
40337 radius: 0,
40338 validPositions: null
40339 };
40340 var diagonalLineRect = powerbi.DataLabelPointPositioner.getLabelRect(labelDataPoint.linesSize[DonutLabelUtils.DiagonalLineIndex], diagonalLineParentPoint, position, offset);
40341 // Create label horizontal line rectangle
40342 var horizontalLineParentPoint = {
40343 point: {
40344 x: labelDataPoint.leaderLinePoints[1][0],
40345 y: labelDataPoint.leaderLinePoints[1][1]
40346 },
40347 radius: 0,
40348 validPositions: null
40349 };
40350 var horizontalLineRect = powerbi.DataLabelPointPositioner.getLabelRect(labelDataPoint.linesSize[DonutLabelUtils.HorizontalLineIndex], horizontalLineParentPoint, position, offset);
40351 if (!labelRect || !diagonalLineRect || !horizontalLineRect)
40352 return;
40353 labelRect.left += center.x;
40354 labelRect.top += center.y;
40355 var centerForLinesWidth = center.x - labelRect.width / 2;
40356 diagonalLineRect.left += centerForLinesWidth;
40357 diagonalLineRect.top += center.y;
40358 horizontalLineRect.left += centerForLinesWidth;
40359 horizontalLineRect.top += center.y;
40360 if (!grid.hasConflict(labelRect) && !grid.hasConflict(diagonalLineRect) && !grid.hasConflict(horizontalLineRect))
40361 return { textRect: labelRect, diagonalLineRect: diagonalLineRect, horizontalLineRect: horizontalLineRect };
40362 };
40363 /**
40364 * Returns an array of valid positions for hidden and truncated labels.
40365 * For truncated labels will return positions with more available space.
40366 * For hidden labels will return all possible positions by the order we draw labels (clockwise)
40367 */
40368 DonutLabelLayout.prototype.getLabelPointPositions = function (labelPoint, isTruncated) {
40369 var parentShape = labelPoint.parentShape;
40370 var position = parentShape.validPositions[0];
40371 if (!isTruncated) {
40372 return position === 4 /* Left */
40373 ? [128 /* AboveLeft */, 32 /* BelowLeft */]
40374 : [16 /* BelowRight */, 64 /* AboveRight */];
40375 }
40376 if (parentShape.point.y < 0) {
40377 return position === 8 /* Right */
40378 ? [64 /* AboveRight */]
40379 : [128 /* AboveLeft */];
40380 }
40381 else {
40382 return position === 8 /* Right */
40383 ? [16 /* BelowRight */]
40384 : [32 /* BelowLeft */];
40385 }
40386 };
40387 /**
40388 * Returns a new DonutLabelDataPoint after splitting it into two lines
40389 */
40390 DonutLabelLayout.prototype.splitDonutDataPoint = function (labelPoint) {
40391 var textSize = {
40392 width: Math.max(labelPoint.categoryLabelSize.width, labelPoint.dataLabelSize.width),
40393 height: labelPoint.dataLabelSize.height * 2,
40394 };
40395 var newLabelPoint = _.clone(labelPoint);
40396 newLabelPoint.textSize = textSize;
40397 newLabelPoint.secondRowText = labelPoint.categoryLabel;
40398 return newLabelPoint;
40399 };
40400 DonutLabelLayout.prototype.generateCandidateAngleForPosition = function (d, position) {
40401 var midAngle = d.startAngle + ((d.endAngle - d.startAngle) / 2);
40402 switch (position) {
40403 case 64 /* AboveRight */:
40404 case 32 /* BelowLeft */:
40405 return ((d.startAngle + midAngle) - Math.PI) / 2;
40406 case 128 /* AboveLeft */:
40407 case 16 /* BelowRight */:
40408 return ((midAngle + d.endAngle) - Math.PI) / 2;
40409 default:
40410 debug.assertFail("Unsupported label position");
40411 }
40412 };
40413 DonutLabelLayout.prototype.getPointPositionForAngle = function (angle) {
40414 // Calculate the new label coordinates
40415 var labelX = DonutLabelUtils.getXPositionForDonutLabel(Math.cos(angle) * this.outerRadius);
40416 var labelY = Math.sin(angle) * this.outerRadius;
40417 var newPosition = labelX < 0 ? 4 /* Left */ : 8 /* Right */;
40418 var pointPosition = {
40419 point: {
40420 x: labelX,
40421 y: labelY,
40422 },
40423 validPositions: [newPosition],
40424 radius: 0,
40425 };
40426 return pointPosition;
40427 };
40428 DonutLabelLayout.prototype.score = function (labelPoint, point) {
40429 var spaceAvailableForLabels = DonutLabelUtils.getSpaceAvailableForDonutLabels(point.x, this.donutChartProperties.viewport);
40430 var textWidth;
40431 // Check if we show category and data labels in one row
40432 if (this.donutChartProperties.dataLabelsSettings.labelStyle === labelStyle.both && labelPoint.secondRowText == null) {
40433 // Each of the labels gets half of the available space for labels so we take this into consideration in the score
40434 textWidth = Math.max(labelPoint.categoryLabelSize.width, labelPoint.dataLabelSize.width + this.additionalCharsWidth);
40435 spaceAvailableForLabels /= 2;
40436 }
40437 else {
40438 textWidth = labelPoint.textSize.width;
40439 }
40440 return Math.max(textWidth - spaceAvailableForLabels, 0);
40441 };
40442 return DonutLabelLayout;
40443 }());
40444 powerbi.DonutLabelLayout = DonutLabelLayout;
40445})(powerbi || (powerbi = {}));
40446/*
40447 * Power BI Visualizations
40448 *
40449 * Copyright (c) Microsoft Corporation
40450 * All rights reserved.
40451 * MIT License
40452 *
40453 * Permission is hereby granted, free of charge, to any person obtaining a copy
40454 * of this software and associated documentation files (the ""Software""), to deal
40455 * in the Software without restriction, including without limitation the rights
40456 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40457 * copies of the Software, and to permit persons to whom the Software is
40458 * furnished to do so, subject to the following conditions:
40459 *
40460 * The above copyright notice and this permission notice shall be included in
40461 * all copies or substantial portions of the Software.
40462 *
40463 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40464 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40465 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40466 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40467 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40468 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40469 * THE SOFTWARE.
40470 */
40471var powerbi;
40472(function (powerbi) {
40473 var NewDataLabelUtils = powerbi.visuals.NewDataLabelUtils;
40474 var DefaultCentroidOffset = 5;
40475 var OffsetDelta = 10;
40476 var MaximumOffset = 60;
40477 var stemExtension = 5;
40478 var FilledMapLabelLayout = (function () {
40479 function FilledMapLabelLayout() {
40480 }
40481 FilledMapLabelLayout.prototype.layout = function (labelDataPoints, viewport, polygonInfoTransform, redrawDataLabels) {
40482 if (redrawDataLabels || this.labels === undefined) {
40483 var labelDataPointsGroup = {
40484 labelDataPoints: labelDataPoints,
40485 maxNumberOfLabels: labelDataPoints.length
40486 };
40487 for (var _i = 0, labelDataPoints_5 = labelDataPoints; _i < labelDataPoints_5.length; _i++) {
40488 var labelPoint = labelDataPoints_5[_i];
40489 labelPoint.labelSize = {
40490 width: labelPoint.textSize.width + 2 * NewDataLabelUtils.horizontalLabelBackgroundPadding,
40491 height: labelPoint.textSize.height + 2 * NewDataLabelUtils.verticalLabelBackgroundPadding,
40492 };
40493 }
40494 var grid = new powerbi.LabelArrangeGrid([labelDataPointsGroup], viewport);
40495 var resultingDataLabels = [];
40496 var allPolygons = [];
40497 for (var _a = 0, labelDataPoints_6 = labelDataPoints; _a < labelDataPoints_6.length; _a++) {
40498 var labelPoint = labelDataPoints_6[_a];
40499 var polygon = labelPoint.parentShape.polygon;
40500 allPolygons.push(polygon);
40501 polygon.pixelBoundingRect = polygonInfoTransform.applyToRect(polygon.absoluteBoundingRect());
40502 }
40503 var shapesgrid = new LabelPolygonArrangeGrid(allPolygons, viewport);
40504 for (var _b = 0, labelDataPoints_7 = labelDataPoints; _b < labelDataPoints_7.length; _b++) {
40505 var labelPoint = labelDataPoints_7[_b];
40506 var dataLabel = this.getLabelByPolygonPositions(labelPoint, polygonInfoTransform, grid, shapesgrid);
40507 if (dataLabel != null) {
40508 resultingDataLabels.push(dataLabel);
40509 }
40510 }
40511 this.labels = resultingDataLabels;
40512 }
40513 else {
40514 this.updateLabelOffsets(polygonInfoTransform);
40515 }
40516 return this.labels;
40517 };
40518 FilledMapLabelLayout.prototype.getLabelPolygon = function (mapDataPoint, position, pointPosition, offset) {
40519 var dataPointSize = {
40520 width: mapDataPoint.textSize.width,
40521 height: (mapDataPoint.textSize.height)
40522 };
40523 return this.getLabelBoundingBox(dataPointSize, position, pointPosition, offset);
40524 };
40525 FilledMapLabelLayout.prototype.getLabelBoundingBox = function (dataPointSize, position, pointPosition, offset) {
40526 switch (position) {
40527 case 1 /* Above */: {
40528 return powerbi.DataLabelPointPositioner.above(dataPointSize, pointPosition, offset);
40529 }
40530 case 2 /* Below */: {
40531 return powerbi.DataLabelPointPositioner.below(dataPointSize, pointPosition, offset);
40532 }
40533 case 4 /* Left */: {
40534 return powerbi.DataLabelPointPositioner.left(dataPointSize, pointPosition, offset);
40535 }
40536 case 8 /* Right */: {
40537 return powerbi.DataLabelPointPositioner.right(dataPointSize, pointPosition, offset);
40538 }
40539 case 128 /* AboveLeft */: {
40540 return powerbi.DataLabelPointPositioner.aboveLeft(dataPointSize, pointPosition, offset);
40541 }
40542 case 64 /* AboveRight */: {
40543 return powerbi.DataLabelPointPositioner.aboveRight(dataPointSize, pointPosition, offset);
40544 }
40545 case 32 /* BelowLeft */: {
40546 return powerbi.DataLabelPointPositioner.belowLeft(dataPointSize, pointPosition, offset);
40547 }
40548 case 16 /* BelowRight */: {
40549 return powerbi.DataLabelPointPositioner.belowRight(dataPointSize, pointPosition, offset);
40550 }
40551 case 256 /* Center */: {
40552 return powerbi.DataLabelPointPositioner.center(dataPointSize, pointPosition);
40553 }
40554 default: {
40555 debug.assertFail("Unsupported label position");
40556 }
40557 }
40558 return null;
40559 };
40560 FilledMapLabelLayout.prototype.getLabelByPolygonPositions = function (labelPoint, polygonInfoTransform, grid, shapesGrid) {
40561 var offset = 0;
40562 var inverseTransorm = polygonInfoTransform.getInverse();
40563 for (var i = 0; i < 2; i++) {
40564 if (i === 1) {
40565 offset = DefaultCentroidOffset;
40566 }
40567 for (var _i = 0, _a = labelPoint.parentShape.validPositions; _i < _a.length; _i++) {
40568 var position = _a[_i];
40569 var resultingAbsoluteBoundingBox = this.tryPositionForPolygonPosition(position, labelPoint, polygonInfoTransform, offset, inverseTransorm);
40570 if (position === 256 /* Center */ && i !== 0) {
40571 continue;
40572 }
40573 if (resultingAbsoluteBoundingBox) {
40574 var resultingBoundingBox = polygonInfoTransform.applyToRect(resultingAbsoluteBoundingBox);
40575 var dataLabel = {
40576 text: labelPoint.text,
40577 secondRowText: labelPoint.secondRowText,
40578 boundingBox: resultingBoundingBox,
40579 isVisible: true,
40580 fill: labelPoint.insideFill,
40581 identity: null,
40582 selected: false,
40583 hasBackground: true,
40584 textAnchor: "middle",
40585 originalPixelOffset: offset,
40586 isPlacedInsidePolygon: true,
40587 absoluteBoundingBoxCenter: {
40588 x: resultingAbsoluteBoundingBox.left + resultingAbsoluteBoundingBox.width / 2,
40589 y: resultingAbsoluteBoundingBox.top + resultingAbsoluteBoundingBox.height / 2
40590 }
40591 };
40592 return dataLabel;
40593 }
40594 }
40595 }
40596 var currentOffset = 6;
40597 while (currentOffset <= MaximumOffset) {
40598 for (var _b = 0, _c = labelPoint.parentShape.validPositions; _b < _c.length; _b++) {
40599 var position = _c[_b];
40600 if (position === 256 /* Center */) {
40601 continue;
40602 }
40603 var polygon = labelPoint.parentShape.polygon;
40604 var pixelCentroid = polygonInfoTransform.applyToPoint(polygon.absoluteCentroid());
40605 var resultingAbsolutBoundingBox = this.tryPlaceLabelOutsidePolygon(grid, position, labelPoint, currentOffset, pixelCentroid, shapesGrid, inverseTransorm);
40606 if (resultingAbsolutBoundingBox) {
40607 var resultingBoundingBox = polygonInfoTransform.applyToRect(resultingAbsolutBoundingBox);
40608 var dataLabel = {
40609 text: labelPoint.text,
40610 secondRowText: labelPoint.secondRowText,
40611 boundingBox: resultingBoundingBox,
40612 isVisible: true,
40613 fill: labelPoint.insideFill,
40614 identity: null,
40615 selected: false,
40616 hasBackground: true,
40617 isPlacedInsidePolygon: false,
40618 textAnchor: "middle",
40619 originalPixelOffset: currentOffset,
40620 originalPosition: position,
40621 originalAbsoluteCentroid: polygon.absoluteCentroid(),
40622 absoluteBoundingBoxCenter: {
40623 x: resultingAbsolutBoundingBox.left + resultingAbsolutBoundingBox.width / 2,
40624 y: resultingAbsolutBoundingBox.top + resultingAbsolutBoundingBox.height / 2
40625 }
40626 };
40627 var pixelStemSource = this.calculateStemSource(polygonInfoTransform, inverseTransorm, polygon, resultingBoundingBox, position, pixelCentroid);
40628 dataLabel.leaderLinePoints = this.setLeaderLinePoints(pixelStemSource, this.calculateStemDestination(resultingBoundingBox, position));
40629 dataLabel.absoluteStemSource = inverseTransorm.applyToPoint(pixelStemSource);
40630 grid.add(resultingBoundingBox);
40631 return dataLabel;
40632 }
40633 }
40634 currentOffset += OffsetDelta;
40635 }
40636 return null;
40637 };
40638 FilledMapLabelLayout.prototype.setLeaderLinePoints = function (stemSource, stemDestination) {
40639 return [[stemSource.x, stemSource.y], [stemDestination.x, stemDestination.y]];
40640 };
40641 FilledMapLabelLayout.prototype.calculateStemSource = function (polygonInfoTransform, inverseTransorm, polygon, labelBoundingBox, position, pixelCentroid) {
40642 var absoluteStemSource = polygon.lineIntersectionPoint(polygon.absoluteCentroid(), inverseTransorm.applyToPoint({ x: labelBoundingBox.left + labelBoundingBox.width / 2, y: labelBoundingBox.top + labelBoundingBox.height / 2 }));
40643 if (absoluteStemSource == null) {
40644 return pixelCentroid;
40645 }
40646 var stemSource = polygonInfoTransform.applyToPoint(absoluteStemSource);
40647 switch (position) {
40648 case 1 /* Above */: {
40649 stemSource.y += stemExtension;
40650 break;
40651 }
40652 case 2 /* Below */: {
40653 stemSource.y -= stemExtension;
40654 break;
40655 }
40656 case 4 /* Left */: {
40657 stemSource.x += stemExtension;
40658 break;
40659 }
40660 case 8 /* Right */: {
40661 stemSource.x -= stemExtension;
40662 break;
40663 }
40664 case 128 /* AboveLeft */: {
40665 stemSource.x += (stemExtension / powerbi.DataLabelPointPositioner.cos45);
40666 stemSource.y += (stemExtension / powerbi.DataLabelPointPositioner.sin45);
40667 break;
40668 }
40669 case 64 /* AboveRight */: {
40670 stemSource.x -= (stemExtension / powerbi.DataLabelPointPositioner.cos45);
40671 stemSource.y += (stemExtension / powerbi.DataLabelPointPositioner.sin45);
40672 break;
40673 }
40674 case 32 /* BelowLeft */: {
40675 stemSource.x += (stemExtension / powerbi.DataLabelPointPositioner.cos45);
40676 stemSource.y -= (stemExtension / powerbi.DataLabelPointPositioner.sin45);
40677 break;
40678 }
40679 case 16 /* BelowRight */: {
40680 stemSource.x -= (stemExtension / powerbi.DataLabelPointPositioner.cos45);
40681 stemSource.y -= (stemExtension / powerbi.DataLabelPointPositioner.sin45);
40682 break;
40683 }
40684 case 256 /* Center */: {
40685 break;
40686 }
40687 default: {
40688 debug.assertFail("Unsupported label position");
40689 }
40690 }
40691 return stemSource;
40692 };
40693 FilledMapLabelLayout.prototype.calculateStemDestination = function (labelBoundingBox, position) {
40694 var x;
40695 var y;
40696 switch (position) {
40697 case 1 /* Above */: {
40698 x = labelBoundingBox.left + labelBoundingBox.width / 2;
40699 y = labelBoundingBox.top + labelBoundingBox.height;
40700 break;
40701 }
40702 case 2 /* Below */: {
40703 x = labelBoundingBox.left + labelBoundingBox.width / 2;
40704 y = labelBoundingBox.top;
40705 break;
40706 }
40707 case 4 /* Left */: {
40708 x = labelBoundingBox.left + labelBoundingBox.width;
40709 y = labelBoundingBox.top + labelBoundingBox.height / 2;
40710 break;
40711 }
40712 case 8 /* Right */: {
40713 x = labelBoundingBox.left;
40714 y = labelBoundingBox.top + labelBoundingBox.height / 2;
40715 break;
40716 }
40717 case 128 /* AboveLeft */: {
40718 x = labelBoundingBox.left + labelBoundingBox.width;
40719 y = labelBoundingBox.top + labelBoundingBox.height;
40720 break;
40721 }
40722 case 64 /* AboveRight */: {
40723 x = labelBoundingBox.left;
40724 y = labelBoundingBox.top + labelBoundingBox.height;
40725 break;
40726 }
40727 case 32 /* BelowLeft */: {
40728 x = labelBoundingBox.left + labelBoundingBox.width;
40729 y = labelBoundingBox.top;
40730 break;
40731 }
40732 case 16 /* BelowRight */: {
40733 x = labelBoundingBox.left;
40734 y = labelBoundingBox.top;
40735 break;
40736 }
40737 case 256 /* Center */: {
40738 break;
40739 }
40740 default: {
40741 debug.assertFail("Unsupported label position");
40742 }
40743 }
40744 return { x: x, y: y };
40745 };
40746 FilledMapLabelLayout.prototype.tryPositionForPolygonPosition = function (position, labelDataPoint, polygonInfoTransform, offset, inverseTransorm) {
40747 var polygon = labelDataPoint.parentShape.polygon;
40748 var pixelCentroid = polygonInfoTransform.applyToPoint(polygon.absoluteCentroid());
40749 var labelRect = this.getLabelPolygon(labelDataPoint, position, pixelCentroid, offset);
40750 var absoluteLabelRect = this.getAbsoluteRectangle(inverseTransorm, labelRect);
40751 return polygon.contains(absoluteLabelRect) ? absoluteLabelRect : null;
40752 };
40753 /**
40754 * Tests a particular position/offset combination for the given data label.
40755 * If the label can be placed, returns the resulting bounding box for the data
40756 * label. If not, returns null.
40757 */
40758 FilledMapLabelLayout.prototype.tryPlaceLabelOutsidePolygon = function (grid, position, labelDataPoint, offset, pixelCentroid, shapesGrid, inverseTransform) {
40759 var offsetForPosition = offset;
40760 var labelRect = this.getLabelPolygon(labelDataPoint, position, pixelCentroid, offsetForPosition);
40761 var otherLabelsConflict = grid.hasConflict(labelRect);
40762 if (!otherLabelsConflict) {
40763 var absoluteLabelRect = this.getAbsoluteRectangle(inverseTransform, labelRect);
40764 if (!shapesGrid.hasConflict(absoluteLabelRect, labelRect))
40765 return absoluteLabelRect;
40766 }
40767 return null;
40768 };
40769 FilledMapLabelLayout.prototype.updateLabelOffsets = function (polygonInfoTransform) {
40770 for (var _i = 0, _a = this.labels; _i < _a.length; _i++) {
40771 var label = _a[_i];
40772 if (!label.isVisible)
40773 continue;
40774 if (label.isPlacedInsidePolygon) {
40775 var newOffset = polygonInfoTransform.applyToPoint(label.absoluteBoundingBoxCenter);
40776 var xDelta = (label.boundingBox.left + label.boundingBox.width / 2) - newOffset.x;
40777 var yDelta = (label.boundingBox.top + label.boundingBox.height / 2) - newOffset.y;
40778 label.boundingBox.top -= yDelta;
40779 label.boundingBox.left -= xDelta;
40780 }
40781 else {
40782 var stemSourcePoint = polygonInfoTransform.applyToPoint(label.absoluteStemSource);
40783 var pixelCentroid = polygonInfoTransform.applyToPoint(label.originalAbsoluteCentroid);
40784 label.boundingBox = this.getLabelBoundingBox({ width: label.boundingBox.width, height: label.boundingBox.height }, label.originalPosition, pixelCentroid, label.originalPixelOffset);
40785 if (label.leaderLinePoints !== undefined)
40786 label.leaderLinePoints = this.setLeaderLinePoints(stemSourcePoint, this.calculateStemDestination(label.boundingBox, label.originalPosition));
40787 }
40788 }
40789 };
40790 FilledMapLabelLayout.prototype.getAbsoluteRectangle = function (inverseTransorm, rect) {
40791 return inverseTransorm.applyToRect(rect);
40792 };
40793 return FilledMapLabelLayout;
40794 }());
40795 powerbi.FilledMapLabelLayout = FilledMapLabelLayout;
40796 var LabelPolygonArrangeGrid = (function () {
40797 function LabelPolygonArrangeGrid(polygons, viewport) {
40798 this.viewport = viewport;
40799 var maxPolygonWidth = 0;
40800 var maxPolygonHeight = 0;
40801 for (var _i = 0, polygons_1 = polygons; _i < polygons_1.length; _i++) {
40802 var polygon = polygons_1[_i];
40803 var polygonSize = polygon.pixelBoundingRect;
40804 if (polygonSize.width > maxPolygonWidth) {
40805 maxPolygonWidth = polygonSize.width;
40806 }
40807 if (polygonSize.height > maxPolygonHeight) {
40808 maxPolygonHeight = polygonSize.height;
40809 }
40810 }
40811 if (maxPolygonWidth === 0) {
40812 maxPolygonWidth = viewport.width;
40813 }
40814 if (maxPolygonHeight === 0) {
40815 maxPolygonHeight = viewport.height;
40816 }
40817 var cellSize = this.cellSize = { width: maxPolygonWidth * LabelPolygonArrangeGrid.cellSizeMultiplier, height: maxPolygonHeight * LabelPolygonArrangeGrid.cellSizeMultiplier };
40818 this.columnCount = LabelPolygonArrangeGrid.getCellCount(cellSize.width, viewport.width, 1, 100);
40819 this.rowCount = LabelPolygonArrangeGrid.getCellCount(cellSize.height, viewport.height, 1, 100);
40820 var grid = [];
40821 for (var i = 0, ilen = this.columnCount; i < ilen; i++) {
40822 grid[i] = [];
40823 for (var j = 0, jlen = this.rowCount; j < jlen; j++) {
40824 grid[i][j] = [];
40825 }
40826 }
40827 this.grid = grid;
40828 for (var _a = 0, polygons_2 = polygons; _a < polygons_2.length; _a++) {
40829 var polygon = polygons_2[_a];
40830 this.add(polygon);
40831 }
40832 }
40833 LabelPolygonArrangeGrid.prototype.hasConflict = function (absolutLabelRect, pixelLabelRect) {
40834 var containingIndexRect = this.getContainingGridSubsection(pixelLabelRect);
40835 var grid = this.grid;
40836 for (var x = containingIndexRect.xMin; x < containingIndexRect.xMax; x++) {
40837 for (var y = containingIndexRect.yMin; y < containingIndexRect.yMax; y++) {
40838 for (var _i = 0, _a = grid[x][y]; _i < _a.length; _i++) {
40839 var currentPolygon = _a[_i];
40840 if (currentPolygon.conflicts(absolutLabelRect)) {
40841 return true;
40842 }
40843 }
40844 }
40845 }
40846 return false;
40847 };
40848 LabelPolygonArrangeGrid.prototype.add = function (polygon) {
40849 var containingIndexRect = this.getContainingGridSubsection(polygon.pixelBoundingRect);
40850 for (var x = containingIndexRect.xMin; x < containingIndexRect.xMax; x++) {
40851 for (var y = containingIndexRect.yMin; y < containingIndexRect.yMax; y++) {
40852 this.grid[x][y].push(polygon);
40853 }
40854 }
40855 };
40856 LabelPolygonArrangeGrid.prototype.getContainingGridSubsection = function (rect) {
40857 return {
40858 xMin: LabelPolygonArrangeGrid.bound(Math.floor(rect.left / this.cellSize.width), 0, this.columnCount),
40859 xMax: LabelPolygonArrangeGrid.bound(Math.ceil((rect.left + rect.width) / this.cellSize.width), 0, this.columnCount),
40860 yMin: LabelPolygonArrangeGrid.bound(Math.floor(rect.top / this.cellSize.height), 0, this.rowCount),
40861 yMax: LabelPolygonArrangeGrid.bound(Math.ceil((rect.top + rect.height) / this.cellSize.height), 0, this.rowCount),
40862 };
40863 };
40864 LabelPolygonArrangeGrid.getCellCount = function (step, length, minCount, maxCount) {
40865 return LabelPolygonArrangeGrid.bound(Math.ceil(length / step), minCount, maxCount);
40866 };
40867 LabelPolygonArrangeGrid.bound = function (value, min, max) {
40868 return Math.max(Math.min(value, max), min);
40869 };
40870 /**
40871 * A multiplier applied to the largest width height to attempt to balance # of
40872 * polygons in each cell and number of cells each polygon belongs to
40873 */
40874 LabelPolygonArrangeGrid.cellSizeMultiplier = 2;
40875 return LabelPolygonArrangeGrid;
40876 }());
40877 powerbi.LabelPolygonArrangeGrid = LabelPolygonArrangeGrid;
40878})(powerbi || (powerbi = {}));
40879/*
40880 * Power BI Visualizations
40881 *
40882 * Copyright (c) Microsoft Corporation
40883 * All rights reserved.
40884 * MIT License
40885 *
40886 * Permission is hereby granted, free of charge, to any person obtaining a copy
40887 * of this software and associated documentation files (the ""Software""), to deal
40888 * in the Software without restriction, including without limitation the rights
40889 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40890 * copies of the Software, and to permit persons to whom the Software is
40891 * furnished to do so, subject to the following conditions:
40892 *
40893 * The above copyright notice and this permission notice shall be included in
40894 * all copies or substantial portions of the Software.
40895 *
40896 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40897 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40898 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40899 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40900 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40901 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40902 * THE SOFTWARE.
40903 */
40904var powerbi;
40905(function (powerbi) {
40906 var visuals;
40907 (function (visuals) {
40908 function createColorAllocatorFactory() {
40909 return new ColorAllocatorFactory();
40910 }
40911 visuals.createColorAllocatorFactory = createColorAllocatorFactory;
40912 var ColorAllocatorFactory = (function () {
40913 function ColorAllocatorFactory() {
40914 }
40915 ColorAllocatorFactory.prototype.linearGradient2 = function (options) {
40916 return new LinearGradient2Allocator(options);
40917 };
40918 ColorAllocatorFactory.prototype.linearGradient3 = function (options, splitScales) {
40919 if (splitScales)
40920 return new LinearGradient3AllocatorWithSplittedScales(options);
40921 return new LinearGradient3Allocator(options);
40922 };
40923 return ColorAllocatorFactory;
40924 }());
40925 var LinearGradient2Allocator = (function () {
40926 function LinearGradient2Allocator(options) {
40927 debug.assertValue(options, 'options');
40928 this.options = options;
40929 var min = options.min, max = options.max;
40930 this.scale = d3.scale.linear()
40931 .domain([min.value, max.value])
40932 .range([min.color, max.color])
40933 .clamp(true); // process a value outside of the domain - set to extremum values
40934 }
40935 LinearGradient2Allocator.prototype.color = function (value) {
40936 var min = this.options.min, max = this.options.max;
40937 if (min.value === max.value) {
40938 if (value >= max.value)
40939 return max.color;
40940 return min.color;
40941 }
40942 return this.scale(value);
40943 };
40944 return LinearGradient2Allocator;
40945 }());
40946 var LinearGradient3Allocator = (function () {
40947 function LinearGradient3Allocator(options) {
40948 debug.assertValue(options, 'options');
40949 this.options = options;
40950 var min = options.min, mid = options.mid, max = options.max;
40951 this.scale = d3.scale.linear()
40952 .domain([min.value, mid.value, max.value])
40953 .range([min.color, mid.color, max.color])
40954 .clamp(true); // process a value outside of the domain- set to extremum values
40955 }
40956 LinearGradient3Allocator.prototype.color = function (value) {
40957 var min = this.options.min, mid = this.options.mid, max = this.options.max;
40958 if (max.value === mid.value || mid.value === min.value || (max.value === mid.value && max.value === min.value)) {
40959 if (value >= max.value)
40960 return max.color;
40961 else if (value >= mid.value)
40962 return mid.color;
40963 return min.color;
40964 }
40965 return this.scale(value);
40966 };
40967 return LinearGradient3Allocator;
40968 }());
40969 var LinearGradient3AllocatorWithSplittedScales = (function () {
40970 function LinearGradient3AllocatorWithSplittedScales(options) {
40971 debug.assertValue(options, 'options');
40972 this.options = options;
40973 var min = options.min, mid = options.mid, max = options.max;
40974 /*
40975 If the center value is overridden, but the max and min remain automatic,
40976 colors are then assigned on a scale between the overridden center value and the max/min values in the data.
40977 Each side of the center value is assigned separately, independent of the relative scales.
40978 */
40979 this.scale1 = d3.scale.linear()
40980 .domain([min.value, mid.value])
40981 .range([min.color, mid.color])
40982 .clamp(true); // process a value outside of the domain- set to extremum values
40983 this.scale2 = d3.scale.linear()
40984 .domain([mid.value, max.value])
40985 .range([mid.color, max.color])
40986 .clamp(true); // process a value outside of the domain- set to extremum values
40987 }
40988 LinearGradient3AllocatorWithSplittedScales.prototype.color = function (value) {
40989 var min = this.options.min, mid = this.options.mid, max = this.options.max;
40990 if (max.value === mid.value || mid.value === min.value || (max.value === mid.value && max.value === min.value)) {
40991 if (value >= max.value)
40992 return max.color;
40993 else if (value >= mid.value)
40994 return mid.color;
40995 return min.color;
40996 }
40997 else if (value <= mid.value) {
40998 return this.scale1(value);
40999 }
41000 return this.scale2(value);
41001 };
41002 return LinearGradient3AllocatorWithSplittedScales;
41003 }());
41004 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
41005})(powerbi || (powerbi = {}));
41006/*
41007 * Power BI Visualizations
41008 *
41009 * Copyright (c) Microsoft Corporation
41010 * All rights reserved.
41011 * MIT License
41012 *
41013 * Permission is hereby granted, free of charge, to any person obtaining a copy
41014 * of this software and associated documentation files (the ""Software""), to deal
41015 * in the Software without restriction, including without limitation the rights
41016 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41017 * copies of the Software, and to permit persons to whom the Software is
41018 * furnished to do so, subject to the following conditions:
41019 *
41020 * The above copyright notice and this permission notice shall be included in
41021 * all copies or substantial portions of the Software.
41022 *
41023 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41024 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41025 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41026 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41027 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41028 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41029 * THE SOFTWARE.
41030 */
41031var powerbi;
41032(function (powerbi) {
41033 var visuals;
41034 (function (visuals) {
41035 var BeautifiedFormat = {
41036 '0.00 %;-0.00 %;0.00 %': 'Percentage',
41037 '0.0 %;-0.0 %;0.0 %': 'Percentage1',
41038 };
41039 var defaultLocalizedStrings = {
41040 'NullValue': '(Blank)',
41041 'BooleanTrue': 'True',
41042 'BooleanFalse': 'False',
41043 'NaNValue': 'NaN',
41044 'InfinityValue': '+Infinity',
41045 'NegativeInfinityValue': '-Infinity',
41046 'Restatement_Comma': '{0}, {1}',
41047 'Restatement_CompoundAnd': '{0} and {1}',
41048 'DisplayUnitSystem_EAuto_Title': 'Auto',
41049 'DisplayUnitSystem_E0_Title': 'None',
41050 'DisplayUnitSystem_E3_LabelFormat': '{0}K',
41051 'DisplayUnitSystem_E3_Title': 'Thousands',
41052 'DisplayUnitSystem_E6_LabelFormat': '{0}M',
41053 'DisplayUnitSystem_E6_Title': 'Millions',
41054 'DisplayUnitSystem_E9_LabelFormat': '{0}bn',
41055 'DisplayUnitSystem_E9_Title': 'Billions',
41056 'DisplayUnitSystem_E12_LabelFormat': '{0}T',
41057 'DisplayUnitSystem_E12_Title': 'Trillions',
41058 'Percentage': '#,0.##%',
41059 'Percentage1': '#,0.#%',
41060 'RichTextbox_Link_DefaultText': 'Link',
41061 'TableTotalLabel': 'Total',
41062 'Tooltip_HighlightedValueDisplayName': 'Highlighted',
41063 'Funnel_PercentOfFirst': 'Percent of first',
41064 'Funnel_PercentOfPrevious': 'Percent of previous',
41065 'Funnel_PercentOfFirst_Highlight': 'Percent of first (highlighted)',
41066 'Funnel_PercentOfPrevious_Highlight': 'Percent of previous (highlighted)',
41067 // Geotagging strings
41068 'GeotaggingString_Continent': 'continent',
41069 'GeotaggingString_Continents': 'continents',
41070 'GeotaggingString_Country': 'country',
41071 'GeotaggingString_Countries': 'countries',
41072 'GeotaggingString_State': 'state',
41073 'GeotaggingString_States': 'states',
41074 'GeotaggingString_City': 'city',
41075 'GeotaggingString_Cities': 'cities',
41076 'GeotaggingString_Town': 'town',
41077 'GeotaggingString_Towns': 'towns',
41078 'GeotaggingString_Province': 'province',
41079 'GeotaggingString_Provinces': 'provinces',
41080 'GeotaggingString_County': 'county',
41081 'GeotaggingString_Counties': 'counties',
41082 'GeotaggingString_Village': 'village',
41083 'GeotaggingString_Villages': 'villages',
41084 'GeotaggingString_Post': 'post',
41085 'GeotaggingString_Zip': 'zip',
41086 'GeotaggingString_Code': 'code',
41087 'GeotaggingString_Place': 'place',
41088 'GeotaggingString_Places': 'places',
41089 'GeotaggingString_Address': 'address',
41090 'GeotaggingString_Addresses': 'addresses',
41091 'GeotaggingString_Street': 'street',
41092 'GeotaggingString_Streets': 'streets',
41093 'GeotaggingString_Longitude': 'longitude',
41094 'GeotaggingString_Longitude_Short': 'lon',
41095 'GeotaggingString_Latitude': 'latitude',
41096 'GeotaggingString_Latitude_Short': 'lat',
41097 'GeotaggingString_PostalCode': 'postal code',
41098 'GeotaggingString_PostalCodes': 'postal codes',
41099 'GeotaggingString_ZipCode': 'zip code',
41100 'GeotaggingString_ZipCodes': 'zip codes',
41101 'GeotaggingString_Territory': 'territory',
41102 'GeotaggingString_Territories': 'territories',
41103 'Waterfall_IncreaseLabel': 'Increase',
41104 'Waterfall_DecreaseLabel': 'Decrease',
41105 'Waterfall_TotalLabel': 'Total',
41106 'Slicer_SelectAll': 'Select All',
41107 };
41108 var DefaultVisualHostServices = (function () {
41109 function DefaultVisualHostServices() {
41110 }
41111 // TODO: Add locale-awareness to this host service. Currently default/english functionality only.
41112 DefaultVisualHostServices.initialize = function () {
41113 visuals.valueFormatter.setLocaleOptions(DefaultVisualHostServices.createLocaleOptions());
41114 visuals.TooltipManager.setLocalizedStrings(DefaultVisualHostServices.createTooltipLocaleOptions());
41115 };
41116 /**
41117 * Create locale options.
41118 *
41119 * Note: Public for testability.
41120 */
41121 DefaultVisualHostServices.createLocaleOptions = function () {
41122 return {
41123 null: defaultLocalizedStrings['NullValue'],
41124 true: defaultLocalizedStrings['BooleanTrue'],
41125 false: defaultLocalizedStrings['BooleanFalse'],
41126 NaN: defaultLocalizedStrings['NaNValue'],
41127 infinity: defaultLocalizedStrings['InfinityValue'],
41128 negativeInfinity: defaultLocalizedStrings['NegativeInfinityValue'],
41129 beautify: function (format) { return DefaultVisualHostServices.beautify(format); },
41130 describe: function (exponent) { return DefaultVisualHostServices.describeUnit(exponent); },
41131 restatementComma: defaultLocalizedStrings['Restatement_Comma'],
41132 restatementCompoundAnd: defaultLocalizedStrings['Restatement_CompoundAnd'],
41133 restatementCompoundOr: defaultLocalizedStrings['Restatement_CompoundOr']
41134 };
41135 };
41136 DefaultVisualHostServices.createTooltipLocaleOptions = function () {
41137 return {
41138 highlightedValueDisplayName: defaultLocalizedStrings['Tooltip_HighlightedValueDisplayName']
41139 };
41140 };
41141 DefaultVisualHostServices.prototype.getLocalizedString = function (stringId) {
41142 return defaultLocalizedStrings[stringId];
41143 };
41144 // NO-OP IHostServices methods
41145 DefaultVisualHostServices.prototype.onDragStart = function () { };
41146 DefaultVisualHostServices.prototype.canSelect = function () { return false; };
41147 DefaultVisualHostServices.prototype.onSelect = function () { };
41148 DefaultVisualHostServices.prototype.onContextMenu = function () { };
41149 DefaultVisualHostServices.prototype.loadMoreData = function () { };
41150 DefaultVisualHostServices.prototype.persistProperties = function (changes) { };
41151 DefaultVisualHostServices.prototype.onCustomSort = function (args) { };
41152 DefaultVisualHostServices.prototype.getViewMode = function () { return 0 /* View */; };
41153 DefaultVisualHostServices.prototype.setWarnings = function (warnings) { };
41154 DefaultVisualHostServices.prototype.setToolbar = function ($toolbar) { };
41155 DefaultVisualHostServices.prototype.shouldRetainSelection = function () { return false; };
41156 DefaultVisualHostServices.prototype.geocoder = function () { return visuals.services.createGeocoder(); };
41157 DefaultVisualHostServices.prototype.geolocation = function () { return visuals.services.createGeolocation(); };
41158 DefaultVisualHostServices.prototype.promiseFactory = function () { return powerbi.createJQueryPromiseFactory(); };
41159 DefaultVisualHostServices.prototype.analyzeFilter = function (options) {
41160 return {
41161 isNotFilter: false,
41162 selectedIdentities: [],
41163 filter: undefined,
41164 defaultValue: undefined,
41165 };
41166 };
41167 DefaultVisualHostServices.prototype.getIdentityDisplayNames = function (dentities) { return; };
41168 DefaultVisualHostServices.prototype.setIdentityDisplayNames = function (displayNamesIdentityPairs) { };
41169 DefaultVisualHostServices.beautify = function (format) {
41170 var key = BeautifiedFormat[format];
41171 if (key)
41172 return defaultLocalizedStrings[key] || format;
41173 return format;
41174 };
41175 DefaultVisualHostServices.describeUnit = function (exponent) {
41176 var exponentLookup = (exponent === -1) ? 'Auto' : exponent.toString();
41177 var title = defaultLocalizedStrings["DisplayUnitSystem_E" + exponentLookup + "_Title"];
41178 var format = (exponent <= 0) ? '{0}' : defaultLocalizedStrings["DisplayUnitSystem_E" + exponentLookup + "_LabelFormat"];
41179 if (title || format)
41180 return { title: title, format: format };
41181 };
41182 return DefaultVisualHostServices;
41183 }());
41184 visuals.DefaultVisualHostServices = DefaultVisualHostServices;
41185 visuals.defaultVisualHostServices = new DefaultVisualHostServices();
41186 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
41187})(powerbi || (powerbi = {}));
41188/*
41189 * Power BI Visualizations
41190 *
41191 * Copyright (c) Microsoft Corporation
41192 * All rights reserved.
41193 * MIT License
41194 *
41195 * Permission is hereby granted, free of charge, to any person obtaining a copy
41196 * of this software and associated documentation files (the ""Software""), to deal
41197 * in the Software without restriction, including without limitation the rights
41198 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41199 * copies of the Software, and to permit persons to whom the Software is
41200 * furnished to do so, subject to the following conditions:
41201 *
41202 * The above copyright notice and this permission notice shall be included in
41203 * all copies or substantial portions of the Software.
41204 *
41205 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41206 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41207 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41208 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41209 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41210 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41211 * THE SOFTWARE.
41212 */
41213var powerbi;
41214(function (powerbi) {
41215 var visuals;
41216 (function (visuals) {
41217 var ArrayExtensions = jsCommon.ArrayExtensions;
41218 /**
41219 * Factory method to create an IInteractivityService instance.
41220 */
41221 function createInteractivityService(hostServices) {
41222 return new InteractivityService(hostServices);
41223 }
41224 visuals.createInteractivityService = createInteractivityService;
41225 /**
41226 * Creates a clear an svg rect to catch clear clicks.
41227 */
41228 function appendClearCatcher(selection) {
41229 return selection
41230 .append("rect")
41231 .classed("clearCatcher", true)
41232 .attr({ width: "100%", height: "100%" });
41233 }
41234 visuals.appendClearCatcher = appendClearCatcher;
41235 function isCategoryColumnSelected(propertyId, categories, idx) {
41236 return categories.objects != null
41237 && categories.objects[idx]
41238 && powerbi.DataViewObjects.getValue(categories.objects[idx], propertyId);
41239 }
41240 visuals.isCategoryColumnSelected = isCategoryColumnSelected;
41241 function dataHasSelection(data) {
41242 for (var i = 0, ilen = data.length; i < ilen; i++) {
41243 if (data[i].selected)
41244 return true;
41245 }
41246 return false;
41247 }
41248 visuals.dataHasSelection = dataHasSelection;
41249 var InteractivityService = (function () {
41250 function InteractivityService(hostServices) {
41251 this.renderSelectionInVisual = _.noop;
41252 this.renderSelectionInLegend = _.noop;
41253 this.renderSelectionInLabels = _.noop;
41254 // Selection state
41255 this.selectedIds = [];
41256 this.isInvertedSelectionMode = false;
41257 debug.assertValue(hostServices, 'hostServices');
41258 this.hostService = hostServices;
41259 }
41260 // IInteractivityService Implementation
41261 /** Binds the vsiual to the interactivityService */
41262 InteractivityService.prototype.bind = function (dataPoints, behavior, behaviorOptions, options) {
41263 var _this = this;
41264 // Bind the data
41265 if (options && options.overrideSelectionFromData) {
41266 // Override selection state from data points if needed
41267 this.takeSelectionStateFromDataPoints(dataPoints);
41268 }
41269 if (options) {
41270 if (options.isLegend) {
41271 // Bind to legend data instead of normal data if isLegend
41272 this.selectableLegendDataPoints = dataPoints;
41273 this.renderSelectionInLegend = function () { return behavior.renderSelection(_this.legendHasSelection()); };
41274 }
41275 else if (options.isLabels) {
41276 //Bind to label data instead of normal data if isLabels
41277 this.selectableLabelsDataPoints = dataPoints;
41278 this.renderSelectionInLabels = function () { return behavior.renderSelection(_this.labelsHasSelection()); };
41279 }
41280 else {
41281 this.selectableDataPoints = dataPoints;
41282 this.renderSelectionInVisual = function () { return behavior.renderSelection(_this.hasSelection()); };
41283 }
41284 if (options.hasSelectionOverride != null) {
41285 this.hasSelectionOverride = options.hasSelectionOverride;
41286 }
41287 if (options.slicerDefaultValueHandler) {
41288 this.slicerDefaultValueHandler = options.slicerDefaultValueHandler;
41289 }
41290 }
41291 else {
41292 this.selectableDataPoints = dataPoints;
41293 this.renderSelectionInVisual = function () { return behavior.renderSelection(_this.hasSelection()); };
41294 }
41295 // Bind to the behavior
41296 this.behavior = behavior;
41297 behavior.bindEvents(behaviorOptions, this);
41298 // Sync data points with current selection state
41299 this.syncSelectionState();
41300 };
41301 /**
41302 * Sets the selected state of all selectable data points to false and invokes the behavior's select command.
41303 */
41304 InteractivityService.prototype.clearSelection = function () {
41305 // if default value is already applied, don't clear the default selection
41306 if (this.slicerDefaultValueHandler && this.slicerDefaultValueHandler.getDefaultValue() && this.useDefaultValue) {
41307 this.isInvertedSelectionMode = false;
41308 return;
41309 }
41310 this.hasSelectionOverride = undefined;
41311 ArrayExtensions.clear(this.selectedIds);
41312 this.isInvertedSelectionMode = false;
41313 this.applyToAllSelectableDataPoints(function (dataPoint) { return dataPoint.selected = false; });
41314 this.renderAll();
41315 };
41316 InteractivityService.prototype.applySelectionStateToData = function (dataPoints) {
41317 for (var _i = 0, dataPoints_2 = dataPoints; _i < dataPoints_2.length; _i++) {
41318 var dataPoint = dataPoints_2[_i];
41319 dataPoint.selected = InteractivityService.checkDatapointAgainstSelectedIds(dataPoint, this.selectedIds);
41320 }
41321 return this.hasSelection();
41322 };
41323 /**
41324 * Checks whether there is at least one item selected.
41325 */
41326 InteractivityService.prototype.hasSelection = function () {
41327 return this.selectedIds.length > 0;
41328 };
41329 InteractivityService.prototype.legendHasSelection = function () {
41330 return this.selectableLegendDataPoints ? dataHasSelection(this.selectableLegendDataPoints) : false;
41331 };
41332 InteractivityService.prototype.labelsHasSelection = function () {
41333 return this.selectableLabelsDataPoints ? dataHasSelection(this.selectableLabelsDataPoints) : false;
41334 };
41335 InteractivityService.prototype.isSelectionModeInverted = function () {
41336 return this.isInvertedSelectionMode;
41337 };
41338 InteractivityService.prototype.setSelectionModeInverted = function (inverted) {
41339 this.isInvertedSelectionMode = inverted;
41340 };
41341 // ISelectionHandler Implementation
41342 InteractivityService.prototype.handleSelection = function (dataPoint, multiSelect) {
41343 // defect 7067397: should not happen so assert but also don't continue as it's
41344 // causing a lot of error telemetry in desktop.
41345 debug.assertValue(dataPoint, 'dataPoint');
41346 if (!dataPoint)
41347 return;
41348 this.useDefaultValue = false;
41349 this.select(dataPoint, multiSelect);
41350 this.sendSelectionToHost();
41351 this.renderAll();
41352 };
41353 InteractivityService.prototype.handleContextMenu = function (dataPoint, point) {
41354 this.sendContextMenuToHost(dataPoint, point);
41355 };
41356 InteractivityService.prototype.handleClearSelection = function () {
41357 this.useDefaultValue = true;
41358 this.clearSelection();
41359 this.sendSelectionToHost();
41360 };
41361 InteractivityService.prototype.toggleSelectionModeInversion = function () {
41362 this.useDefaultValue = false;
41363 this.isInvertedSelectionMode = !this.isInvertedSelectionMode;
41364 ArrayExtensions.clear(this.selectedIds);
41365 this.applyToAllSelectableDataPoints(function (dataPoint) { return dataPoint.selected = false; });
41366 this.sendSelectionToHost();
41367 this.isInvertedSelectionMode ? this.syncSelectionStateInverted() : this.syncSelectionState();
41368 this.renderAll();
41369 return this.isInvertedSelectionMode;
41370 };
41371 InteractivityService.prototype.persistSelectionFilter = function (filterPropertyIdentifier) {
41372 this.hostService.persistProperties(this.createChangeForFilterProperty(filterPropertyIdentifier));
41373 };
41374 InteractivityService.prototype.setDefaultValueMode = function (useDefaultValue) {
41375 this.useDefaultValue = useDefaultValue;
41376 };
41377 InteractivityService.prototype.isDefaultValueEnabled = function () {
41378 return this.useDefaultValue;
41379 };
41380 // Private utility methods
41381 InteractivityService.prototype.renderAll = function () {
41382 this.renderSelectionInVisual();
41383 this.renderSelectionInLegend();
41384 this.renderSelectionInLabels();
41385 };
41386 /** Marks a data point as selected and syncs selection with the host. */
41387 InteractivityService.prototype.select = function (d, multiSelect) {
41388 // If we're in inverted mode, use the invertedSelect instead
41389 if (this.isInvertedSelectionMode) {
41390 return this.selectInverted(d, multiSelect);
41391 }
41392 // For highlight data points we actually want to select the non-highlight data point
41393 if (d.identity.highlight) {
41394 d = _.find(this.selectableDataPoints, function (dp) { return !dp.identity.highlight && d.identity.includes(dp.identity, /* ignoreHighlight */ true); });
41395 debug.assertValue(d, 'Expected to find a non-highlight data point');
41396 }
41397 var id = d.identity;
41398 if (!id)
41399 return;
41400 var selected = !d.selected || (!multiSelect && this.selectedIds.length > 1);
41401 // If we have a multiselect flag, we attempt a multiselect
41402 if (multiSelect) {
41403 if (selected) {
41404 d.selected = true;
41405 this.selectedIds.push(id);
41406 if (id.hasIdentity()) {
41407 this.removeSelectionIdsWithOnlyMeasures();
41408 }
41409 else {
41410 this.removeSelectionIdsExceptOnlyMeasures();
41411 }
41412 }
41413 else {
41414 d.selected = false;
41415 this.removeId(id);
41416 }
41417 }
41418 // We do a single select if we didn't do a multiselect or if we find out that the multiselect is invalid.
41419 if (!multiSelect || !this.hostService.canSelect({ data: this.selectedIds.map(function (value) { return value.getSelector(); }) })) {
41420 this.clearSelection();
41421 if (selected) {
41422 d.selected = true;
41423 this.selectedIds.push(id);
41424 }
41425 }
41426 this.syncSelectionState();
41427 };
41428 InteractivityService.prototype.selectInverted = function (d, multiSelect) {
41429 var wasSelected = d.selected;
41430 var id = d.identity;
41431 debug.assert(!!multiSelect, "inverted selections are only supported in multiselect mode");
41432 // the current datapoint state has to be inverted
41433 d.selected = !wasSelected;
41434 if (wasSelected) {
41435 this.removeId(id);
41436 }
41437 else {
41438 this.selectedIds.push(id);
41439 if (id.hasIdentity()) {
41440 this.removeSelectionIdsWithOnlyMeasures();
41441 }
41442 else {
41443 this.removeSelectionIdsExceptOnlyMeasures();
41444 }
41445 }
41446 this.syncSelectionStateInverted();
41447 };
41448 InteractivityService.prototype.removeId = function (toRemove) {
41449 var selectedIds = this.selectedIds;
41450 for (var i = selectedIds.length - 1; i > -1; i--) {
41451 var currentId = selectedIds[i];
41452 if (toRemove.includes(currentId))
41453 selectedIds.splice(i, 1);
41454 }
41455 };
41456 /** Note: Public for UnitTesting */
41457 InteractivityService.prototype.createChangeForFilterProperty = function (filterPropertyIdentifier) {
41458 var properties = {};
41459 var selectors = [];
41460 if (this.selectedIds.length > 0) {
41461 selectors = _.chain(this.selectedIds)
41462 .filter(function (value) { return value.hasIdentity(); })
41463 .map(function (value) { return value.getSelector(); })
41464 .value();
41465 }
41466 var instance = {
41467 objectName: filterPropertyIdentifier.objectName,
41468 selector: undefined,
41469 properties: properties
41470 };
41471 var filter = powerbi.data.Selector.filterFromSelector(selectors, this.isInvertedSelectionMode);
41472 if (this.slicerDefaultValueHandler && this.slicerDefaultValueHandler.getDefaultValue()) {
41473 // we explicitly check for true/false because undefine means no default value
41474 if (this.useDefaultValue === true)
41475 filter = powerbi.data.SemanticFilter.getDefaultValueFilter(this.slicerDefaultValueHandler.getIdentityFields());
41476 else if (_.isEmpty(selectors))
41477 filter = powerbi.data.SemanticFilter.getAnyValueFilter(this.slicerDefaultValueHandler.getIdentityFields());
41478 }
41479 if (filter == null) {
41480 properties[filterPropertyIdentifier.propertyName] = {};
41481 return {
41482 remove: [instance]
41483 };
41484 }
41485 else {
41486 properties[filterPropertyIdentifier.propertyName] = filter;
41487 return {
41488 merge: [instance]
41489 };
41490 }
41491 };
41492 InteractivityService.prototype.sendContextMenuToHost = function (dataPoint, position) {
41493 var host = this.hostService;
41494 if (!host.onContextMenu)
41495 return;
41496 var selectors = this.getSelectorsByColumn([dataPoint.identity]);
41497 if (_.isEmpty(selectors))
41498 return;
41499 var args = {
41500 data: selectors,
41501 position: position
41502 };
41503 host.onContextMenu(args);
41504 };
41505 InteractivityService.prototype.sendSelectionToHost = function () {
41506 var host = this.hostService;
41507 if (host.onSelect) {
41508 var selectArgs = {
41509 data: this.selectedIds.filter(function (value) { return value.hasIdentity(); }).map(function (value) { return value.getSelector(); })
41510 };
41511 var data2 = this.getSelectorsByColumn(this.selectedIds);
41512 if (!_.isEmpty(data2))
41513 selectArgs.data2 = data2;
41514 host.onSelect(selectArgs);
41515 }
41516 };
41517 InteractivityService.prototype.getSelectorsByColumn = function (selectionIds) {
41518 return _(selectionIds)
41519 .filter(function (value) { return value.hasIdentity; })
41520 .map(function (value) { return value.getSelectorsByColumn(); })
41521 .compact()
41522 .value();
41523 };
41524 InteractivityService.prototype.takeSelectionStateFromDataPoints = function (dataPoints) {
41525 debug.assertValue(dataPoints, "dataPoints");
41526 var selectedIds = this.selectedIds;
41527 // Replace the existing selectedIds rather than merging.
41528 ArrayExtensions.clear(selectedIds);
41529 for (var _i = 0, dataPoints_3 = dataPoints; _i < dataPoints_3.length; _i++) {
41530 var dataPoint = dataPoints_3[_i];
41531 if (dataPoint.selected)
41532 selectedIds.push(dataPoint.identity);
41533 }
41534 };
41535 /**
41536 * Syncs the selection state for all data points that have the same category. Returns
41537 * true if the selection state was out of sync and corrections were made; false if
41538 * the data is already in sync with the service.
41539 *
41540 * If the data is not compatible with the current service's current selection state,
41541 * the state is cleared and the cleared selection is sent to the host.
41542 *
41543 * Ignores series for now, since we don't support series selection at the moment.
41544 */
41545 InteractivityService.prototype.syncSelectionState = function () {
41546 if (this.isInvertedSelectionMode) {
41547 return this.syncSelectionStateInverted();
41548 }
41549 var selectedIds = this.selectedIds;
41550 var selectableDataPoints = this.selectableDataPoints;
41551 var selectableLegendDataPoints = this.selectableLegendDataPoints;
41552 var selectableLabelsDataPoints = this.selectableLabelsDataPoints;
41553 var foundMatchingId = false; // Checked only against the visual's data points; it's possible to have stuff selected in the visual that's not in the legend, but not vice-verse
41554 if (!selectableDataPoints && !selectableLegendDataPoints)
41555 return;
41556 if (selectableDataPoints) {
41557 if (InteractivityService.updateSelectableDataPointsBySelectedIds(selectableDataPoints, selectedIds))
41558 foundMatchingId = true;
41559 }
41560 if (selectableLegendDataPoints) {
41561 if (InteractivityService.updateSelectableDataPointsBySelectedIds(selectableLegendDataPoints, selectedIds))
41562 foundMatchingId = true;
41563 }
41564 if (selectableLabelsDataPoints) {
41565 var labelsDataPoint_1;
41566 for (var i = 0, ilen = selectableLabelsDataPoints.length; i < ilen; i++) {
41567 labelsDataPoint_1 = selectableLabelsDataPoints[i];
41568 if (selectedIds.some(function (value) { return value.includes(labelsDataPoint_1.identity); }))
41569 labelsDataPoint_1.selected = true;
41570 else
41571 labelsDataPoint_1.selected = false;
41572 }
41573 }
41574 if (!foundMatchingId && selectedIds.length > 0) {
41575 this.clearSelection();
41576 this.sendSelectionToHost();
41577 }
41578 };
41579 InteractivityService.prototype.syncSelectionStateInverted = function () {
41580 var selectedIds = this.selectedIds;
41581 var selectableDataPoints = this.selectableDataPoints;
41582 if (!selectableDataPoints)
41583 return;
41584 if (selectedIds.length === 0) {
41585 for (var _i = 0, selectableDataPoints_1 = selectableDataPoints; _i < selectableDataPoints_1.length; _i++) {
41586 var dataPoint_1 = selectableDataPoints_1[_i];
41587 dataPoint_1.selected = false;
41588 }
41589 }
41590 else {
41591 for (var _a = 0, selectableDataPoints_2 = selectableDataPoints; _a < selectableDataPoints_2.length; _a++) {
41592 var dataPoint = selectableDataPoints_2[_a];
41593 if (selectedIds.some(function (value) { return value.includes(dataPoint.identity); }))
41594 dataPoint.selected = true;
41595 else if (dataPoint.selected)
41596 dataPoint.selected = false;
41597 }
41598 }
41599 };
41600 InteractivityService.prototype.applyToAllSelectableDataPoints = function (action) {
41601 var selectableDataPoints = this.selectableDataPoints;
41602 var selectableLegendDataPoints = this.selectableLegendDataPoints;
41603 var selectableLabelsDataPoints = this.selectableLabelsDataPoints;
41604 if (selectableDataPoints) {
41605 for (var _i = 0, selectableDataPoints_3 = selectableDataPoints; _i < selectableDataPoints_3.length; _i++) {
41606 var dataPoint = selectableDataPoints_3[_i];
41607 action(dataPoint);
41608 }
41609 }
41610 if (selectableLegendDataPoints) {
41611 for (var _a = 0, selectableLegendDataPoints_1 = selectableLegendDataPoints; _a < selectableLegendDataPoints_1.length; _a++) {
41612 var dataPoint = selectableLegendDataPoints_1[_a];
41613 action(dataPoint);
41614 }
41615 }
41616 if (selectableLabelsDataPoints) {
41617 for (var _b = 0, selectableLabelsDataPoints_1 = selectableLabelsDataPoints; _b < selectableLabelsDataPoints_1.length; _b++) {
41618 var dataPoint = selectableLabelsDataPoints_1[_b];
41619 action(dataPoint);
41620 }
41621 }
41622 };
41623 InteractivityService.updateSelectableDataPointsBySelectedIds = function (selectableDataPoints, selectedIds) {
41624 var foundMatchingId = false;
41625 for (var _i = 0, selectableDataPoints_4 = selectableDataPoints; _i < selectableDataPoints_4.length; _i++) {
41626 var datapoint = selectableDataPoints_4[_i];
41627 datapoint.selected = InteractivityService.checkDatapointAgainstSelectedIds(datapoint, selectedIds);
41628 if (datapoint.selected)
41629 foundMatchingId = true;
41630 }
41631 return foundMatchingId;
41632 };
41633 InteractivityService.checkDatapointAgainstSelectedIds = function (datapoint, selectedIds) {
41634 return selectedIds.some(function (value) { return value.includes(datapoint.identity); });
41635 };
41636 InteractivityService.prototype.removeSelectionIdsWithOnlyMeasures = function () {
41637 this.selectedIds = _.filter(this.selectedIds, function (identity) { return identity.hasIdentity(); });
41638 };
41639 InteractivityService.prototype.removeSelectionIdsExceptOnlyMeasures = function () {
41640 this.selectedIds = _.filter(this.selectedIds, function (identity) { return !identity.hasIdentity(); });
41641 };
41642 return InteractivityService;
41643 }());
41644 visuals.InteractivityService = InteractivityService;
41645 ;
41646 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
41647})(powerbi || (powerbi = {}));
41648/*
41649 * Power BI Visualizations
41650 *
41651 * Copyright (c) Microsoft Corporation
41652 * All rights reserved.
41653 * MIT License
41654 *
41655 * Permission is hereby granted, free of charge, to any person obtaining a copy
41656 * of this software and associated documentation files (the ""Software""), to deal
41657 * in the Software without restriction, including without limitation the rights
41658 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41659 * copies of the Software, and to permit persons to whom the Software is
41660 * furnished to do so, subject to the following conditions:
41661 *
41662 * The above copyright notice and this permission notice shall be included in
41663 * all copies or substantial portions of the Software.
41664 *
41665 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41666 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41667 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41668 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41669 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41670 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41671 * THE SOFTWARE.
41672 */
41673var powerbi;
41674(function (powerbi) {
41675 var visuals;
41676 (function (visuals) {
41677 var services;
41678 (function (services) {
41679 var CategoryTypes = visuals.MapUtil.CategoryTypes;
41680 var Settings = visuals.MapUtil.Settings;
41681 function createGeocoder() {
41682 return {
41683 geocode: geocode,
41684 geocodeBoundary: geocodeBoundary,
41685 geocodePoint: geocodePoint,
41686 tryGeocodeImmediate: tryGeocodeImmediate,
41687 tryGeocodeBoundaryImmediate: tryGeocodeBoundaryImmediate,
41688 };
41689 }
41690 services.createGeocoder = createGeocoder;
41691 services.safeCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
41692 /** Note: Used for test mockup */
41693 services.BingAjaxCall = $.ajax;
41694 services.CategoryTypeArray = [
41695 "Address",
41696 "City",
41697 "Continent",
41698 "Country",
41699 "County",
41700 "Longitude",
41701 "Latitude",
41702 "Place",
41703 "PostalCode",
41704 "StateOrProvince"
41705 ];
41706 function isCategoryType(value) {
41707 return services.CategoryTypeArray.indexOf(value) > -1;
41708 }
41709 services.isCategoryType = isCategoryType;
41710 services.BingEntities = {
41711 Continent: "Continent",
41712 Sovereign: "Sovereign",
41713 CountryRegion: "CountryRegion",
41714 AdminDivision1: "AdminDivision1",
41715 AdminDivision2: "AdminDivision2",
41716 PopulatedPlace: "PopulatedPlace",
41717 Postcode: "Postcode",
41718 Postcode1: "Postcode1",
41719 Neighborhood: "Neighborhood",
41720 Address: "Address",
41721 };
41722 // Static variables for caching, maps, etc.
41723 var geocodeQueue;
41724 var activeRequests;
41725 var categoryToBingEntity;
41726 var categoryToBingEntityGeodata;
41727 var geocodingCache;
41728 var GeocodeQuery = (function () {
41729 function GeocodeQuery(query, category) {
41730 this.query = query != null ? query : "";
41731 this.category = category != null ? category : "";
41732 this.key = (this.query + "/" + this.category).toLowerCase();
41733 if (!geocodingCache) {
41734 geocodingCache = services.createGeocodingCache(Settings.MaxCacheSize, Settings.MaxCacheSizeOverflow);
41735 }
41736 }
41737 GeocodeQuery.prototype.getBingEntity = function () {
41738 var category = this.category.toLowerCase();
41739 if (!categoryToBingEntity) {
41740 categoryToBingEntity = {};
41741 categoryToBingEntity[CategoryTypes.Continent.toLowerCase()] = services.BingEntities.Continent;
41742 categoryToBingEntity[CategoryTypes.CountryRegion.toLowerCase()] = services.BingEntities.Sovereign;
41743 categoryToBingEntity[CategoryTypes.StateOrProvince.toLowerCase()] = services.BingEntities.AdminDivision1;
41744 categoryToBingEntity[CategoryTypes.County.toLowerCase()] = services.BingEntities.AdminDivision2;
41745 categoryToBingEntity[CategoryTypes.City.toLowerCase()] = services.BingEntities.PopulatedPlace;
41746 categoryToBingEntity[CategoryTypes.PostalCode.toLowerCase()] = services.BingEntities.Postcode;
41747 categoryToBingEntity[CategoryTypes.Address.toLowerCase()] = services.BingEntities.Address;
41748 }
41749 return categoryToBingEntity[category] || "";
41750 };
41751 GeocodeQuery.prototype.getUrl = function () {
41752 var url = Settings.BingUrl + "?key=" + Settings.BingKey;
41753 var entityType = this.getBingEntity();
41754 var queryAdded = false;
41755 if (entityType) {
41756 if (entityType === services.BingEntities.Postcode) {
41757 url += "&includeEntityTypes=Postcode,Postcode1,Postcode2,Postcode3,Postcode4";
41758 }
41759 else if (this.query.indexOf(",") === -1 && (entityType === services.BingEntities.AdminDivision1 || entityType === services.BingEntities.AdminDivision2)) {
41760 queryAdded = true;
41761 try {
41762 url += "&adminDistrict=" + decodeURIComponent(this.query);
41763 }
41764 catch (e) {
41765 return null;
41766 }
41767 }
41768 else {
41769 url += "&includeEntityTypes=" + entityType;
41770 }
41771 }
41772 if (!queryAdded) {
41773 try {
41774 url += "&q=" + decodeURIComponent(this.query);
41775 }
41776 catch (e) {
41777 return null;
41778 }
41779 }
41780 var cultureName = navigator.userLanguage || navigator["language"];
41781 cultureName = mapLocalesForBing(cultureName);
41782 if (cultureName) {
41783 url += "&c=" + cultureName;
41784 }
41785 url += "&maxRes=20";
41786 // If the query is of length 2, request the ISO 2-letter country code to be returned with the result to be compared against the query so that such results can be preferred.
41787 if (this.query.length === 2 && this.category === CategoryTypes.CountryRegion) {
41788 url += "&include=ciso2";
41789 }
41790 return url;
41791 };
41792 return GeocodeQuery;
41793 }());
41794 services.GeocodeQuery = GeocodeQuery;
41795 var GeocodePointQuery = (function (_super) {
41796 __extends(GeocodePointQuery, _super);
41797 function GeocodePointQuery(latitude, longitude) {
41798 _super.call(this, [latitude, longitude].join(), "Point");
41799 this.latitude = latitude;
41800 this.longitude = longitude;
41801 }
41802 GeocodePointQuery.prototype.getUrl = function () {
41803 var url = Settings.BingUrl + "/" +
41804 [this.latitude, this.longitude].join() + "?" +
41805 "key=" + Settings.BingKey +
41806 "&includeEntityTypes=" + [
41807 services.BingEntities.Address,
41808 services.BingEntities.Neighborhood,
41809 services.BingEntities.PopulatedPlace,
41810 services.BingEntities.Postcode1,
41811 services.BingEntities.AdminDivision1,
41812 services.BingEntities.AdminDivision2,
41813 services.BingEntities.CountryRegion].join() +
41814 "&include=ciso2";
41815 return url;
41816 };
41817 return GeocodePointQuery;
41818 }(GeocodeQuery));
41819 services.GeocodePointQuery = GeocodePointQuery;
41820 var GeocodeBoundaryQuery = (function (_super) {
41821 __extends(GeocodeBoundaryQuery, _super);
41822 function GeocodeBoundaryQuery(latitude, longitude, category, levelOfDetail, maxGeoData) {
41823 if (maxGeoData === void 0) { maxGeoData = 3; }
41824 _super.call(this, [latitude, longitude, levelOfDetail, maxGeoData].join(","), category);
41825 this.latitude = latitude;
41826 this.longitude = longitude;
41827 this.levelOfDetail = levelOfDetail;
41828 this.maxGeoData = maxGeoData;
41829 }
41830 GeocodeBoundaryQuery.prototype.getBingEntity = function () {
41831 var category = this.category.toLowerCase();
41832 if (!categoryToBingEntityGeodata) {
41833 categoryToBingEntityGeodata = {};
41834 categoryToBingEntityGeodata[CategoryTypes.CountryRegion.toLowerCase()] = services.BingEntities.CountryRegion;
41835 categoryToBingEntityGeodata[CategoryTypes.StateOrProvince.toLowerCase()] = services.BingEntities.AdminDivision1;
41836 categoryToBingEntityGeodata[CategoryTypes.County.toLowerCase()] = services.BingEntities.AdminDivision2;
41837 categoryToBingEntityGeodata[CategoryTypes.City.toLowerCase()] = services.BingEntities.PopulatedPlace;
41838 categoryToBingEntityGeodata[CategoryTypes.PostalCode.toLowerCase()] = services.BingEntities.Postcode1;
41839 }
41840 return categoryToBingEntityGeodata[category] || "";
41841 };
41842 GeocodeBoundaryQuery.prototype.getUrl = function () {
41843 var url = Settings.BingUrlGeodata + "key=" + Settings.BingKey + "&$format=json";
41844 var entityType = this.getBingEntity();
41845 if (!entityType) {
41846 return null;
41847 }
41848 var cultureName = navigator.userLanguage || navigator["language"];
41849 cultureName = mapLocalesForBing(cultureName);
41850 var cultures = cultureName.split("-");
41851 var data = [this.latitude, this.longitude, this.levelOfDetail, "'" + entityType + "'", 1, 0, "'" + cultureName + "'"];
41852 if (cultures.length > 1) {
41853 data.push("'" + cultures[1] + "'");
41854 }
41855 return url + "&SpatialFilter=GetBoundary(" + data.join(", ") + ")";
41856 };
41857 return GeocodeBoundaryQuery;
41858 }(GeocodeQuery));
41859 services.GeocodeBoundaryQuery = GeocodeBoundaryQuery;
41860 /**
41861 * Map locales that cause failures to similar locales that work
41862 */
41863 function mapLocalesForBing(locale) {
41864 switch (locale.toLowerCase()) {
41865 case 'fr':
41866 return 'fr-FR';
41867 default:
41868 return locale;
41869 }
41870 }
41871 function tryGeocodeImmediate(query, category) {
41872 var result = geocodingCache ? geocodingCache.getCoordinates(new GeocodeQuery(query, category).key) : undefined;
41873 return result;
41874 }
41875 function tryGeocodeBoundaryImmediate(latitude, longitude, category, levelOfDetail, maxGeoData) {
41876 if (maxGeoData === void 0) { maxGeoData = 3; }
41877 var result = geocodingCache ? geocodingCache.getCoordinates(new GeocodeBoundaryQuery(latitude, longitude, category, levelOfDetail, maxGeoData).key) : undefined;
41878 return result;
41879 }
41880 function geocodeCore(geocodeQuery) {
41881 var result = geocodingCache ? geocodingCache.getCoordinates(geocodeQuery.key) : undefined;
41882 var deferred = $.Deferred();
41883 if (result) {
41884 deferred.resolve(result);
41885 }
41886 else {
41887 geocodeQueue.push({ query: geocodeQuery, deferred: deferred });
41888 dequeue();
41889 }
41890 return deferred;
41891 }
41892 services.geocodeCore = geocodeCore;
41893 function geocode(query, category) {
41894 if (category === void 0) { category = ""; }
41895 return geocodeCore(new GeocodeQuery(query, category));
41896 }
41897 services.geocode = geocode;
41898 function geocodeBoundary(latitude, longitude, category, levelOfDetail, maxGeoData) {
41899 if (category === void 0) { category = ""; }
41900 if (levelOfDetail === void 0) { levelOfDetail = 2; }
41901 if (maxGeoData === void 0) { maxGeoData = 3; }
41902 return geocodeCore(new GeocodeBoundaryQuery(latitude, longitude, category, levelOfDetail, maxGeoData));
41903 }
41904 services.geocodeBoundary = geocodeBoundary;
41905 function geocodePoint(latitude, longitude) {
41906 return geocodeCore(new GeocodePointQuery(latitude, longitude));
41907 }
41908 services.geocodePoint = geocodePoint;
41909 function dequeue(decrement) {
41910 if (decrement === void 0) { decrement = 0; }
41911 activeRequests -= decrement;
41912 while (activeRequests < Settings.MaxBingRequest) {
41913 if (geocodeQueue.length === 0) {
41914 break;
41915 }
41916 activeRequests++;
41917 makeRequest(geocodeQueue.shift());
41918 }
41919 }
41920 function makeRequest(item) {
41921 // Check again if we already got the coordinate;
41922 var result = geocodingCache ? geocodingCache.getCoordinates(item.query.key) : undefined;
41923 if (result) {
41924 setTimeout(function () { return dequeue(1); });
41925 item.deferred.resolve(result);
41926 return;
41927 }
41928 // Unfortunately the Bing service doesn't support CORS, only jsonp. This issue must be raised and revised.
41929 // VSTS: 1396088 - Tracking: Ask: Bing geocoding to support CORS
41930 var config = {
41931 type: "GET",
41932 dataType: "jsonp",
41933 jsonp: "jsonp"
41934 };
41935 var url = item.query.getUrl();
41936 if (!url) {
41937 completeRequest(item, new Error("Unsupported query. " + item.query.query));
41938 }
41939 services.BingAjaxCall(url, config).then(function (data) {
41940 try {
41941 if (item.query instanceof GeocodeBoundaryQuery) {
41942 var result_1 = data;
41943 if (result_1 && result_1.d && Array.isArray(result_1.d.results) && result_1.d.results.length > 0) {
41944 var entity = result_1.d.results[0];
41945 var primitives = entity.Primitives;
41946 if (primitives && primitives.length > 0) {
41947 var coordinates = {
41948 latitude: item.query.latitude,
41949 longitude: item.query.longitude,
41950 locations: []
41951 };
41952 primitives.sort(function (a, b) {
41953 if (a.Shape.length < b.Shape.length) {
41954 return 1;
41955 }
41956 if (a.Shape.length > b.Shape.length) {
41957 return -1;
41958 }
41959 return 0;
41960 });
41961 var maxGeoData = Math.min(primitives.length, item.query.maxGeoData);
41962 for (var i = 0; i < maxGeoData; i++) {
41963 var ringStr = primitives[i].Shape;
41964 var ringArray = ringStr.split(",");
41965 for (var j = 1; j < ringArray.length; j++) {
41966 coordinates.locations.push({ nativeBing: ringArray[j] });
41967 }
41968 }
41969 completeRequest(item, null, coordinates);
41970 }
41971 else {
41972 completeRequest(item, new Error("Geocode result is empty."));
41973 }
41974 }
41975 else {
41976 completeRequest(item, new Error("Geocode result is empty."));
41977 }
41978 }
41979 else if (item.query instanceof GeocodePointQuery) {
41980 var resources = data.resourceSets[0].resources;
41981 if (Array.isArray(resources) && resources.length > 0) {
41982 var index = getBestResultIndex(resources, item.query);
41983 var pointData = resources[index].point.coordinates;
41984 var addressData = resources[index].address;
41985 var coordinates = {
41986 latitude: parseFloat(pointData[0]),
41987 longitude: parseFloat(pointData[1]),
41988 addressLine: addressData.addressLine,
41989 locality: addressData.locality,
41990 neighborhood: addressData.neighborhood,
41991 adminDistrict: addressData.adminDistrict,
41992 adminDistrict2: addressData.adminDistrict2,
41993 formattedAddress: addressData.formattedAddress,
41994 postalCode: addressData.postalCode,
41995 countryRegionIso2: addressData.countryRegionIso2,
41996 countryRegion: addressData.countryRegion,
41997 landmark: addressData.landmark,
41998 };
41999 completeRequest(item, null, coordinates);
42000 }
42001 else {
42002 completeRequest(item, new Error("Geocode result is empty."));
42003 }
42004 }
42005 else {
42006 var resources = data.resourceSets[0].resources;
42007 if (Array.isArray(resources) && resources.length > 0) {
42008 var index = getBestResultIndex(resources, item.query);
42009 var pointData = resources[index].point.coordinates;
42010 var coordinates = {
42011 latitude: parseFloat(pointData[0]),
42012 longitude: parseFloat(pointData[1])
42013 };
42014 completeRequest(item, null, coordinates);
42015 }
42016 else {
42017 completeRequest(item, new Error("Geocode result is empty."));
42018 }
42019 }
42020 }
42021 catch (error) {
42022 completeRequest(item, error);
42023 }
42024 }, function (error) {
42025 completeRequest(item, error);
42026 });
42027 }
42028 var dequeueTimeoutId;
42029 function completeRequest(item, error, coordinate) {
42030 if (coordinate === void 0) { coordinate = null; }
42031 dequeueTimeoutId = setTimeout(function () { return dequeue(1); }, Settings.UseDoubleArrayGeodataResult ? Settings.UseDoubleArrayDequeueTimeout : 0);
42032 if (error) {
42033 item.deferred.reject(error);
42034 }
42035 else {
42036 if (geocodingCache && !(item.query instanceof GeocodePointQuery))
42037 geocodingCache.registerCoordinates(item.query.key, coordinate);
42038 item.deferred.resolve(coordinate);
42039 }
42040 }
42041 function getBestResultIndex(resources, query) {
42042 var queryString = query.query.toLowerCase();
42043 // If string is of length 2 and is a country, check against the ISO country code of results, prefering exact matches
42044 if (queryString.length === 2 && query.category === CategoryTypes.CountryRegion) {
42045 for (var index = 0; index < resources.length; index++) {
42046 var iso2 = resources[index].address && resources[index].address.countryRegionIso2;
42047 if (iso2 && queryString === iso2.toLowerCase()) {
42048 return index;
42049 }
42050 }
42051 }
42052 // Prefer results that match the targetEntity (geotagged category) on the query
42053 var targetEntity = query.getBingEntity().toLowerCase();
42054 for (var index = 0; index < resources.length; index++) {
42055 var resultEntity = (resources[index].entityType || "").toLowerCase();
42056 if (resultEntity === targetEntity) {
42057 return index;
42058 }
42059 }
42060 return 0;
42061 }
42062 function reset() {
42063 geocodeQueue = [];
42064 activeRequests = 0;
42065 categoryToBingEntity = null;
42066 clearTimeout(dequeueTimeoutId);
42067 }
42068 services.reset = reset;
42069 reset();
42070 })(services = visuals.services || (visuals.services = {}));
42071 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
42072})(powerbi || (powerbi = {}));
42073/*
42074 * Power BI Visualizations
42075 *
42076 * Copyright (c) Microsoft Corporation
42077 * All rights reserved.
42078 * MIT License
42079 *
42080 * Permission is hereby granted, free of charge, to any person obtaining a copy
42081 * of this software and associated documentation files (the ""Software""), to deal
42082 * in the Software without restriction, including without limitation the rights
42083 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42084 * copies of the Software, and to permit persons to whom the Software is
42085 * furnished to do so, subject to the following conditions:
42086 *
42087 * The above copyright notice and this permission notice shall be included in
42088 * all copies or substantial portions of the Software.
42089 *
42090 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42091 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42092 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42093 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42094 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42095 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42096 * THE SOFTWARE.
42097 */
42098var powerbi;
42099(function (powerbi) {
42100 var visuals;
42101 (function (visuals) {
42102 var services;
42103 (function (services) {
42104 function createGeocodingCache(maxCacheSize, maxCacheSizeOverflow, localStorageService) {
42105 if (!localStorageService)
42106 localStorageService = powerbi.localStorageService;
42107 return new GeocodingCache(maxCacheSize, maxCacheSizeOverflow, localStorageService);
42108 }
42109 services.createGeocodingCache = createGeocodingCache;
42110 var GeocodingCache = (function () {
42111 function GeocodingCache(maxCacheSize, maxCacheSizeOverflow, localStorageService) {
42112 this.geocodeCache = {};
42113 this.geocodeCacheCount = 0;
42114 this.maxCacheSize = maxCacheSize;
42115 this.maxCacheSizeOverflow = maxCacheSizeOverflow;
42116 this.localStorageService = localStorageService;
42117 }
42118 /**
42119 * Retrieves the coordinate for the key from the cache, returning undefined on a cache miss.
42120 */
42121 GeocodingCache.prototype.getCoordinates = function (key) {
42122 // Check in-memory cache
42123 var pair = this.geocodeCache[key];
42124 if (pair) {
42125 ++pair.hitCount;
42126 return pair.coordinate;
42127 }
42128 // Check local storage cache
42129 pair = this.localStorageService.getData(key);
42130 if (pair) {
42131 this.registerInMemory(key, pair.coordinate);
42132 return pair.coordinate;
42133 }
42134 return undefined;
42135 };
42136 /**
42137 * Registers the query and coordinate to the cache.
42138 */
42139 GeocodingCache.prototype.registerCoordinates = function (key, coordinate) {
42140 this.registerInMemory(key, coordinate);
42141 this.registerInStorage(key, coordinate);
42142 };
42143 GeocodingCache.prototype.registerInMemory = function (key, coordinate) {
42144 var geocodeCache = this.geocodeCache;
42145 var maxCacheSize = this.maxCacheSize;
42146 var maxCacheCount = maxCacheSize + this.maxCacheSizeOverflow;
42147 // are we about to exceed the maximum?
42148 if (this.geocodeCacheCount >= maxCacheCount) {
42149 var keys = Object.keys(geocodeCache);
42150 var cacheSize = keys.length;
42151 // sort keys in *descending* hitCount order
42152 keys.sort(function (a, b) {
42153 var cachedA = geocodeCache[a];
42154 var cachedB = geocodeCache[b];
42155 var ca = cachedA ? cachedA.hitCount : 0;
42156 var cb = cachedB ? cachedB.hitCount : 0;
42157 return ca < cb ? 1 : (ca > cb ? -1 : 0);
42158 });
42159 // whack ones with the lower hitCounts.
42160 // - while # whacked keys is small, do a quick wipe
42161 // - after awhile we get lots of keys whose cached value is undefined.
42162 // when there are "too many," make a whole new memory cache.
42163 if (cacheSize < 2 * maxCacheCount) {
42164 for (var i = maxCacheSize; i < cacheSize; i++)
42165 geocodeCache[keys[i]] = undefined;
42166 }
42167 else {
42168 var newGeocodeCache = {};
42169 for (var i = 0; i < maxCacheSize; ++i)
42170 newGeocodeCache[keys[i]] = geocodeCache[keys[i]];
42171 geocodeCache = this.geocodeCache = newGeocodeCache;
42172 }
42173 this.geocodeCacheCount = maxCacheSize;
42174 }
42175 geocodeCache[key] = { key: key, coordinate: coordinate, hitCount: 1 };
42176 ++this.geocodeCacheCount;
42177 };
42178 GeocodingCache.prototype.registerInStorage = function (key, coordinate) {
42179 this.localStorageService.setData(key, { coordinate: coordinate });
42180 };
42181 return GeocodingCache;
42182 }());
42183 })(services = visuals.services || (visuals.services = {}));
42184 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
42185})(powerbi || (powerbi = {}));
42186/*
42187 * Power BI Visualizations
42188 *
42189 * Copyright (c) Microsoft Corporation
42190 * All rights reserved.
42191 * MIT License
42192 *
42193 * Permission is hereby granted, free of charge, to any person obtaining a copy
42194 * of this software and associated documentation files (the ""Software""), to deal
42195 * in the Software without restriction, including without limitation the rights
42196 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42197 * copies of the Software, and to permit persons to whom the Software is
42198 * furnished to do so, subject to the following conditions:
42199 *
42200 * The above copyright notice and this permission notice shall be included in
42201 * all copies or substantial portions of the Software.
42202 *
42203 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42204 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42205 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42206 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42207 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42208 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42209 * THE SOFTWARE.
42210 */
42211var powerbi;
42212(function (powerbi) {
42213 var visuals;
42214 (function (visuals) {
42215 var services;
42216 (function (services) {
42217 function createGeolocation() {
42218 return new GeolocationService();
42219 }
42220 services.createGeolocation = createGeolocation;
42221 /**
42222 * HTML5 Implementation of IGeolocation
42223 */
42224 var GeolocationService = (function () {
42225 function GeolocationService() {
42226 this.webGeolocation = navigator.geolocation;
42227 }
42228 GeolocationService.prototype.watchPosition = function (successCallback, errorCallback) {
42229 return this.webGeolocation.watchPosition(function (position) {
42230 successCallback(position);
42231 }, function (error) {
42232 if (errorCallback != null) {
42233 errorCallback(error);
42234 }
42235 });
42236 };
42237 GeolocationService.prototype.clearWatch = function (watchId) {
42238 this.webGeolocation.clearWatch(watchId);
42239 };
42240 GeolocationService.prototype.getCurrentPosition = function (successCallback, errorCallback) {
42241 this.webGeolocation.getCurrentPosition(function (position) {
42242 successCallback(position);
42243 }, function (error) {
42244 if (errorCallback != null) {
42245 errorCallback(error);
42246 }
42247 });
42248 };
42249 return GeolocationService;
42250 }());
42251 })(services = visuals.services || (visuals.services = {}));
42252 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
42253})(powerbi || (powerbi = {}));
42254/*
42255 * Power BI Visualizations
42256 *
42257 * Copyright (c) Microsoft Corporation
42258 * All rights reserved.
42259 * MIT License
42260 *
42261 * Permission is hereby granted, free of charge, to any person obtaining a copy
42262 * of this software and associated documentation files (the ""Software""), to deal
42263 * in the Software without restriction, including without limitation the rights
42264 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42265 * copies of the Software, and to permit persons to whom the Software is
42266 * furnished to do so, subject to the following conditions:
42267 *
42268 * The above copyright notice and this permission notice shall be included in
42269 * all copies or substantial portions of the Software.
42270 *
42271 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42272 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42273 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42274 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42275 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42276 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42277 * THE SOFTWARE.
42278 */
42279var powerbi;
42280(function (powerbi) {
42281 var visuals;
42282 (function (visuals) {
42283 var unsupportedVisuals = ['play', 'subview', 'smallMultiple'];
42284 var visualPluginFactory;
42285 (function (visualPluginFactory) {
42286 var VisualPluginService = (function () {
42287 function VisualPluginService(featureSwitches) {
42288 this.plugins = powerbi.visuals.plugins;
42289 this.featureSwitches = featureSwitches;
42290 }
42291 /**
42292 * Gets metadata for all registered.
42293 */
42294 VisualPluginService.prototype.getVisuals = function () {
42295 var registry = this.plugins, names = Object.keys(registry);
42296 return names.map(function (name) { return registry[name]; });
42297 };
42298 VisualPluginService.prototype.getPlugin = function (type) {
42299 if (!type) {
42300 return;
42301 }
42302 var plugin = this.plugins[type];
42303 if (!plugin) {
42304 return;
42305 }
42306 return plugin;
42307 };
42308 VisualPluginService.prototype.capabilities = function (type) {
42309 var plugin = this.getPlugin(type);
42310 if (plugin)
42311 return plugin.capabilities;
42312 };
42313 VisualPluginService.prototype.requireSandbox = function (plugin) {
42314 return plugin && plugin.custom;
42315 };
42316 VisualPluginService.prototype.removeAnyCustomVisuals = function () {
42317 var plugins = powerbi.visuals.plugins;
42318 for (var key in plugins) {
42319 var p = plugins[key];
42320 if (p.custom) {
42321 delete plugins[key];
42322 }
42323 }
42324 };
42325 VisualPluginService.prototype.isCustomVisual = function (visual) {
42326 if (visual) {
42327 if (this.plugins[visual]) {
42328 return this.plugins[visual].custom === true;
42329 }
42330 else if (_.include(unsupportedVisuals, visual)) {
42331 /*use the hardcoded unsupported visual list to distinguish unsupported visual with custom visual when the plugin object is not in memory*/
42332 return false;
42333 }
42334 else {
42335 return true;
42336 }
42337 }
42338 return false;
42339 };
42340 VisualPluginService.prototype.isScriptVisual = function (type) {
42341 var visualCapabilities = this.capabilities(type);
42342 if (visualCapabilities && visualCapabilities.dataViewMappings && powerbi.ScriptResultUtil.findScriptResult(visualCapabilities.dataViewMappings)) {
42343 return true;
42344 }
42345 return false;
42346 };
42347 VisualPluginService.prototype.shouldDisableVisual = function (type, mapDisabled) {
42348 return (type === visuals.plugins.map.name || type === visuals.plugins.filledMap.name) && mapDisabled;
42349 };
42350 VisualPluginService.prototype.isScriptVisualQueryable = function () {
42351 // Feature switch determines if Script visuals are query visuals - currently non-query in PBI site
42352 return (this.featureSwitches !== undefined && this.featureSwitches.scriptVisualEnabled);
42353 };
42354 VisualPluginService.prototype.getInteractivityOptions = function (visualType) {
42355 var interactivityOptions = {
42356 overflow: 'hidden',
42357 };
42358 return interactivityOptions;
42359 };
42360 return VisualPluginService;
42361 }());
42362 visualPluginFactory.VisualPluginService = VisualPluginService;
42363 function createPlugin(visualPlugins, base, create, modifyPluginFn) {
42364 var visualPlugin = powerbi.Prototype.inherit(base);
42365 visualPlugin.create = create;
42366 if (modifyPluginFn) {
42367 modifyPluginFn(visualPlugin);
42368 }
42369 visualPlugins[base.name] = visualPlugin;
42370 }
42371 visualPluginFactory.createPlugin = createPlugin;
42372 function createDashboardPlugins(plugins, options, featureSwitches) {
42373 var tooltipsOnDashboard = options.tooltipsEnabled;
42374 var lineChartLabelDensityEnabled = featureSwitches && featureSwitches.lineChartLabelDensityEnabled;
42375 // Bar Chart
42376 createPlugin(plugins, powerbi.visuals.plugins.barChart, function () { return new visuals.CartesianChart({
42377 chartType: 6 /* StackedBar */,
42378 tooltipsEnabled: tooltipsOnDashboard,
42379 }); });
42380 // Clustered Bar Chart
42381 createPlugin(plugins, powerbi.visuals.plugins.clusteredBarChart, function () { return new visuals.CartesianChart({
42382 chartType: 5 /* ClusteredBar */,
42383 tooltipsEnabled: tooltipsOnDashboard,
42384 }); });
42385 // Clustered Column Chart
42386 createPlugin(plugins, powerbi.visuals.plugins.clusteredColumnChart, function () { return new visuals.CartesianChart({
42387 chartType: 3 /* ClusteredColumn */,
42388 tooltipsEnabled: tooltipsOnDashboard,
42389 }); });
42390 // Column Chart
42391 createPlugin(plugins, powerbi.visuals.plugins.columnChart, function () { return new visuals.CartesianChart({
42392 chartType: 4 /* StackedColumn */,
42393 tooltipsEnabled: tooltipsOnDashboard,
42394 }); });
42395 // Data Dot Clustered Combo Chart
42396 createPlugin(plugins, powerbi.visuals.plugins.dataDotClusteredColumnComboChart, function () { return new visuals.CartesianChart({
42397 chartType: 15 /* DataDotClusteredColumnCombo */,
42398 tooltipsEnabled: tooltipsOnDashboard,
42399 }); });
42400 // Data Dot Stacked Combo Chart
42401 createPlugin(plugins, powerbi.visuals.plugins.dataDotStackedColumnComboChart, function () { return new visuals.CartesianChart({
42402 chartType: 16 /* DataDotStackedColumnCombo */,
42403 tooltipsEnabled: tooltipsOnDashboard,
42404 }); });
42405 // Donut Chart
42406 createPlugin(plugins, powerbi.visuals.plugins.donutChart, function () { return new visuals.DonutChart({
42407 tooltipsEnabled: tooltipsOnDashboard,
42408 }); });
42409 // Funnel Chart
42410 createPlugin(plugins, powerbi.visuals.plugins.funnel, function () { return new visuals.FunnelChart({
42411 tooltipsEnabled: tooltipsOnDashboard,
42412 }); });
42413 // Gauge
42414 createPlugin(plugins, powerbi.visuals.plugins.gauge, function () { return new visuals.Gauge({
42415 tooltipsEnabled: tooltipsOnDashboard,
42416 }); });
42417 // Hundred Percent Stacked Bar Chart
42418 createPlugin(plugins, powerbi.visuals.plugins.hundredPercentStackedBarChart, function () { return new visuals.CartesianChart({
42419 chartType: 7 /* HundredPercentStackedBar */,
42420 tooltipsEnabled: tooltipsOnDashboard,
42421 }); });
42422 // Hundred Percent Stacked Column Chart
42423 createPlugin(plugins, powerbi.visuals.plugins.hundredPercentStackedColumnChart, function () { return new visuals.CartesianChart({
42424 chartType: 8 /* HundredPercentStackedColumn */,
42425 tooltipsEnabled: tooltipsOnDashboard,
42426 }); });
42427 // Line Chart
42428 createPlugin(plugins, powerbi.visuals.plugins.lineChart, function () { return new visuals.CartesianChart({
42429 chartType: 0 /* Line */,
42430 tooltipsEnabled: tooltipsOnDashboard,
42431 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
42432 }); });
42433 // Area Chart
42434 createPlugin(plugins, powerbi.visuals.plugins.areaChart, function () { return new visuals.CartesianChart({
42435 chartType: 1 /* Area */,
42436 tooltipsEnabled: tooltipsOnDashboard,
42437 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
42438 }); });
42439 // Stacked Area Chart
42440 createPlugin(plugins, powerbi.visuals.plugins.stackedAreaChart, function () { return new visuals.CartesianChart({
42441 chartType: 2 /* StackedArea */,
42442 tooltipsEnabled: tooltipsOnDashboard,
42443 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
42444 }); });
42445 // Line Clustered Combo Chart
42446 createPlugin(plugins, powerbi.visuals.plugins.lineClusteredColumnComboChart, function () { return new visuals.CartesianChart({
42447 chartType: 13 /* LineClusteredColumnCombo */,
42448 tooltipsEnabled: tooltipsOnDashboard,
42449 }); });
42450 // Line Stacked Combo Chart
42451 createPlugin(plugins, powerbi.visuals.plugins.lineStackedColumnComboChart, function () { return new visuals.CartesianChart({
42452 chartType: 14 /* LineStackedColumnCombo */,
42453 tooltipsEnabled: tooltipsOnDashboard,
42454 }); });
42455 // Pie Chart
42456 createPlugin(plugins, powerbi.visuals.plugins.pieChart, function () { return new visuals.DonutChart({
42457 sliceWidthRatio: 0,
42458 tooltipsEnabled: tooltipsOnDashboard,
42459 }); });
42460 // Scatter Chart
42461 createPlugin(plugins, powerbi.visuals.plugins.scatterChart, function () { return new visuals.CartesianChart({
42462 chartType: 9 /* Scatter */,
42463 tooltipsEnabled: tooltipsOnDashboard,
42464 }); });
42465 // Treemap
42466 createPlugin(plugins, powerbi.visuals.plugins.treemap, function () { return new visuals.Treemap({
42467 isScrollable: false,
42468 tooltipsEnabled: tooltipsOnDashboard,
42469 }); });
42470 // Waterfall Chart
42471 createPlugin(plugins, powerbi.visuals.plugins.waterfallChart, function () { return new visuals.CartesianChart({
42472 chartType: 12 /* Waterfall */,
42473 tooltipsEnabled: tooltipsOnDashboard,
42474 }); });
42475 // Map
42476 createPlugin(plugins, powerbi.visuals.plugins.map, function () { return new visuals.Map({
42477 tooltipsEnabled: tooltipsOnDashboard,
42478 disableZooming: true,
42479 disablePanning: true,
42480 }); });
42481 // Filled Map
42482 createPlugin(plugins, powerbi.visuals.plugins.filledMap, function () { return new visuals.Map({
42483 filledMap: true,
42484 tooltipsEnabled: tooltipsOnDashboard,
42485 disableZooming: true,
42486 disablePanning: true,
42487 }); });
42488 // Matrix
42489 createPlugin(plugins, powerbi.visuals.plugins.matrix, function () { return new visuals.Matrix({}); });
42490 // Table
42491 createPlugin(plugins, powerbi.visuals.plugins.table, function () { return new visuals.Table({
42492 isConditionalFormattingEnabled: false,
42493 }); });
42494 }
42495 function createMinervaPlugins(plugins, featureSwitches) {
42496 var scriptVisualEnabled = featureSwitches ? featureSwitches.scriptVisualEnabled : false;
42497 var scriptVisualAuthoringEnabled = featureSwitches ? featureSwitches.scriptVisualAuthoringEnabled : false;
42498 var isLabelInteractivityEnabled = featureSwitches ? featureSwitches.isLabelInteractivityEnabled : false;
42499 var conditionalFormattingEnabled = featureSwitches ? featureSwitches.conditionalFormattingEnabled : false;
42500 var fillMapDataLabelsEnabled = featureSwitches ? featureSwitches.filledMapDataLabelsEnabled : false;
42501 var lineChartLabelDensityEnabled = featureSwitches ? featureSwitches.lineChartLabelDensityEnabled : false;
42502 // Bar Chart
42503 createPlugin(plugins, powerbi.visuals.plugins.barChart, function () { return new visuals.CartesianChart({
42504 chartType: 6 /* StackedBar */,
42505 isScrollable: true, animator: new visuals.WebColumnChartAnimator(),
42506 tooltipsEnabled: true,
42507 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior()]),
42508 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42509 }); });
42510 // Card
42511 createPlugin(plugins, powerbi.visuals.plugins.card, function () { return new visuals.Card({
42512 isScrollable: true,
42513 animator: new visuals.BaseAnimator(),
42514 }); });
42515 // Clustered Bar Chart
42516 createPlugin(plugins, powerbi.visuals.plugins.clusteredBarChart, function () { return new visuals.CartesianChart({
42517 chartType: 5 /* ClusteredBar */,
42518 isScrollable: true,
42519 tooltipsEnabled: true,
42520 animator: new visuals.WebColumnChartAnimator(),
42521 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior()]),
42522 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42523 }); });
42524 // Clustered Column Chart
42525 createPlugin(plugins, powerbi.visuals.plugins.clusteredColumnChart, function () { return new visuals.CartesianChart({
42526 chartType: 3 /* ClusteredColumn */,
42527 isScrollable: true,
42528 tooltipsEnabled: true,
42529 animator: new visuals.WebColumnChartAnimator(),
42530 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior()]),
42531 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42532 }); });
42533 // Column Chart
42534 createPlugin(plugins, powerbi.visuals.plugins.columnChart, function () { return new visuals.CartesianChart({
42535 chartType: 4 /* StackedColumn */,
42536 isScrollable: true,
42537 tooltipsEnabled: true,
42538 animator: new visuals.WebColumnChartAnimator(),
42539 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior()]),
42540 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42541 }); });
42542 // Data Dot Clustered Combo Chart
42543 createPlugin(plugins, powerbi.visuals.plugins.dataDotClusteredColumnComboChart, function () { return new visuals.CartesianChart({
42544 chartType: 15 /* DataDotClusteredColumnCombo */,
42545 isScrollable: true,
42546 tooltipsEnabled: true,
42547 animator: new visuals.WebColumnChartAnimator(),
42548 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior(), new visuals.DataDotChartWebBehavior()]),
42549 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42550 }); });
42551 // Data Dot Stacked Combo Chart
42552 createPlugin(plugins, powerbi.visuals.plugins.dataDotStackedColumnComboChart, function () { return new visuals.CartesianChart({
42553 chartType: 16 /* DataDotStackedColumnCombo */,
42554 isScrollable: true,
42555 tooltipsEnabled: true,
42556 animator: new visuals.WebColumnChartAnimator(),
42557 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior(), new visuals.DataDotChartWebBehavior()]),
42558 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42559 }); });
42560 // Donut Chart
42561 createPlugin(plugins, powerbi.visuals.plugins.donutChart, function () { return new visuals.DonutChart({
42562 animator: new visuals.WebDonutChartAnimator(),
42563 isScrollable: true,
42564 tooltipsEnabled: true,
42565 behavior: new visuals.DonutChartWebBehavior(),
42566 }); });
42567 // Funnel Chart
42568 createPlugin(plugins, powerbi.visuals.plugins.funnel, function () { return new visuals.FunnelChart({
42569 animator: new visuals.WebFunnelAnimator(),
42570 behavior: new visuals.FunnelWebBehavior(),
42571 tooltipsEnabled: true,
42572 }); });
42573 // Gauge
42574 createPlugin(plugins, powerbi.visuals.plugins.gauge, function () { return new visuals.Gauge({
42575 animator: new visuals.BaseAnimator(),
42576 tooltipsEnabled: true,
42577 }); });
42578 // Hundred Percent Stacked Bar Chart
42579 createPlugin(plugins, powerbi.visuals.plugins.hundredPercentStackedBarChart, function () { return new visuals.CartesianChart({
42580 chartType: 7 /* HundredPercentStackedBar */,
42581 isScrollable: true,
42582 tooltipsEnabled: true,
42583 animator: new visuals.WebColumnChartAnimator(),
42584 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior()]),
42585 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42586 }); });
42587 // Hundred Percent Stacked Column Chart
42588 createPlugin(plugins, powerbi.visuals.plugins.hundredPercentStackedColumnChart, function () { return new visuals.CartesianChart({
42589 chartType: 8 /* HundredPercentStackedColumn */,
42590 isScrollable: true,
42591 tooltipsEnabled: true,
42592 animator: new visuals.WebColumnChartAnimator(),
42593 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior()]),
42594 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42595 }); });
42596 // Line Chart
42597 createPlugin(plugins, powerbi.visuals.plugins.lineChart, function () { return new visuals.CartesianChart({
42598 chartType: 0 /* Line */,
42599 isScrollable: true,
42600 tooltipsEnabled: true,
42601 animator: new visuals.BaseAnimator(),
42602 behavior: new visuals.CartesianChartBehavior([new visuals.LineChartWebBehavior()]),
42603 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42604 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
42605 }); });
42606 // Area Chart
42607 createPlugin(plugins, powerbi.visuals.plugins.areaChart, function () { return new visuals.CartesianChart({
42608 chartType: 1 /* Area */,
42609 isScrollable: true,
42610 tooltipsEnabled: true,
42611 animator: new visuals.BaseAnimator(),
42612 behavior: new visuals.CartesianChartBehavior([new visuals.LineChartWebBehavior()]),
42613 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42614 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
42615 }); });
42616 // Stacked Area Chart
42617 createPlugin(plugins, powerbi.visuals.plugins.stackedAreaChart, function () { return new visuals.CartesianChart({
42618 chartType: 2 /* StackedArea */,
42619 isScrollable: true,
42620 tooltipsEnabled: true,
42621 animator: new visuals.BaseAnimator(),
42622 behavior: new visuals.CartesianChartBehavior([new visuals.LineChartWebBehavior()]),
42623 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
42624 }); });
42625 // Line Clustered Combo Chart
42626 createPlugin(plugins, powerbi.visuals.plugins.lineClusteredColumnComboChart, function () { return new visuals.CartesianChart({
42627 chartType: 13 /* LineClusteredColumnCombo */,
42628 isScrollable: true,
42629 tooltipsEnabled: true,
42630 animator: new visuals.WebColumnChartAnimator(),
42631 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior(), new visuals.LineChartWebBehavior()]),
42632 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42633 }); });
42634 // Line Stacked Combo Chart
42635 createPlugin(plugins, powerbi.visuals.plugins.lineStackedColumnComboChart, function () { return new visuals.CartesianChart({
42636 chartType: 14 /* LineStackedColumnCombo */,
42637 isScrollable: true,
42638 tooltipsEnabled: true,
42639 animator: new visuals.WebColumnChartAnimator(),
42640 behavior: new visuals.CartesianChartBehavior([new visuals.ColumnChartWebBehavior(), new visuals.LineChartWebBehavior()]),
42641 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42642 }); });
42643 // Pie Chart
42644 createPlugin(plugins, powerbi.visuals.plugins.pieChart, function () { return new visuals.DonutChart({
42645 sliceWidthRatio: 0,
42646 animator: new visuals.WebDonutChartAnimator(),
42647 isScrollable: true,
42648 tooltipsEnabled: true,
42649 behavior: new visuals.DonutChartWebBehavior(),
42650 }); });
42651 // Scatter Chart
42652 createPlugin(plugins, powerbi.visuals.plugins.scatterChart, function () { return new visuals.CartesianChart({
42653 chartType: 9 /* Scatter */,
42654 isScrollable: true,
42655 tooltipsEnabled: true,
42656 animator: new visuals.BaseAnimator(),
42657 behavior: new visuals.CartesianChartBehavior([new visuals.ScatterChartWebBehavior()]),
42658 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42659 }); });
42660 // Treemap
42661 createPlugin(plugins, powerbi.visuals.plugins.treemap, function () { return new visuals.Treemap({
42662 animator: new visuals.WebTreemapAnimator,
42663 isScrollable: true,
42664 behavior: new visuals.TreemapWebBehavior(),
42665 tooltipsEnabled: true,
42666 }); });
42667 // Waterfall Chart
42668 createPlugin(plugins, powerbi.visuals.plugins.waterfallChart, function () { return new visuals.CartesianChart({
42669 chartType: 12 /* Waterfall */,
42670 isScrollable: true,
42671 tooltipsEnabled: true,
42672 behavior: new visuals.CartesianChartBehavior([new visuals.WaterfallChartWebBehavior()]),
42673 isLabelInteractivityEnabled: isLabelInteractivityEnabled,
42674 }); });
42675 // Map
42676 createPlugin(plugins, powerbi.visuals.plugins.map, function () { return new visuals.Map({
42677 behavior: new visuals.MapBehavior(),
42678 tooltipsEnabled: true,
42679 isLegendScrollable: true,
42680 }); });
42681 // Filled Map
42682 createPlugin(plugins, powerbi.visuals.plugins.filledMap, function () { return new visuals.Map({
42683 filledMap: true,
42684 behavior: new visuals.MapBehavior,
42685 tooltipsEnabled: true,
42686 filledMapDataLabelsEnabled: fillMapDataLabelsEnabled,
42687 isLegendScrollable: true,
42688 }); });
42689 // Slicer
42690 createPlugin(plugins, powerbi.visuals.plugins.slicer, function () { return new visuals.Slicer({
42691 behavior: new visuals.SlicerWebBehavior(),
42692 }); });
42693 // Matrix
42694 createPlugin(plugins, powerbi.visuals.plugins.matrix, function () { return new visuals.Matrix({}); });
42695 // Table
42696 createPlugin(plugins, powerbi.visuals.plugins.table, function () { return new visuals.Table({
42697 isConditionalFormattingEnabled: conditionalFormattingEnabled,
42698 }); });
42699 ;
42700 if (scriptVisualEnabled && scriptVisualAuthoringEnabled) {
42701 // R visual
42702 createPlugin(plugins, powerbi.visuals.plugins.scriptVisual, function () { return new visuals.ScriptVisual({ canRefresh: true }); });
42703 }
42704 }
42705 var PlaygroundVisualPluginService = (function (_super) {
42706 __extends(PlaygroundVisualPluginService, _super);
42707 function PlaygroundVisualPluginService() {
42708 _super.call(this, undefined);
42709 this.visualPlugins = powerbi.visuals.plugins;
42710 createMinervaPlugins(this.visualPlugins, null);
42711 }
42712 PlaygroundVisualPluginService.prototype.getVisuals = function () {
42713 var registry = this.visualPlugins, names = Object.keys(registry);
42714 return names.map(function (name) { return registry[name]; });
42715 };
42716 PlaygroundVisualPluginService.prototype.getPlugin = function (type) {
42717 if (!type) {
42718 return;
42719 }
42720 var plugin = this.visualPlugins[type];
42721 if (!plugin) {
42722 return;
42723 }
42724 return plugin;
42725 };
42726 PlaygroundVisualPluginService.prototype.capabilities = function (type) {
42727 var plugin = this.getPlugin(type);
42728 if (plugin) {
42729 return plugin.capabilities;
42730 }
42731 };
42732 return PlaygroundVisualPluginService;
42733 }(VisualPluginService));
42734 visualPluginFactory.PlaygroundVisualPluginService = PlaygroundVisualPluginService;
42735 /**
42736 * This plug-in service is used when displaying visuals on the dashboard.
42737 */
42738 var DashboardPluginService = (function (_super) {
42739 __extends(DashboardPluginService, _super);
42740 function DashboardPluginService(featureSwitches, options) {
42741 _super.call(this, featureSwitches);
42742 debug.assertValue(featureSwitches, 'featureSwitches');
42743 this.visualPlugins = {};
42744 createDashboardPlugins(this.visualPlugins, options, this.featureSwitches);
42745 }
42746 DashboardPluginService.prototype.getPlugin = function (type) {
42747 if (this.visualPlugins[type]) {
42748 return this.visualPlugins[type];
42749 }
42750 return _super.prototype.getPlugin.call(this, type);
42751 };
42752 DashboardPluginService.prototype.requireSandbox = function (plugin) {
42753 return (this.featureSwitches.sandboxVisualsEnabled) && (!plugin || (plugin && plugin.custom));
42754 };
42755 return DashboardPluginService;
42756 }(VisualPluginService));
42757 visualPluginFactory.DashboardPluginService = DashboardPluginService;
42758 // This plug-in service is used when displaying visuals for insights.
42759 var InsightsPluginService = (function (_super) {
42760 __extends(InsightsPluginService, _super);
42761 function InsightsPluginService(featureSwitches) {
42762 _super.call(this, featureSwitches);
42763 debug.assertValue(featureSwitches, 'featureSwitches');
42764 this.visualPlugins = {};
42765 // Clustered Bar Chart
42766 createPlugin(this.visualPlugins, powerbi.visuals.plugins.clusteredBarChart, function () { return new visuals.CartesianChart({
42767 chartType: 5 /* ClusteredBar */,
42768 animator: new visuals.WebColumnChartAnimator(),
42769 tooltipsEnabled: true
42770 }); });
42771 // Column Chart
42772 createPlugin(this.visualPlugins, powerbi.visuals.plugins.columnChart, function () { return new visuals.CartesianChart({
42773 chartType: 4 /* StackedColumn */,
42774 animator: new visuals.WebColumnChartAnimator(),
42775 tooltipsEnabled: true
42776 }); });
42777 // Donut Chart
42778 createPlugin(this.visualPlugins, powerbi.visuals.plugins.donutChart, function () { return new visuals.DonutChart({
42779 animator: new visuals.WebDonutChartAnimator(),
42780 tooltipsEnabled: true,
42781 }); });
42782 // Hundred Percent Stacked Bar Chart
42783 createPlugin(this.visualPlugins, powerbi.visuals.plugins.hundredPercentStackedBarChart, function () { return new visuals.CartesianChart({
42784 chartType: 7 /* HundredPercentStackedBar */,
42785 animator: new visuals.WebColumnChartAnimator(),
42786 tooltipsEnabled: true
42787 }); });
42788 // Hundred Percent Stacked Column Chart
42789 createPlugin(this.visualPlugins, powerbi.visuals.plugins.hundredPercentStackedColumnChart, function () { return new visuals.CartesianChart({
42790 chartType: 8 /* HundredPercentStackedColumn */,
42791 animator: new visuals.WebColumnChartAnimator(),
42792 tooltipsEnabled: true
42793 }); });
42794 // Line Chart
42795 createPlugin(this.visualPlugins, powerbi.visuals.plugins.lineChart, function () { return new visuals.CartesianChart({
42796 chartType: 0 /* Line */,
42797 animator: new visuals.BaseAnimator(),
42798 tooltipsEnabled: true,
42799 }); });
42800 // Area Chart
42801 createPlugin(this.visualPlugins, powerbi.visuals.plugins.areaChart, function () { return new visuals.CartesianChart({
42802 chartType: 1 /* Area */,
42803 animator: new visuals.BaseAnimator(),
42804 tooltipsEnabled: true,
42805 }); });
42806 // Pie Chart
42807 createPlugin(this.visualPlugins, powerbi.visuals.plugins.pieChart, function () { return new visuals.DonutChart({
42808 sliceWidthRatio: 0,
42809 animator: new visuals.WebDonutChartAnimator(),
42810 tooltipsEnabled: true,
42811 }); });
42812 // Scatter Chart
42813 createPlugin(this.visualPlugins, powerbi.visuals.plugins.scatterChart, function () { return new visuals.CartesianChart({
42814 chartType: 9 /* Scatter */,
42815 animator: new visuals.BaseAnimator(),
42816 tooltipsEnabled: true,
42817 }); }, undefined);
42818 }
42819 InsightsPluginService.prototype.getPlugin = function (type) {
42820 if (this.visualPlugins[type]) {
42821 return this.visualPlugins[type];
42822 }
42823 return _super.prototype.getPlugin.call(this, type);
42824 };
42825 InsightsPluginService.prototype.requireSandbox = function (plugin) {
42826 return (this.featureSwitches.sandboxVisualsEnabled) && (!plugin || (plugin && plugin.custom));
42827 };
42828 return InsightsPluginService;
42829 }(VisualPluginService));
42830 visualPluginFactory.InsightsPluginService = InsightsPluginService;
42831 var MobileVisualPluginService = (function (_super) {
42832 __extends(MobileVisualPluginService, _super);
42833 function MobileVisualPluginService(smallViewPortProperties, featureSwitches) {
42834 var _this = this;
42835 _super.call(this, featureSwitches);
42836 this.smallViewPortProperties = smallViewPortProperties || {
42837 CartesianSmallViewPortProperties: {
42838 hideAxesOnSmallViewPort: true,
42839 hideLegendOnSmallViewPort: true,
42840 MinHeightLegendVisible: MobileVisualPluginService.MinHeightLegendVisible,
42841 MinHeightAxesVisible: MobileVisualPluginService.MinHeightAxesVisible,
42842 },
42843 GaugeSmallViewPortProperties: {
42844 hideGaugeSideNumbersOnSmallViewPort: true,
42845 smallGaugeMarginsOnSmallViewPort: true,
42846 MinHeightGaugeSideNumbersVisible: MobileVisualPluginService.MinHeightGaugeSideNumbersVisible,
42847 GaugeMarginsOnSmallViewPort: MobileVisualPluginService.GaugeMarginsOnSmallViewPort,
42848 },
42849 FunnelSmallViewPortProperties: {
42850 hideFunnelCategoryLabelsOnSmallViewPort: true,
42851 minHeightFunnelCategoryLabelsVisible: MobileVisualPluginService.MinHeightFunnelCategoryLabelsVisible,
42852 },
42853 DonutSmallViewPortProperties: {
42854 maxHeightToScaleDonutLegend: MobileVisualPluginService.MaxHeightToScaleDonutLegend,
42855 },
42856 };
42857 // Disable tooltips for mobile
42858 visuals.TooltipManager.ShowTooltips = false;
42859 // Don't trim overflow data on mobile
42860 var trimOrdinalDataOnOverflow = false;
42861 var mapThrottleInterval = this.getMapThrottleInterval();
42862 this.visualPlugins = {};
42863 createPlugin(this.visualPlugins, powerbi.visuals.plugins.areaChart, function () { return new visuals.CartesianChart({
42864 chartType: 1 /* Area */,
42865 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42866 }); });
42867 createPlugin(this.visualPlugins, powerbi.visuals.plugins.barChart, function () { return new visuals.CartesianChart({
42868 chartType: 6 /* StackedBar */,
42869 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42870 }); });
42871 createPlugin(this.visualPlugins, powerbi.visuals.plugins.clusteredBarChart, function () { return new visuals.CartesianChart({
42872 chartType: 5 /* ClusteredBar */,
42873 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42874 }); });
42875 createPlugin(this.visualPlugins, powerbi.visuals.plugins.clusteredColumnChart, function () { return new visuals.CartesianChart({
42876 chartType: 3 /* ClusteredColumn */,
42877 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42878 }); });
42879 createPlugin(this.visualPlugins, powerbi.visuals.plugins.columnChart, function () { return new visuals.CartesianChart({
42880 chartType: 4 /* StackedColumn */,
42881 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42882 }); });
42883 createPlugin(this.visualPlugins, powerbi.visuals.plugins.comboChart, function () { return new visuals.CartesianChart({
42884 chartType: 10 /* ComboChart */,
42885 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42886 }); });
42887 createPlugin(this.visualPlugins, powerbi.visuals.plugins.dataDotChart, function () { return new visuals.CartesianChart({
42888 chartType: 11 /* DataDot */,
42889 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42890 }); });
42891 createPlugin(this.visualPlugins, powerbi.visuals.plugins.dataDotClusteredColumnComboChart, function () { return new visuals.CartesianChart({
42892 chartType: 15 /* DataDotClusteredColumnCombo */,
42893 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42894 }); });
42895 createPlugin(this.visualPlugins, powerbi.visuals.plugins.dataDotStackedColumnComboChart, function () { return new visuals.CartesianChart({
42896 chartType: 16 /* DataDotStackedColumnCombo */,
42897 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42898 }); });
42899 createPlugin(this.visualPlugins, powerbi.visuals.plugins.hundredPercentStackedBarChart, function () { return new visuals.CartesianChart({
42900 chartType: 7 /* HundredPercentStackedBar */,
42901 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42902 }); });
42903 createPlugin(this.visualPlugins, powerbi.visuals.plugins.hundredPercentStackedColumnChart, function () { return new visuals.CartesianChart({
42904 chartType: 8 /* HundredPercentStackedColumn */,
42905 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42906 }); });
42907 createPlugin(this.visualPlugins, powerbi.visuals.plugins.stackedAreaChart, function () { return new visuals.CartesianChart({
42908 chartType: 2 /* StackedArea */,
42909 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42910 }); });
42911 createPlugin(this.visualPlugins, powerbi.visuals.plugins.waterfallChart, function () { return new visuals.CartesianChart({
42912 chartType: 12 /* Waterfall */,
42913 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42914 }); });
42915 createPlugin(this.visualPlugins, powerbi.visuals.plugins.lineChart, function () { return new visuals.CartesianChart({
42916 chartType: 0 /* Line */,
42917 cartesianSmallViewPortProperties: _this.smallViewPortProperties.CartesianSmallViewPortProperties,
42918 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42919 }); });
42920 createPlugin(this.visualPlugins, powerbi.visuals.plugins.lineClusteredColumnComboChart, function () { return new visuals.CartesianChart({
42921 chartType: 13 /* LineClusteredColumnCombo */,
42922 cartesianSmallViewPortProperties: _this.smallViewPortProperties.CartesianSmallViewPortProperties,
42923 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42924 }); });
42925 createPlugin(this.visualPlugins, powerbi.visuals.plugins.lineStackedColumnComboChart, function () { return new visuals.CartesianChart({
42926 chartType: 14 /* LineStackedColumnCombo */,
42927 cartesianSmallViewPortProperties: _this.smallViewPortProperties.CartesianSmallViewPortProperties,
42928 trimOrdinalDataOnOverflow: trimOrdinalDataOnOverflow
42929 }); });
42930 createPlugin(this.visualPlugins, powerbi.visuals.plugins.scatterChart, function () { return new visuals.CartesianChart({
42931 chartType: 9 /* Scatter */,
42932 cartesianSmallViewPortProperties: _this.smallViewPortProperties.CartesianSmallViewPortProperties,
42933 behavior: new visuals.CartesianChartBehavior([new visuals.ScatterChartMobileBehavior()])
42934 }); });
42935 createPlugin(this.visualPlugins, powerbi.visuals.plugins.gauge, function () { return new visuals.Gauge({
42936 gaugeSmallViewPortProperties: _this.smallViewPortProperties.GaugeSmallViewPortProperties
42937 }); });
42938 createPlugin(this.visualPlugins, powerbi.visuals.plugins.funnel, function () { return new visuals.FunnelChart({
42939 animator: null,
42940 funnelSmallViewPortProperties: _this.smallViewPortProperties.FunnelSmallViewPortProperties
42941 }); });
42942 createPlugin(this.visualPlugins, powerbi.visuals.plugins.donutChart, function () { return new visuals.DonutChart({
42943 disableGeometricCulling: true,
42944 smallViewPortProperties: _this.smallViewPortProperties.DonutSmallViewPortProperties
42945 }); });
42946 createPlugin(this.visualPlugins, powerbi.visuals.plugins.pieChart, function () { return new visuals.DonutChart({
42947 sliceWidthRatio: 0,
42948 disableGeometricCulling: true,
42949 smallViewPortProperties: _this.smallViewPortProperties.DonutSmallViewPortProperties
42950 }); });
42951 createPlugin(this.visualPlugins, powerbi.visuals.plugins.matrix, function () { return new visuals.Matrix({
42952 isTouchEnabled: true
42953 }); });
42954 createPlugin(this.visualPlugins, powerbi.visuals.plugins.table, function () { return new visuals.Table({
42955 isTouchEnabled: true
42956 }); });
42957 createPlugin(this.visualPlugins, powerbi.visuals.plugins.map, function () { return new visuals.Map({
42958 viewChangeThrottleInterval: mapThrottleInterval,
42959 enableCurrentLocation: featureSwitches ? featureSwitches.mapCurrentLocationEnabled : false
42960 }); });
42961 createPlugin(this.visualPlugins, powerbi.visuals.plugins.filledMap, function () { return new visuals.Map({
42962 filledMap: true,
42963 viewChangeThrottleInterval: mapThrottleInterval
42964 }); });
42965 }
42966 MobileVisualPluginService.prototype.getPlugin = function (type) {
42967 if (this.visualPlugins[type])
42968 return this.visualPlugins[type];
42969 return _super.prototype.getPlugin.call(this, type);
42970 };
42971 MobileVisualPluginService.prototype.requireSandbox = function (plugin) {
42972 if (this.featureSwitches)
42973 return (this.featureSwitches.sandboxVisualsEnabled) && (!plugin || (plugin && plugin.custom));
42974 else
42975 return _super.prototype.requireSandbox.call(this, plugin);
42976 };
42977 // Windows phone webView chokes when zooming on heavy maps,
42978 // this is a workaround to allow a relatively smooth pinch to zoom experience.
42979 MobileVisualPluginService.prototype.getMapThrottleInterval = function () {
42980 var windowsPhoneThrottleInterval = 100;
42981 var userAgentLowerCase = navigator.userAgent.toLowerCase();
42982 if (userAgentLowerCase.indexOf('windows phone') !== -1) {
42983 return windowsPhoneThrottleInterval;
42984 }
42985 return undefined;
42986 };
42987 MobileVisualPluginService.prototype.getInteractivityOptions = function (visualType) {
42988 var mobileOptions = {
42989 overflow: this.getMobileOverflowString(visualType),
42990 isInteractiveLegend: this.isChartSupportInteractivity(visualType),
42991 selection: true,
42992 };
42993 return mobileOptions;
42994 };
42995 MobileVisualPluginService.prototype.getMobileOverflowString = function (visualType) {
42996 switch (visualType) {
42997 case 'multiRowCard':
42998 return 'visible';
42999 default:
43000 return 'hidden';
43001 }
43002 };
43003 MobileVisualPluginService.prototype.isChartSupportInteractivity = function (visualType) {
43004 switch (visualType) {
43005 case 'areaChart':
43006 case 'barChart':
43007 case 'clusteredBarChart':
43008 case 'clusteredColumnChart':
43009 case 'columnChart':
43010 case 'donutChart':
43011 case 'hundredPercentStackedBarChart':
43012 case 'hundredPercentStackedColumnChart':
43013 case 'lineChart':
43014 case 'pieChart':
43015 case 'scatterChart':
43016 case 'table':
43017 case 'matrix':
43018 case 'multiRowCard':
43019 return true;
43020 default:
43021 return false;
43022 }
43023 };
43024 MobileVisualPluginService.MinHeightLegendVisible = 125;
43025 MobileVisualPluginService.MinHeightAxesVisible = 125;
43026 MobileVisualPluginService.MinHeightGaugeSideNumbersVisible = 80;
43027 MobileVisualPluginService.GaugeMarginsOnSmallViewPort = 10;
43028 MobileVisualPluginService.MinHeightFunnelCategoryLabelsVisible = 80;
43029 MobileVisualPluginService.MaxHeightToScaleDonutLegend = 300;
43030 return MobileVisualPluginService;
43031 }(VisualPluginService));
43032 visualPluginFactory.MobileVisualPluginService = MobileVisualPluginService;
43033 // this function is called by tests
43034 function create() {
43035 return new VisualPluginService(undefined);
43036 }
43037 visualPluginFactory.create = create;
43038 function createVisualPluginService(featureSwitch) {
43039 return new VisualPluginService(featureSwitch);
43040 }
43041 visualPluginFactory.createVisualPluginService = createVisualPluginService;
43042 function createDashboard(featureSwitches, options) {
43043 return new DashboardPluginService(featureSwitches, options);
43044 }
43045 visualPluginFactory.createDashboard = createDashboard;
43046 function createInsights(featureSwitches) {
43047 return new InsightsPluginService(featureSwitches);
43048 }
43049 visualPluginFactory.createInsights = createInsights;
43050 function createMobile(smallViewPortProperties, featureSwitches) {
43051 return new MobileVisualPluginService(smallViewPortProperties, featureSwitches);
43052 }
43053 visualPluginFactory.createMobile = createMobile;
43054 })(visualPluginFactory = visuals.visualPluginFactory || (visuals.visualPluginFactory = {}));
43055 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
43056})(powerbi || (powerbi = {}));
43057/*
43058 * Power BI Visualizations
43059 *
43060 * Copyright (c) Microsoft Corporation
43061 * All rights reserved.
43062 * MIT License
43063 *
43064 * Permission is hereby granted, free of charge, to any person obtaining a copy
43065 * of this software and associated documentation files (the ""Software""), to deal
43066 * in the Software without restriction, including without limitation the rights
43067 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43068 * copies of the Software, and to permit persons to whom the Software is
43069 * furnished to do so, subject to the following conditions:
43070 *
43071 * The above copyright notice and this permission notice shall be included in
43072 * all copies or substantial portions of the Software.
43073 *
43074 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43075 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43076 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43077 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43078 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43079 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43080 * THE SOFTWARE.
43081 */
43082var powerbi;
43083(function (powerbi) {
43084 var visuals;
43085 (function (visuals) {
43086 var controls;
43087 (function (controls) {
43088 var UNSELECTABLE_CLASS_NAME = "unselectable";
43089 function fire(eventHandlers, eventArgs) {
43090 if (eventHandlers) {
43091 for (var i = 0; i < eventHandlers.length; i++) {
43092 var h = eventHandlers[i];
43093 h(eventArgs);
43094 }
43095 }
43096 }
43097 controls.fire = fire;
43098 var ScrollbarButton = (function () {
43099 // Constructor
43100 function ScrollbarButton(owner, direction) {
43101 this._owner = owner;
43102 this._direction = direction;
43103 this._timerHandle = undefined;
43104 this.createView();
43105 var that = this;
43106 this._element.addEventListener("mousedown", function (e) { that.onMouseDown(e); });
43107 $(this._element).addClass(UNSELECTABLE_CLASS_NAME);
43108 $(this._svg).addClass(UNSELECTABLE_CLASS_NAME);
43109 $(this._polygon).addClass(UNSELECTABLE_CLASS_NAME);
43110 }
43111 Object.defineProperty(ScrollbarButton.prototype, "element", {
43112 // Properties
43113 get: function () {
43114 return this._element;
43115 },
43116 enumerable: true,
43117 configurable: true
43118 });
43119 // Methods
43120 ScrollbarButton.prototype.createView = function () {
43121 var svgns = "http://www.w3.org/2000/svg";
43122 this._polygon = document.createElementNS(svgns, "polygon");
43123 this._polygon.setAttributeNS(null, "points", "3,3 6,3 13,8 6,13 3,13 10,8");
43124 this._polygon.setAttributeNS(null, "fill", ScrollbarButton.ARROW_COLOR);
43125 this._svg = document.createElementNS(svgns, "svg");
43126 var svgStyle = this._svg.style;
43127 svgStyle.position = "absolute";
43128 svgStyle.left = "0px";
43129 svgStyle.top = "0px";
43130 this._svg.appendChild(this._polygon);
43131 this._element = document.createElement("div");
43132 this._element.className = Scrollbar.arrowClassName;
43133 this._element.appendChild(this._svg);
43134 this._owner.element.appendChild(this._element);
43135 };
43136 ScrollbarButton.prototype.onMouseDown = function (event) {
43137 var that = this;
43138 clearTimeout(this._timerHandle);
43139 if (!this._mouseUpWrapper) {
43140 event.cancelBubble = true;
43141 var that_1 = this;
43142 this._mouseUpWrapper = function (event) { that_1.onMouseUp(event); };
43143 Scrollbar.addDocumentMouseUpEvent(this._mouseUpWrapper);
43144 }
43145 this._owner._scrollSmallIncrement(this._direction);
43146 this._owner.refresh();
43147 this._timerHandle = setTimeout(function () { that.onMouseDown(event); }, 100);
43148 if (event.preventDefault) {
43149 event.preventDefault(); // prevent dragging
43150 }
43151 };
43152 ScrollbarButton.prototype.onMouseUp = function (event) {
43153 clearTimeout(this._timerHandle);
43154 Scrollbar.removeDocumentMouseUpEvent(this._mouseUpWrapper);
43155 this._mouseUpWrapper = undefined;
43156 };
43157 ScrollbarButton.prototype.arrange = function (width, height, angle) {
43158 var size = Math.min(width, height);
43159 var scale = size / 16;
43160 var x = (width - size) / 2;
43161 var y = (height - size) / 2;
43162 this._polygon.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ") scale(" + scale + ") rotate(" + angle + ",8,8)");
43163 this._svg.setAttributeNS(null, "width", width + "px");
43164 this._svg.setAttributeNS(null, "height", height + "px");
43165 controls.HTMLElementUtils.setElementWidth(this._element, width);
43166 controls.HTMLElementUtils.setElementHeight(this._element, height);
43167 };
43168 // Const
43169 // TODO: Move to style
43170 ScrollbarButton.MIN_WIDTH = 26;
43171 ScrollbarButton.ARROW_COLOR = "#404040";
43172 return ScrollbarButton;
43173 }());
43174 controls.ScrollbarButton = ScrollbarButton;
43175 /** Scrollbar base class */
43176 var Scrollbar = (function () {
43177 function Scrollbar(parentElement, layoutKind) {
43178 this.MIN_BAR_SIZE = 10;
43179 this.min = 0;
43180 this.max = 10;
43181 this.viewMin = 0;
43182 this.viewSize = 2;
43183 this.smallIncrement = 1;
43184 this._onscroll = [];
43185 this._screenToOffsetScale = 1.0;
43186 this.createView(parentElement, layoutKind);
43187 var that = this;
43188 this._element.addEventListener("mousedown", function (e) { that.onBackgroundMouseDown(e); });
43189 this._middleBar.addEventListener("mousedown", function (e) { that.onMiddleBarMouseDown(e); });
43190 this._timerHandle = undefined;
43191 this._visible = true;
43192 this.element["winControl"] = this;
43193 $(this._touchPanel).addClass(UNSELECTABLE_CLASS_NAME);
43194 }
43195 Scrollbar.prototype.scrollBy = function (delta) {
43196 this.scrollTo(this.viewMin + delta);
43197 };
43198 Scrollbar.prototype.scrollUp = function () {
43199 this.scrollBy(-this.smallIncrement);
43200 };
43201 Scrollbar.prototype.scrollDown = function () {
43202 this.scrollBy(this.smallIncrement);
43203 };
43204 Scrollbar.prototype.scrollPageUp = function () {
43205 this.scrollBy(-this.viewSize);
43206 };
43207 Scrollbar.prototype.scrollPageDown = function () {
43208 this.scrollBy(this.viewSize);
43209 };
43210 Object.defineProperty(Scrollbar.prototype, "width", {
43211 get: function () {
43212 return this._width;
43213 },
43214 set: function (value) {
43215 this._width = value;
43216 this._element.style.width = value;
43217 this.invalidateArrange();
43218 },
43219 enumerable: true,
43220 configurable: true
43221 });
43222 Object.defineProperty(Scrollbar.prototype, "height", {
43223 get: function () {
43224 return this._height;
43225 },
43226 set: function (value) {
43227 this._height = value;
43228 this._element.style.height = value;
43229 this.invalidateArrange();
43230 },
43231 enumerable: true,
43232 configurable: true
43233 });
43234 Scrollbar.prototype.refresh = function () {
43235 debug.assertFail("PureVirtualMethod: Scrollbar.refresh()");
43236 };
43237 Object.defineProperty(Scrollbar.prototype, "element", {
43238 get: function () {
43239 return this._element;
43240 },
43241 enumerable: true,
43242 configurable: true
43243 });
43244 Object.defineProperty(Scrollbar.prototype, "maxButton", {
43245 get: function () {
43246 return this._maxButton;
43247 },
43248 enumerable: true,
43249 configurable: true
43250 });
43251 Object.defineProperty(Scrollbar.prototype, "middleBar", {
43252 get: function () {
43253 return this._middleBar;
43254 },
43255 enumerable: true,
43256 configurable: true
43257 });
43258 Scrollbar.prototype._scrollSmallIncrement = function (direction) {
43259 this.scrollBy(this.smallIncrement * direction);
43260 };
43261 Object.defineProperty(Scrollbar.prototype, "visible", {
43262 get: function () {
43263 return this._visible;
43264 },
43265 enumerable: true,
43266 configurable: true
43267 });
43268 Object.defineProperty(Scrollbar.prototype, "isInMouseCapture", {
43269 get: function () {
43270 return this._timerHandle !== undefined;
43271 },
43272 enumerable: true,
43273 configurable: true
43274 });
43275 Scrollbar.prototype.show = function (value) {
43276 this._visible = value;
43277 this.element.style.visibility = value ? "visible" : "hidden";
43278 this.invalidateArrange();
43279 };
43280 Scrollbar.prototype._getMouseOffset = function (event) {
43281 if (event.offsetX !== undefined)
43282 return { x: event.offsetX, y: event.offsetY };
43283 if (event.layerX !== undefined)
43284 return { x: event.layerX, y: event.layerY };
43285 return { x: event.screenX, y: event.screenY };
43286 };
43287 Scrollbar.prototype._getOffsetXDelta = function (event) {
43288 return (event.screenX - this._screenPrevMousePos.x) / this._screenToOffsetScale;
43289 };
43290 Scrollbar.prototype._getOffsetYDelta = function (event) {
43291 return (event.screenY - this._screenPrevMousePos.y) / this._screenToOffsetScale;
43292 };
43293 Scrollbar.prototype._getOffsetXTouchDelta = function (event) {
43294 return this._getMouseOffset(event).x - this._offsetTouchPrevPos.x;
43295 };
43296 Scrollbar.prototype._getOffsetYTouchDelta = function (event) {
43297 return this._getMouseOffset(event).y - this._offsetTouchPrevPos.y;
43298 };
43299 Scrollbar.prototype.initTouch = function (panel, allowMouseDrag) {
43300 var _this = this;
43301 this._touchPanel = panel;
43302 this._allowMouseDrag = allowMouseDrag === undefined ? true : allowMouseDrag;
43303 if ("ontouchmove" in panel) {
43304 panel.addEventListener("touchstart", function (e) { return _this.onTouchStart(e); });
43305 panel.addEventListener("touchmove", function (e) { return _this.onTouchMove(e); });
43306 panel.addEventListener("touchend", function (e) { return _this.onTouchEnd(e); });
43307 }
43308 else {
43309 panel.addEventListener("mousedown", function (e) { return _this.onTouchMouseDown(e); });
43310 panel.addEventListener("mousemove", function (e) { return _this.onTouchMouseMove(e); });
43311 panel.addEventListener("mouseup", function (e) { return _this.onTouchMouseUp(e); });
43312 }
43313 };
43314 Scrollbar.prototype.onTouchStart = function (e) {
43315 if (e.touches.length === 1) {
43316 this.onTouchMouseDown(e.touches[0]);
43317 }
43318 };
43319 Scrollbar.prototype.onTouchMove = function (e) {
43320 if (e.touches.length === 1) {
43321 if (e.preventDefault)
43322 e.preventDefault();
43323 this.onTouchMouseMove(e.touches[0]);
43324 }
43325 };
43326 Scrollbar.prototype.onTouchEnd = function (e) {
43327 this.onTouchMouseUp(e.touches.length === 1 ? e.touches[0] : e, true);
43328 };
43329 Scrollbar.prototype.onTouchMouseDown = function (e) {
43330 // except IE touch cancels mouse so not need for detection. For IE touch and mouse difference is detected by a flag.
43331 if (!this._allowMouseDrag &&
43332 e["pointerType"] === MSPointerEvent.MSPOINTER_TYPE_MOUSE) {
43333 return;
43334 }
43335 if ("setCapture" in this._touchPanel) {
43336 this._touchPanel.setCapture(true);
43337 }
43338 this._offsetTouchPrevPos = this._offsetTouchStartPos = null;
43339 this._touchStarted = true;
43340 };
43341 Scrollbar.prototype._getOffsetTouchDelta = function (e) {
43342 debug.assertFail("PureVirtualMethod: Scrollbar._getOffsetTouchDelta()");
43343 return null;
43344 };
43345 Scrollbar.prototype.onTouchMouseMove = function (e) {
43346 if (this._touchStarted) {
43347 if (!this._offsetTouchStartPos) {
43348 this._offsetTouchPrevPos = this._offsetTouchStartPos = this._getMouseOffset(e);
43349 }
43350 var delta = this._getOffsetTouchDelta(e);
43351 if (delta !== 0) {
43352 this.scrollBy(-delta / this._getRunningSize(false) * this.viewSize);
43353 this._offsetTouchPrevPos = this._getMouseOffset(e);
43354 }
43355 if (e.preventDefault)
43356 e.preventDefault();
43357 e.cancelBubble = true;
43358 }
43359 };
43360 Scrollbar.prototype.onTouchMouseUp = function (e, bubble) {
43361 if (this._touchStarted) {
43362 if (this._offsetTouchStartPos) {
43363 var end = this._getMouseOffset(e);
43364 if (!bubble && (Math.abs(this._offsetTouchStartPos.x - end.x) > 3 || Math.abs(this._offsetTouchStartPos.y - end.y) > 3)) {
43365 if (e.preventDefault)
43366 e.preventDefault();
43367 e.cancelBubble = true;
43368 }
43369 }
43370 }
43371 if ("releaseCapture" in this._touchPanel) {
43372 this._touchPanel.releaseCapture();
43373 }
43374 this._touchStarted = false;
43375 };
43376 Scrollbar.prototype.registerElementForMouseWheelScrolling = function (element) {
43377 var _this = this;
43378 element.addEventListener("mousewheel", function (e) { _this.onMouseWheel(e); });
43379 element.addEventListener("DOMMouseScroll", function (e) { _this.onFireFoxMouseWheel(e); });
43380 };
43381 Scrollbar.prototype.createView = function (parentElement, layoutKind) {
43382 this._element = document.createElement("div");
43383 this._element.className = Scrollbar.className;
43384 this._element.setAttribute("drag-resize-disabled", "true");
43385 if (layoutKind === 0 /* Canvas */)
43386 parentElement.appendChild(this._element);
43387 this._minButton = new ScrollbarButton(this, -1);
43388 this._maxButton = new ScrollbarButton(this, 1);
43389 this._middleBar = document.createElement("div");
43390 this._middleBar.className = Scrollbar.barClassName;
43391 this._element.appendChild(this._middleBar);
43392 };
43393 Scrollbar.prototype.scrollTo = function (pos) {
43394 var viewMin = Math.min(this.max - this.viewSize, Math.max(this.min, pos));
43395 if (viewMin !== this.viewMin) {
43396 this.viewMin = viewMin;
43397 fire(this._onscroll, null);
43398 }
43399 };
43400 Scrollbar.prototype._scrollByPage = function (event) {
43401 debug.assertFail("PureVirtualMethod: Scrollbar._scrollByPage()");
43402 };
43403 Scrollbar.prototype._getRunningSize = function (net) {
43404 debug.assertFail("PureVirtualMethod: Scrollbar._getRunningSize()");
43405 return null;
43406 };
43407 Scrollbar.prototype._getOffsetDelta = function (event) {
43408 debug.assertFail("PureVirtualMethod: Scrollbar._getOffsetDelta()");
43409 return null;
43410 };
43411 Scrollbar.prototype.scroll = function (event) {
43412 var delta = this._getOffsetDelta(event) / this._getRunningSize(true) * (this.max - this.min);
43413 if (delta < 0) {
43414 if (this._getScreenMousePos(event) >= this._screenMaxMousePos) {
43415 return;
43416 }
43417 }
43418 else if (delta > 0) {
43419 if (this._getScreenMousePos(event) <= this._screenMinMousePos) {
43420 return;
43421 }
43422 }
43423 this.scrollBy(delta);
43424 };
43425 Object.defineProperty(Scrollbar.prototype, "actualWidth", {
43426 get: function () {
43427 if (this._actualWidth === undefined) {
43428 this.arrange();
43429 }
43430 return this._actualWidth;
43431 },
43432 enumerable: true,
43433 configurable: true
43434 });
43435 Object.defineProperty(Scrollbar.prototype, "actualHeight", {
43436 get: function () {
43437 if (!this._actualHeight === undefined) {
43438 this.arrange();
43439 }
43440 return this._actualHeight;
43441 },
43442 enumerable: true,
43443 configurable: true
43444 });
43445 Object.defineProperty(Scrollbar.prototype, "actualButtonWidth", {
43446 get: function () {
43447 if (!this._actualButtonWidth === undefined) {
43448 this.arrange();
43449 }
43450 return this._actualButtonWidth;
43451 },
43452 enumerable: true,
43453 configurable: true
43454 });
43455 Object.defineProperty(Scrollbar.prototype, "actualButtonHeight", {
43456 get: function () {
43457 if (!this._actualButtonHeight === undefined) {
43458 this.arrange();
43459 }
43460 return this._actualButtonHeight;
43461 },
43462 enumerable: true,
43463 configurable: true
43464 });
43465 Scrollbar.prototype.arrange = function () {
43466 if (!this._actualWidth) {
43467 this._actualWidth = this._element.offsetWidth;
43468 this._actualHeight = this._element.offsetHeight;
43469 this._actualButtonWidth = this._calculateButtonWidth();
43470 this._actualButtonHeight = this._calculateButtonHeight();
43471 this._minButton.arrange(this._actualButtonWidth, this._actualButtonHeight, this._getMinButtonAngle());
43472 this._maxButton.arrange(this._actualButtonWidth, this._actualButtonHeight, this._getMaxButtonAngle());
43473 this._setMaxButtonPosition();
43474 }
43475 };
43476 Scrollbar.prototype._calculateButtonWidth = function () {
43477 debug.assertFail("PureVirtualMethod: Scrollbar._calculateButtonWidth()");
43478 return null;
43479 };
43480 Scrollbar.prototype._calculateButtonHeight = function () {
43481 debug.assertFail("PureVirtualMethod: Scrollbar._calculateButtonHeight()");
43482 return null;
43483 };
43484 Scrollbar.prototype._getMinButtonAngle = function () {
43485 debug.assertFail("PureVirtualMethod: Scrollbar._getMinButtonAngle()");
43486 return null;
43487 };
43488 Scrollbar.prototype._getMaxButtonAngle = function () {
43489 debug.assertFail("PureVirtualMethod: Scrollbar._getMaxButtonAngle()");
43490 return null;
43491 };
43492 Scrollbar.prototype._setMaxButtonPosition = function () {
43493 debug.assertFail("PureVirtualMethod: Scrollbar._setMaxButtonPosition()");
43494 };
43495 Scrollbar.prototype.invalidateArrange = function () {
43496 this._actualWidth = undefined;
43497 this._actualHeight = undefined;
43498 this._actualButtonWidth = undefined;
43499 this._actualButtonHeight = undefined;
43500 };
43501 Scrollbar.prototype.onHoldBackgroundMouseDown = function (event) {
43502 var _this = this;
43503 var holdDelay = this._timerHandle ?
43504 Scrollbar.ScrollbarBackgroundMousedownHoldDelay :
43505 Scrollbar.ScrollbarBackgroundFirstTimeMousedownHoldDelay;
43506 this._timerHandle = setTimeout(function () {
43507 _this.onBackgroundMouseDown(event);
43508 }, holdDelay);
43509 };
43510 Scrollbar.prototype.onBackgroundMouseDown = function (event) {
43511 var that = this;
43512 clearTimeout(this._timerHandle);
43513 if (!this._backgroundMouseUpWrapper) {
43514 event.cancelBubble = true;
43515 this._backgroundMouseUpWrapper = function (event) { that.onBackgroundMouseUp(event); };
43516 Scrollbar.addDocumentMouseUpEvent(this._backgroundMouseUpWrapper);
43517 }
43518 this._scrollByPage(event);
43519 this.refresh();
43520 this.onHoldBackgroundMouseDown(event);
43521 if (event.preventDefault)
43522 event.preventDefault(); // prevent dragging
43523 };
43524 Scrollbar.prototype.onBackgroundMouseUp = function (event) {
43525 clearTimeout(this._timerHandle);
43526 this._timerHandle = undefined;
43527 Scrollbar.removeDocumentMouseUpEvent(this._backgroundMouseUpWrapper);
43528 this._backgroundMouseUpWrapper = undefined;
43529 };
43530 Scrollbar.prototype.getPinchZoomY = function () {
43531 return document.documentElement.clientHeight / window.innerHeight;
43532 };
43533 Scrollbar.prototype.onMiddleBarMouseDown = function (event) {
43534 event.cancelBubble = true;
43535 this._screenPrevMousePos = { x: event.screenX, y: event.screenY };
43536 this._screenMinMousePos = this._getScreenMousePos(event) - (this._getScreenContextualLeft(this._middleBar) - this._getScreenContextualRight(this._minButton.element));
43537 this._screenMaxMousePos = this._getScreenMousePos(event) + (this._getScreenContextualLeft(this._maxButton.element) - this._getScreenContextualRight(this._middleBar));
43538 this._screenToOffsetScale = controls.HTMLElementUtils.getAccumulatedScale(this.element) * this.getPinchZoomY();
43539 var that = this;
43540 this._middleBarMouseMoveWrapper = function (e) { that.onMiddleBarMouseMove(e); };
43541 Scrollbar.addDocumentMouseMoveEvent(this._middleBarMouseMoveWrapper);
43542 this._middleBarMouseUpWrapper = function (e) { that.onMiddleBarMouseUp(e); };
43543 Scrollbar.addDocumentMouseUpEvent(this._middleBarMouseUpWrapper);
43544 if (event.preventDefault)
43545 event.preventDefault(); // prevent dragging
43546 };
43547 Scrollbar.prototype.onMiddleBarMouseMove = function (event) {
43548 if (!this._screenPrevMousePos) {
43549 return;
43550 }
43551 this.scroll(event);
43552 this.refresh();
43553 this._screenPrevMousePos = { x: event.screenX, y: event.screenY };
43554 };
43555 Scrollbar.prototype.onMiddleBarMouseUp = function (event) {
43556 this._screenPrevMousePos = undefined;
43557 Scrollbar.removeDocumentMouseMoveEvent(this._middleBarMouseMoveWrapper);
43558 this._middleBarMouseMoveWrapper = undefined;
43559 Scrollbar.removeDocumentMouseUpEvent(this._middleBarMouseUpWrapper);
43560 this._middleBarMouseUpWrapper = undefined;
43561 if (event.preventDefault)
43562 event.preventDefault(); // prevent other events
43563 };
43564 Scrollbar.prototype._getScreenContextualLeft = function (element) {
43565 debug.assertFail("PureVirtualMethod: Scrollbar._getScreenContextualLeft()");
43566 return null;
43567 };
43568 Scrollbar.prototype._getScreenContextualRight = function (element) {
43569 debug.assertFail("PureVirtualMethod: Scrollbar._getScreenContextualRight()");
43570 return null;
43571 };
43572 Scrollbar.prototype.onMouseWheel = function (e) {
43573 if (e.wheelDelta) {
43574 this.mouseWheel(e.wheelDelta);
43575 }
43576 e.preventDefault();
43577 };
43578 Scrollbar.prototype.onFireFoxMouseWheel = function (e) {
43579 if (e.detail) {
43580 this.mouseWheel(-e.detail);
43581 }
43582 e.preventDefault();
43583 };
43584 Scrollbar.prototype.mouseWheel = function (delta) {
43585 if (this.visible) {
43586 if (delta < 0) {
43587 delta = Math.min(-Scrollbar.MouseWheelRange, delta);
43588 }
43589 else if (delta > 0) {
43590 delta = Math.max(Scrollbar.MouseWheelRange, delta);
43591 }
43592 this.scrollBy(-delta / Scrollbar.MouseWheelRange * this.smallIncrement);
43593 }
43594 };
43595 Scrollbar.prototype._getScreenMousePos = function (event) {
43596 debug.assertFail("PureVirtualMethod: Scrollbar._getScreenMousePos()");
43597 return null;
43598 };
43599 Scrollbar.addDocumentMouseUpEvent = function (func) {
43600 document.addEventListener("mouseup", func);
43601 };
43602 Scrollbar.removeDocumentMouseUpEvent = function (func) {
43603 document.removeEventListener("mouseup", func);
43604 };
43605 Scrollbar.addDocumentMouseMoveEvent = function (func) {
43606 document.addEventListener("mousemove", func);
43607 };
43608 Scrollbar.removeDocumentMouseMoveEvent = function (func) {
43609 document.removeEventListener("mousemove", func);
43610 };
43611 Scrollbar.DefaultScrollbarWidth = "15px"; // protected
43612 Scrollbar.ScrollbarBackgroundFirstTimeMousedownHoldDelay = 500;
43613 Scrollbar.ScrollbarBackgroundMousedownHoldDelay = 50;
43614 Scrollbar.MouseWheelRange = 120;
43615 Scrollbar.className = "scroll-bar-div";
43616 Scrollbar.barClassName = "scroll-bar-part-bar";
43617 Scrollbar.arrowClassName = "scroll-bar-part-arrow";
43618 return Scrollbar;
43619 }());
43620 controls.Scrollbar = Scrollbar;
43621 /** Horizontal Scrollbar */
43622 var HorizontalScrollbar = (function (_super) {
43623 __extends(HorizontalScrollbar, _super);
43624 function HorizontalScrollbar(parentElement, layoutKind) {
43625 _super.call(this, parentElement, layoutKind);
43626 this.height = Scrollbar.DefaultScrollbarWidth;
43627 }
43628 HorizontalScrollbar.prototype._calculateButtonWidth = function () {
43629 return Math.min(this.actualWidth / 2, Math.max(this.actualHeight, ScrollbarButton.MIN_WIDTH));
43630 };
43631 HorizontalScrollbar.prototype._calculateButtonHeight = function () {
43632 return this.actualHeight;
43633 };
43634 HorizontalScrollbar.prototype._getMinButtonAngle = function () {
43635 return -180;
43636 };
43637 HorizontalScrollbar.prototype._getMaxButtonAngle = function () {
43638 return 0;
43639 };
43640 HorizontalScrollbar.prototype._setMaxButtonPosition = function () {
43641 controls.HTMLElementUtils.setElementLeft(this.maxButton.element, this.actualWidth - this.actualButtonWidth);
43642 };
43643 HorizontalScrollbar.prototype.refresh = function () {
43644 this.arrange();
43645 var runningSize = this.actualWidth - this.actualButtonWidth * 2 - 2;
43646 var barSize = this.viewSize / (this.max - this.min) * runningSize;
43647 if (barSize < this.MIN_BAR_SIZE) {
43648 runningSize -= this.MIN_BAR_SIZE - barSize;
43649 barSize = this.MIN_BAR_SIZE;
43650 }
43651 if (runningSize < 0) {
43652 runningSize = 0;
43653 barSize = 0;
43654 }
43655 barSize = Math.min(barSize, runningSize);
43656 var barPos = this.viewMin / (this.max - this.min) * runningSize;
43657 controls.HTMLElementUtils.setElementWidth(this.middleBar, barSize);
43658 controls.HTMLElementUtils.setElementHeight(this.middleBar, this.actualHeight);
43659 controls.HTMLElementUtils.setElementLeft(this.middleBar, this.actualButtonWidth + 1 + barPos);
43660 };
43661 HorizontalScrollbar.prototype.show = function (visible) {
43662 if (visible === this.visible)
43663 return;
43664 _super.prototype.show.call(this, visible);
43665 if (visible) {
43666 this.element.style.height = this.height;
43667 }
43668 else {
43669 controls.HTMLElementUtils.setElementHeight(this.element, 0);
43670 }
43671 };
43672 HorizontalScrollbar.prototype._scrollByPage = function (event) {
43673 var left = this.middleBar.offsetLeft;
43674 var right = left + this.middleBar.offsetWidth;
43675 var x = (event.offsetX === undefined) ? event.layerX : event.offsetX;
43676 if (x > right) {
43677 this.scrollPageDown();
43678 }
43679 else if (x < left) {
43680 this.scrollPageUp();
43681 }
43682 };
43683 HorizontalScrollbar.prototype._getRunningSize = function (net) {
43684 var result = this.actualWidth;
43685 if (net) {
43686 var barMinPos = this.actualButtonWidth + 1;
43687 result -= barMinPos * 2;
43688 var barSize = result * (this.viewSize / (this.max - this.min));
43689 if (barSize < this.MIN_BAR_SIZE)
43690 result -= this.MIN_BAR_SIZE - barSize;
43691 }
43692 return result;
43693 };
43694 HorizontalScrollbar.prototype._getOffsetDelta = function (event) {
43695 return this._getOffsetXDelta(event);
43696 };
43697 HorizontalScrollbar.prototype._getOffsetTouchDelta = function (e) {
43698 return this._getOffsetXTouchDelta(e);
43699 };
43700 HorizontalScrollbar.prototype._getScreenContextualLeft = function (element) {
43701 return element.getBoundingClientRect().left;
43702 };
43703 HorizontalScrollbar.prototype._getScreenContextualRight = function (element) {
43704 return element.getBoundingClientRect().right;
43705 };
43706 HorizontalScrollbar.prototype._getScreenMousePos = function (event) {
43707 return event.screenX;
43708 };
43709 return HorizontalScrollbar;
43710 }(Scrollbar));
43711 controls.HorizontalScrollbar = HorizontalScrollbar;
43712 /** Vertical Scrollbar */
43713 var VerticalScrollbar = (function (_super) {
43714 __extends(VerticalScrollbar, _super);
43715 function VerticalScrollbar(parentElement, layoutKind) {
43716 _super.call(this, parentElement, layoutKind);
43717 this.width = Scrollbar.DefaultScrollbarWidth;
43718 }
43719 VerticalScrollbar.prototype._calculateButtonWidth = function () {
43720 return this.actualWidth;
43721 };
43722 VerticalScrollbar.prototype._calculateButtonHeight = function () {
43723 return Math.min(this.actualHeight / 2, Math.max(this.actualWidth, ScrollbarButton.MIN_WIDTH));
43724 };
43725 VerticalScrollbar.prototype._getMinButtonAngle = function () {
43726 return -90;
43727 };
43728 VerticalScrollbar.prototype._getMaxButtonAngle = function () {
43729 return 90;
43730 };
43731 VerticalScrollbar.prototype._setMaxButtonPosition = function () {
43732 controls.HTMLElementUtils.setElementTop(this.maxButton.element, this.actualHeight - this.actualButtonHeight);
43733 };
43734 VerticalScrollbar.prototype.refresh = function () {
43735 this.arrange();
43736 var runningSize = this.actualHeight - this.actualButtonHeight * 2 - 2;
43737 var barSize = this.viewSize / (this.max - this.min) * runningSize;
43738 if (barSize < this.MIN_BAR_SIZE) {
43739 runningSize -= this.MIN_BAR_SIZE - barSize;
43740 barSize = this.MIN_BAR_SIZE;
43741 }
43742 if (runningSize < 0) {
43743 runningSize = 0;
43744 barSize = 0;
43745 }
43746 var barPos = this.viewMin / (this.max - this.min) * runningSize;
43747 controls.HTMLElementUtils.setElementWidth(this.middleBar, this.actualWidth);
43748 controls.HTMLElementUtils.setElementHeight(this.middleBar, barSize);
43749 controls.HTMLElementUtils.setElementTop(this.middleBar, this.actualButtonHeight + 1 + barPos);
43750 };
43751 VerticalScrollbar.prototype.show = function (visible) {
43752 if (visible === this.visible)
43753 return;
43754 _super.prototype.show.call(this, visible);
43755 if (visible) {
43756 this.element.style.width = this.width;
43757 }
43758 else {
43759 controls.HTMLElementUtils.setElementWidth(this.element, 0);
43760 }
43761 };
43762 VerticalScrollbar.prototype._scrollByPage = function (event) {
43763 var top = this.middleBar.offsetTop;
43764 var bottom = top + this.middleBar.offsetHeight;
43765 var y = (event.offsetY === undefined) ? event.layerY : event.offsetY;
43766 if (y > bottom) {
43767 this.scrollPageDown();
43768 }
43769 else if (y < top) {
43770 this.scrollPageUp();
43771 }
43772 };
43773 VerticalScrollbar.prototype._getRunningSize = function (net) {
43774 var result = this.actualHeight;
43775 if (net) {
43776 var barMinPos = this.actualButtonHeight + 1;
43777 result -= barMinPos * 2;
43778 var barSize = result * (this.viewSize / (this.max - this.min));
43779 if (barSize < this.MIN_BAR_SIZE)
43780 result -= this.MIN_BAR_SIZE - barSize;
43781 }
43782 return result;
43783 };
43784 VerticalScrollbar.prototype._getOffsetDelta = function (event) {
43785 return this._getOffsetYDelta(event);
43786 };
43787 VerticalScrollbar.prototype._getOffsetTouchDelta = function (e) {
43788 return this._getOffsetYTouchDelta(e);
43789 };
43790 VerticalScrollbar.prototype._getScreenContextualLeft = function (element) {
43791 return element.getBoundingClientRect().top;
43792 };
43793 VerticalScrollbar.prototype._getScreenContextualRight = function (element) {
43794 return element.getBoundingClientRect().bottom;
43795 };
43796 VerticalScrollbar.prototype._getScreenMousePos = function (event) {
43797 return event.screenY;
43798 };
43799 return VerticalScrollbar;
43800 }(Scrollbar));
43801 controls.VerticalScrollbar = VerticalScrollbar;
43802 })(controls = visuals.controls || (visuals.controls = {}));
43803 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
43804})(powerbi || (powerbi = {}));
43805/*
43806 * Power BI Visualizations
43807 *
43808 * Copyright (c) Microsoft Corporation
43809 * All rights reserved.
43810 * MIT License
43811 *
43812 * Permission is hereby granted, free of charge, to any person obtaining a copy
43813 * of this software and associated documentation files (the ""Software""), to deal
43814 * in the Software without restriction, including without limitation the rights
43815 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43816 * copies of the Software, and to permit persons to whom the Software is
43817 * furnished to do so, subject to the following conditions:
43818 *
43819 * The above copyright notice and this permission notice shall be included in
43820 * all copies or substantial portions of the Software.
43821 *
43822 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43823 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43824 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43825 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43826 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43827 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43828 * THE SOFTWARE.
43829 */
43830var powerbi;
43831(function (powerbi) {
43832 var visuals;
43833 (function (visuals) {
43834 var controls;
43835 (function (controls) {
43836 var internal;
43837 (function (internal) {
43838 var UNSELECTABLE_CLASS_NAME = "unselectable";
43839 /** This class is responsible for tablix header resizing */
43840 var TablixResizer = (function () {
43841 function TablixResizer(element, handler) {
43842 this._element = element;
43843 this._handler = handler;
43844 this._elementMouseDownWrapper = null;
43845 this._elementMouseMoveWrapper = null;
43846 this._elementMouseOutWrapper = null;
43847 this._documentMouseMoveWrapper = null;
43848 this._documentMouseUpWrapper = null;
43849 this._startMousePosition = null;
43850 this._originalCursor = null;
43851 }
43852 TablixResizer.addDocumentMouseUpEvent = function (listener) {
43853 document.addEventListener("mouseup", listener);
43854 };
43855 TablixResizer.removeDocumentMouseUpEvent = function (listener) {
43856 document.removeEventListener("mouseup", listener);
43857 };
43858 TablixResizer.addDocumentMouseMoveEvent = function (listener) {
43859 document.addEventListener("mousemove", listener);
43860 };
43861 TablixResizer.removeDocumentMouseMoveEvent = function (listener) {
43862 document.removeEventListener("mousemove", listener);
43863 };
43864 TablixResizer.getMouseCoordinates = function (event) {
43865 return { x: event.pageX, y: event.pageY };
43866 };
43867 TablixResizer.getMouseCoordinateDelta = function (previous, current) {
43868 return { x: current.x - previous.x, y: current.y - previous.y };
43869 };
43870 TablixResizer.prototype.initialize = function () {
43871 var _this = this;
43872 this._elementMouseDownWrapper = function (e) { return _this.onElementMouseDown(e); };
43873 this._element.addEventListener("mousedown", this._elementMouseDownWrapper);
43874 this._elementMouseMoveWrapper = function (e) { return _this.onElementMouseMove(e); };
43875 this._element.addEventListener("mousemove", this._elementMouseMoveWrapper);
43876 this._elementMouseOutWrapper = function (e) { return _this.onElementMouseOut(e); };
43877 this._element.addEventListener("mouseout", this._elementMouseOutWrapper);
43878 this._elementMouseDoubleClickOutWrapper = function (e) { return _this.onElementMouseDoubleClick(e); };
43879 this._element.addEventListener("dblclick", this._elementMouseDoubleClickOutWrapper);
43880 };
43881 TablixResizer.prototype.uninitialize = function () {
43882 this._element.removeEventListener("mousedown", this._elementMouseDownWrapper);
43883 this._elementMouseDownWrapper = null;
43884 this._element.removeEventListener("mousemove", this._elementMouseMoveWrapper);
43885 this._elementMouseMoveWrapper = null;
43886 this._element.removeEventListener("mouseout", this._elementMouseOutWrapper);
43887 this._elementMouseOutWrapper = null;
43888 this._element.removeEventListener("dblclick", this._elementMouseDoubleClickOutWrapper);
43889 this._elementMouseDoubleClickOutWrapper = null;
43890 };
43891 Object.defineProperty(TablixResizer.prototype, "cell", {
43892 get: function () {
43893 // abstract
43894 debug.assertFail("PureVirtualMethod: TablixResizer.cell");
43895 return null;
43896 },
43897 enumerable: true,
43898 configurable: true
43899 });
43900 Object.defineProperty(TablixResizer.prototype, "element", {
43901 get: function () {
43902 return this._element;
43903 },
43904 enumerable: true,
43905 configurable: true
43906 });
43907 // Protected
43908 TablixResizer.prototype._hotSpot = function (position) {
43909 // abstract
43910 debug.assertFail("PureVirtualMethod: TablixResizer._hotSpot");
43911 return false;
43912 };
43913 TablixResizer.prototype.onElementMouseDown = function (event) {
43914 var _this = this;
43915 var position = TablixResizer.getMouseCoordinates(event);
43916 if (!this._hotSpot(position))
43917 return;
43918 if ("setCapture" in this._element) {
43919 this._element.setCapture();
43920 }
43921 event.cancelBubble = true;
43922 this._startMousePosition = position;
43923 this._documentMouseMoveWrapper = function (e) { return _this.onDocumentMouseMove(e); };
43924 TablixResizer.addDocumentMouseMoveEvent(this._documentMouseMoveWrapper);
43925 this._documentMouseUpWrapper = function (e) { return _this.onDocumentMouseUp(e); };
43926 TablixResizer.addDocumentMouseUpEvent(this._documentMouseUpWrapper);
43927 if (document.documentElement) {
43928 this._originalCursor = document.documentElement.style.cursor;
43929 document.documentElement.style.cursor = TablixResizer.resizeCursor;
43930 }
43931 this._handler.onStartResize(this.cell, this._startMousePosition.x, this._startMousePosition.y);
43932 };
43933 TablixResizer.prototype.onElementMouseMove = function (event) {
43934 if (!this._startMousePosition) {
43935 if (this._hotSpot(TablixResizer.getMouseCoordinates(event))) {
43936 if (this._originalCursor === null) {
43937 this._originalCursor = this._element.style.cursor;
43938 this._element.style.cursor = TablixResizer.resizeCursor;
43939 }
43940 }
43941 else {
43942 if (this._originalCursor !== null) {
43943 this._element.style.cursor = this._originalCursor;
43944 this._originalCursor = null;
43945 }
43946 }
43947 }
43948 };
43949 TablixResizer.prototype.onElementMouseOut = function (event) {
43950 if (!this._startMousePosition) {
43951 if (this._originalCursor !== null) {
43952 this._element.style.cursor = this._originalCursor;
43953 this._originalCursor = null;
43954 }
43955 }
43956 };
43957 TablixResizer.prototype.onElementMouseDoubleClick = function (event) {
43958 if (!this._hotSpot(TablixResizer.getMouseCoordinates(event)))
43959 return;
43960 this._handler.onReset(this.cell);
43961 };
43962 TablixResizer.prototype.onDocumentMouseMove = function (event) {
43963 if (!this._startMousePosition)
43964 return;
43965 var delta = TablixResizer.getMouseCoordinateDelta(this._startMousePosition, TablixResizer.getMouseCoordinates(event));
43966 this._handler.onResize(this.cell, delta.x, delta.y);
43967 // Need to prevent default to prevent mouse move from triggering other effects (VSTS 6720639)
43968 event.preventDefault();
43969 };
43970 TablixResizer.prototype.onDocumentMouseUp = function (event) {
43971 this._startMousePosition = null;
43972 if ("releaseCapture" in this._element) {
43973 this._element.releaseCapture();
43974 }
43975 TablixResizer.removeDocumentMouseMoveEvent(this._documentMouseMoveWrapper);
43976 this._documentMouseMoveWrapper = null;
43977 TablixResizer.removeDocumentMouseUpEvent(this._documentMouseUpWrapper);
43978 this._documentMouseUpWrapper = null;
43979 if (document.documentElement)
43980 document.documentElement.style.cursor = this._originalCursor;
43981 if (event.preventDefault)
43982 event.preventDefault(); // prevent other events
43983 this._handler.onEndResize(this.cell);
43984 };
43985 TablixResizer.resizeHandleSize = 4;
43986 TablixResizer.resizeCursor = "e-resize";
43987 return TablixResizer;
43988 }());
43989 internal.TablixResizer = TablixResizer;
43990 var TablixDomResizer = (function (_super) {
43991 __extends(TablixDomResizer, _super);
43992 function TablixDomResizer(cell, element, handler) {
43993 _super.call(this, element, handler);
43994 this._cell = cell;
43995 }
43996 Object.defineProperty(TablixDomResizer.prototype, "cell", {
43997 get: function () {
43998 return this._cell;
43999 },
44000 enumerable: true,
44001 configurable: true
44002 });
44003 // Protected
44004 TablixDomResizer.prototype._hotSpot = function (position) {
44005 return position.x >= this.element.getBoundingClientRect().right - TablixResizer.resizeHandleSize;
44006 };
44007 return TablixDomResizer;
44008 }(TablixResizer));
44009 internal.TablixDomResizer = TablixDomResizer;
44010 var TablixCellPresenter = (function () {
44011 function TablixCellPresenter(fitProportionally, layoutKind) {
44012 // Table cell will be created once needed
44013 this._tableCell = null;
44014 // Content element
44015 this._contentElement = internal.TablixUtils.createDiv();
44016 // Content Host
44017 this._contentHost = internal.TablixUtils.createDiv();
44018 this.layoutKind = layoutKind;
44019 this._contentElement.appendChild(this._contentHost);
44020 this._resizer = null;
44021 }
44022 TablixCellPresenter.prototype.initialize = function (owner) {
44023 this._owner = owner;
44024 };
44025 Object.defineProperty(TablixCellPresenter.prototype, "owner", {
44026 get: function () {
44027 return this._owner;
44028 },
44029 enumerable: true,
44030 configurable: true
44031 });
44032 TablixCellPresenter.prototype.registerTableCell = function (tableCell) {
44033 this._tableCell = tableCell;
44034 tableCell.appendChild(this._contentElement);
44035 };
44036 Object.defineProperty(TablixCellPresenter.prototype, "tableCell", {
44037 get: function () {
44038 return this._tableCell;
44039 },
44040 enumerable: true,
44041 configurable: true
44042 });
44043 Object.defineProperty(TablixCellPresenter.prototype, "contentElement", {
44044 /**
44045 * Outer DIV
44046 */
44047 get: function () {
44048 return this._contentElement;
44049 },
44050 enumerable: true,
44051 configurable: true
44052 });
44053 Object.defineProperty(TablixCellPresenter.prototype, "contentHost", {
44054 /**
44055 * Inner DIV
44056 */
44057 get: function () {
44058 return this._contentHost;
44059 },
44060 enumerable: true,
44061 configurable: true
44062 });
44063 TablixCellPresenter.prototype.registerClickHandler = function (handler) {
44064 this._contentElement.onclick = handler;
44065 };
44066 TablixCellPresenter.prototype.unregisterClickHandler = function () {
44067 this._contentElement.onclick = null;
44068 };
44069 TablixCellPresenter.prototype.onContainerWidthChanged = function (value) {
44070 controls.HTMLElementUtils.setElementWidth(this._contentElement, value);
44071 };
44072 TablixCellPresenter.prototype.onContinerHeightChanged = function (height) {
44073 controls.HTMLElementUtils.setElementHeight(this._contentElement, height);
44074 };
44075 TablixCellPresenter.prototype.onColumnSpanChanged = function (value) {
44076 this._tableCell.colSpan = value;
44077 };
44078 TablixCellPresenter.prototype.onRowSpanChanged = function (value) {
44079 this._tableCell.rowSpan = value;
44080 };
44081 TablixCellPresenter.prototype.onTextAlignChanged = function (value) {
44082 this._tableCell.style.textAlign = value;
44083 };
44084 TablixCellPresenter.prototype.onClear = function () {
44085 this._contentHost.className = "";
44086 this._tableCell.className = "";
44087 };
44088 TablixCellPresenter.prototype.onHorizontalScroll = function (width, offset) {
44089 controls.HTMLElementUtils.setElementLeft(this._contentHost, offset);
44090 controls.HTMLElementUtils.setElementWidth(this._contentHost, width);
44091 };
44092 TablixCellPresenter.prototype.onVerticalScroll = function (height, offset) {
44093 controls.HTMLElementUtils.setElementTop(this._contentHost, offset);
44094 controls.HTMLElementUtils.setElementHeight(this._contentHost, height);
44095 };
44096 TablixCellPresenter.prototype.onInitializeScrolling = function () {
44097 controls.HTMLElementUtils.setElementLeft(this._contentHost, 0);
44098 controls.HTMLElementUtils.setElementTop(this._contentHost, 0);
44099 controls.HTMLElementUtils.setElementWidth(this._contentHost, -1);
44100 controls.HTMLElementUtils.setElementHeight(this._contentHost, -1);
44101 };
44102 TablixCellPresenter.prototype.enableHorizontalResize = function (enable, handler) {
44103 if (enable === (this._resizer !== null))
44104 return;
44105 if (enable) {
44106 this._resizer = new TablixDomResizer(this._owner, this._tableCell, handler);
44107 this._resizer.initialize();
44108 }
44109 else {
44110 this._resizer.uninitialize();
44111 this._resizer = null;
44112 }
44113 };
44114 /**
44115 * In order to allow dragging of the tableCell we need to
44116 * disable dragging of the container of the cell in IE.
44117 */
44118 TablixCellPresenter.prototype.disableDragResize = function () {
44119 this._tableCell.setAttribute(TablixCellPresenter._dragResizeDisabledAttributeName, "true");
44120 };
44121 // Attribute used to disable dragging in order to have cell resizing work.
44122 TablixCellPresenter._dragResizeDisabledAttributeName = "drag-resize-disabled";
44123 return TablixCellPresenter;
44124 }());
44125 internal.TablixCellPresenter = TablixCellPresenter;
44126 var TablixRowPresenter = (function () {
44127 function TablixRowPresenter(fitProportionally) {
44128 // Table row will be created once needed
44129 this._tableRow = null;
44130 this._fitProportionally = fitProportionally;
44131 }
44132 TablixRowPresenter.prototype.initialize = function (row) {
44133 this._row = row;
44134 };
44135 TablixRowPresenter.prototype.createCellPresenter = function (layoutKind) {
44136 return new TablixCellPresenter(this._fitProportionally, layoutKind);
44137 };
44138 TablixRowPresenter.prototype.registerRow = function (tableRow) {
44139 this._tableRow = tableRow;
44140 };
44141 TablixRowPresenter.prototype.onAppendCell = function (cell) {
44142 var presenter = cell._presenter;
44143 if (presenter.tableCell === null) {
44144 // For performance reason we use InsertCell() to create new table cells instead of AppendChild()
44145 // We use -1 to insert at the end (that's the cross-browser way of doing it)
44146 var tableCell = this._tableRow.insertCell(-1);
44147 presenter.registerTableCell(tableCell);
44148 }
44149 else {
44150 this._tableRow.appendChild(presenter.tableCell);
44151 }
44152 };
44153 TablixRowPresenter.prototype.onInsertCellBefore = function (cell, refCell) {
44154 debug.assertValue(refCell._presenter.tableCell, 'refTableCell');
44155 var presenter = cell._presenter;
44156 if (presenter.tableCell === null) {
44157 // For performance reasons we use InsertCell() to create new table cells instead of AppendChild()
44158 var tableCell = this._tableRow.insertCell(Math.max(0, refCell._presenter.tableCell.cellIndex - 1));
44159 presenter.registerTableCell(tableCell);
44160 }
44161 else {
44162 this._tableRow.insertBefore(cell._presenter.tableCell, refCell._presenter.tableCell);
44163 }
44164 };
44165 TablixRowPresenter.prototype.onRemoveCell = function (cell) {
44166 this._tableRow.removeChild(cell._presenter.tableCell);
44167 };
44168 TablixRowPresenter.prototype.getHeight = function () {
44169 return this.getCellHeight(this._row.getTablixCell());
44170 };
44171 TablixRowPresenter.prototype.getCellHeight = function (cell) {
44172 debug.assertFail("PureVirtualMethod: TablixRowPresenter.getCellHeight");
44173 return -1;
44174 };
44175 TablixRowPresenter.prototype.getCellContentHeight = function (cell) {
44176 debug.assertFail("PureVirtualMethod: TablixRowPresenter.getCellHeight");
44177 return -1;
44178 };
44179 Object.defineProperty(TablixRowPresenter.prototype, "tableRow", {
44180 get: function () {
44181 return this._tableRow;
44182 },
44183 enumerable: true,
44184 configurable: true
44185 });
44186 return TablixRowPresenter;
44187 }());
44188 internal.TablixRowPresenter = TablixRowPresenter;
44189 var DashboardRowPresenter = (function (_super) {
44190 __extends(DashboardRowPresenter, _super);
44191 function DashboardRowPresenter(gridPresenter, fitProportionally) {
44192 _super.call(this, fitProportionally);
44193 this._gridPresenter = gridPresenter;
44194 }
44195 DashboardRowPresenter.prototype.getCellHeight = function (cell) {
44196 return cell.containerHeight;
44197 };
44198 DashboardRowPresenter.prototype.getCellContentHeight = function (cell) {
44199 return cell.contentHeight;
44200 };
44201 return DashboardRowPresenter;
44202 }(TablixRowPresenter));
44203 internal.DashboardRowPresenter = DashboardRowPresenter;
44204 var CanvasRowPresenter = (function (_super) {
44205 __extends(CanvasRowPresenter, _super);
44206 function CanvasRowPresenter() {
44207 _super.apply(this, arguments);
44208 }
44209 CanvasRowPresenter.prototype.getCellHeight = function (cell) {
44210 return cell.containerHeight;
44211 };
44212 CanvasRowPresenter.prototype.getCellContentHeight = function (cell) {
44213 return cell.contentHeight;
44214 };
44215 return CanvasRowPresenter;
44216 }(TablixRowPresenter));
44217 internal.CanvasRowPresenter = CanvasRowPresenter;
44218 var TablixColumnPresenter = (function () {
44219 function TablixColumnPresenter() {
44220 }
44221 TablixColumnPresenter.prototype.initialize = function (column) {
44222 this._column = column;
44223 };
44224 TablixColumnPresenter.prototype.getWidth = function () {
44225 return this.getCellWidth(this._column.getTablixCell());
44226 };
44227 TablixColumnPresenter.prototype.getCellWidth = function (cell) {
44228 debug.assertFail("PureVirtualMethod: TablixColumnPresenter.getCellWidth");
44229 return -1;
44230 };
44231 TablixColumnPresenter.prototype.getCellContentWidth = function (cell) {
44232 debug.assertFail("PureVirtualMethod: TablixColumnPresenter.getCellContentWidth");
44233 return -1;
44234 };
44235 return TablixColumnPresenter;
44236 }());
44237 internal.TablixColumnPresenter = TablixColumnPresenter;
44238 var DashboardColumnPresenter = (function (_super) {
44239 __extends(DashboardColumnPresenter, _super);
44240 function DashboardColumnPresenter(gridPresenter) {
44241 _super.call(this);
44242 this._gridPresenter = gridPresenter;
44243 }
44244 DashboardColumnPresenter.prototype.getCellWidth = function (cell) {
44245 return this._gridPresenter.sizeComputationManager.cellWidth;
44246 };
44247 DashboardColumnPresenter.prototype.getCellContentWidth = function (cell) {
44248 return this._gridPresenter.sizeComputationManager.contentWidth;
44249 };
44250 return DashboardColumnPresenter;
44251 }(TablixColumnPresenter));
44252 internal.DashboardColumnPresenter = DashboardColumnPresenter;
44253 var CanvasColumnPresenter = (function (_super) {
44254 __extends(CanvasColumnPresenter, _super);
44255 function CanvasColumnPresenter(gridPresenter, index) {
44256 _super.call(this);
44257 this._gridPresenter = gridPresenter;
44258 this._columnIndex = index;
44259 }
44260 CanvasColumnPresenter.prototype.getCellWidth = function (cell) {
44261 var persistedWidth = this._gridPresenter.getPersistedCellWidth(this._columnIndex);
44262 // Because persistedWidth could be 0 check specifically for null or undefined
44263 if (_.isNumber(persistedWidth))
44264 return persistedWidth;
44265 if (!cell._presenter)
44266 return 0;
44267 return controls.HTMLElementUtils.getElementWidth(cell._presenter.tableCell);
44268 };
44269 CanvasColumnPresenter.prototype.getCellContentWidth = function (cell) {
44270 var persistedWidth = this._gridPresenter.getPersistedCellWidth(this._columnIndex);
44271 // Because persistedWidth could be 0 check specifically for null or undefined
44272 if (_.isNumber(persistedWidth))
44273 return persistedWidth;
44274 if (!cell._presenter)
44275 return 0;
44276 var requiredWidth = controls.HTMLElementUtils.getElementWidth(cell._presenter.contentElement);
44277 if (requiredWidth > 0 && cell.colSpan === 1)
44278 requiredWidth += 1; // Adding 1px because offsetWidth returns floored number, may risk getting ellipsis
44279 return requiredWidth;
44280 };
44281 return CanvasColumnPresenter;
44282 }(TablixColumnPresenter));
44283 internal.CanvasColumnPresenter = CanvasColumnPresenter;
44284 var TablixGridPresenter = (function () {
44285 function TablixGridPresenter(columnWidthManager) {
44286 // Main Table
44287 this._table = internal.TablixUtils.createTable();
44288 this._table.className = UNSELECTABLE_CLASS_NAME;
44289 // Footer Table
44290 this._footerTable = internal.TablixUtils.createTable();
44291 this._footerTable.className = UNSELECTABLE_CLASS_NAME;
44292 // ColumnWidthManager
44293 this._columnWidthManager = columnWidthManager;
44294 }
44295 TablixGridPresenter.prototype.initialize = function (owner, gridHost, footerHost, control) {
44296 this._owner = owner;
44297 gridHost.appendChild(this._table);
44298 footerHost.appendChild(this._footerTable);
44299 };
44300 TablixGridPresenter.prototype.getWidth = function () {
44301 debug.assertFail("PureVirtualMethod: TablixGridPresenter.getWidth");
44302 return -1;
44303 };
44304 TablixGridPresenter.prototype.getHeight = function () {
44305 debug.assertFail("PureVirtualMethod: TablixGridPresenter.getHeight");
44306 return -1;
44307 };
44308 TablixGridPresenter.prototype.getScreenToCssRatioX = function () {
44309 return 1;
44310 };
44311 TablixGridPresenter.prototype.getScreenToCssRatioY = function () {
44312 return 1;
44313 };
44314 TablixGridPresenter.prototype.createRowPresenter = function () {
44315 debug.assertFail("PureVirtualMethod: TablixGridPresenter.createRowPresenter");
44316 return null;
44317 };
44318 TablixGridPresenter.prototype.createColumnPresenter = function (index) {
44319 debug.assertFail("PureVirtualMethod: TablixGridPresenter.createColumnPresenter");
44320 return null;
44321 };
44322 TablixGridPresenter.prototype.onAppendRow = function (row) {
44323 var presenter = row.presenter;
44324 if (presenter.tableRow === null) {
44325 // For performance reason we use InsertRow() to create new table cells instead of AppendChild()
44326 // We use -1 to insert at the end (that's the cross-browser way of doing it)
44327 var tableRow = this._table.insertRow(-1);
44328 presenter.registerRow(tableRow);
44329 }
44330 else {
44331 this._table.tBodies[0].appendChild(row.presenter.tableRow);
44332 }
44333 };
44334 TablixGridPresenter.prototype.onInsertRowBefore = function (row, refRow) {
44335 debug.assertValue(refRow.presenter.tableRow, 'refTableRow');
44336 var presenter = row.presenter;
44337 if (presenter.tableRow === null) {
44338 // For performance reason we use InsertRow() to create new table cells instead of AppendChild()
44339 var tableRow = this._table.insertRow(Math.max(0, refRow.presenter.tableRow.rowIndex - 1));
44340 presenter.registerRow(tableRow);
44341 }
44342 else {
44343 this._table.tBodies[0].insertBefore(row.presenter.tableRow, refRow.presenter.tableRow);
44344 }
44345 };
44346 TablixGridPresenter.prototype.onRemoveRow = function (row) {
44347 this._table.tBodies[0].removeChild(row.presenter.tableRow);
44348 };
44349 TablixGridPresenter.prototype.onAddFooterRow = function (row) {
44350 var presenter = row.presenter;
44351 if (presenter.tableRow === null) {
44352 // For performance reason we use InsertRow() to create new table cells instead of AppendChild()
44353 // We use -1 to insert at the end (that's the cross-browser way of doing it)
44354 var tableRow = this._footerTable.insertRow(-1);
44355 presenter.registerRow(tableRow);
44356 }
44357 else {
44358 this._footerTable.tBodies[0].appendChild(row.presenter.tableRow);
44359 }
44360 };
44361 TablixGridPresenter.prototype.onClear = function () {
44362 controls.HTMLElementUtils.clearChildren(this._table);
44363 controls.HTMLElementUtils.clearChildren(this._footerTable);
44364 };
44365 TablixGridPresenter.prototype.onFillColumnsProportionallyChanged = function (value) {
44366 if (value) {
44367 this._table.style.width = "100%";
44368 this._footerTable.style.width = "100%";
44369 }
44370 else {
44371 this._table.style.width = "auto";
44372 this._footerTable.style.width = "auto";
44373 }
44374 };
44375 TablixGridPresenter.prototype.invokeColumnResizeEndCallback = function (columnIndex, width) {
44376 if (this._columnWidthManager)
44377 this._columnWidthManager.onColumnWidthChanged(columnIndex, width);
44378 };
44379 TablixGridPresenter.prototype.getPersistedCellWidth = function (columnIndex) {
44380 if (this._columnWidthManager)
44381 return this._columnWidthManager.getPersistedColumnWidth(columnIndex);
44382 };
44383 return TablixGridPresenter;
44384 }());
44385 internal.TablixGridPresenter = TablixGridPresenter;
44386 var DashboardTablixGridPresenter = (function (_super) {
44387 __extends(DashboardTablixGridPresenter, _super);
44388 function DashboardTablixGridPresenter(sizeComputationManager) {
44389 _super.call(this);
44390 this._sizeComputationManager = sizeComputationManager;
44391 }
44392 DashboardTablixGridPresenter.prototype.createRowPresenter = function () {
44393 return new DashboardRowPresenter(this, this._owner.fillColumnsProportionally);
44394 };
44395 DashboardTablixGridPresenter.prototype.createColumnPresenter = function (index) {
44396 return new DashboardColumnPresenter(this);
44397 };
44398 Object.defineProperty(DashboardTablixGridPresenter.prototype, "sizeComputationManager", {
44399 get: function () {
44400 return this._sizeComputationManager;
44401 },
44402 enumerable: true,
44403 configurable: true
44404 });
44405 DashboardTablixGridPresenter.prototype.getWidth = function () {
44406 return this._sizeComputationManager.gridWidth;
44407 };
44408 DashboardTablixGridPresenter.prototype.getHeight = function () {
44409 return this._sizeComputationManager.gridHeight;
44410 };
44411 return DashboardTablixGridPresenter;
44412 }(TablixGridPresenter));
44413 internal.DashboardTablixGridPresenter = DashboardTablixGridPresenter;
44414 var CanvasTablixGridPresenter = (function (_super) {
44415 __extends(CanvasTablixGridPresenter, _super);
44416 function CanvasTablixGridPresenter(columnWidthManager) {
44417 _super.call(this, columnWidthManager);
44418 }
44419 CanvasTablixGridPresenter.prototype.createRowPresenter = function () {
44420 return new CanvasRowPresenter(this._owner.fillColumnsProportionally);
44421 };
44422 CanvasTablixGridPresenter.prototype.createColumnPresenter = function (index) {
44423 return new CanvasColumnPresenter(this, index);
44424 };
44425 CanvasTablixGridPresenter.prototype.getWidth = function () {
44426 return controls.HTMLElementUtils.getElementWidth(this._table);
44427 };
44428 CanvasTablixGridPresenter.prototype.getHeight = function () {
44429 return controls.HTMLElementUtils.getElementHeight(this._table);
44430 };
44431 return CanvasTablixGridPresenter;
44432 }(TablixGridPresenter));
44433 internal.CanvasTablixGridPresenter = CanvasTablixGridPresenter;
44434 })(internal = controls.internal || (controls.internal = {}));
44435 })(controls = visuals.controls || (visuals.controls = {}));
44436 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
44437})(powerbi || (powerbi = {}));
44438/*
44439 * Power BI Visualizations
44440 *
44441 * Copyright (c) Microsoft Corporation
44442 * All rights reserved.
44443 * MIT License
44444 *
44445 * Permission is hereby granted, free of charge, to any person obtaining a copy
44446 * of this software and associated documentation files (the ""Software""), to deal
44447 * in the Software without restriction, including without limitation the rights
44448 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44449 * copies of the Software, and to permit persons to whom the Software is
44450 * furnished to do so, subject to the following conditions:
44451 *
44452 * The above copyright notice and this permission notice shall be included in
44453 * all copies or substantial portions of the Software.
44454 *
44455 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44456 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44457 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44458 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44459 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44460 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44461 * THE SOFTWARE.
44462 */
44463var powerbi;
44464(function (powerbi) {
44465 var visuals;
44466 (function (visuals) {
44467 var controls;
44468 (function (controls) {
44469 var internal;
44470 (function (internal) {
44471 /**
44472 * Base class for Tablix realization manager.
44473 */
44474 var TablixDimensionRealizationManager = (function () {
44475 function TablixDimensionRealizationManager(binder) {
44476 this._binder = binder;
44477 this._adjustmentFactor = 1;
44478 }
44479 TablixDimensionRealizationManager.prototype._getOwner = function () {
44480 debug.assertFail("PureVirtualMethod: DimensionLayoutManager.getOwner");
44481 return null;
44482 };
44483 Object.defineProperty(TablixDimensionRealizationManager.prototype, "binder", {
44484 get: function () {
44485 return this._binder;
44486 },
44487 enumerable: true,
44488 configurable: true
44489 });
44490 Object.defineProperty(TablixDimensionRealizationManager.prototype, "adjustmentFactor", {
44491 get: function () {
44492 return this._adjustmentFactor;
44493 },
44494 enumerable: true,
44495 configurable: true
44496 });
44497 Object.defineProperty(TablixDimensionRealizationManager.prototype, "itemsToRealizeCount", {
44498 get: function () {
44499 return this._itemsToRealizeCount;
44500 },
44501 set: function (count) {
44502 this._itemsToRealizeCount = count;
44503 },
44504 enumerable: true,
44505 configurable: true
44506 });
44507 Object.defineProperty(TablixDimensionRealizationManager.prototype, "itemsEstimatedContextualWidth", {
44508 get: function () {
44509 return this._itemsEstimatedContextualWidth;
44510 },
44511 set: function (contextualWidth) {
44512 this._itemsEstimatedContextualWidth = contextualWidth;
44513 },
44514 enumerable: true,
44515 configurable: true
44516 });
44517 TablixDimensionRealizationManager.prototype.onStartRenderingIteration = function () {
44518 var owner = this._getOwner();
44519 if (owner.measureEnabled && !owner.done) {
44520 this._getEstimatedItemsToRealizeCount();
44521 }
44522 this._realizedLeavesCount = 0;
44523 };
44524 TablixDimensionRealizationManager.prototype.onEndRenderingIteration = function (gridContextualWidth, filled) {
44525 if (!filled && !this._getOwner().allItemsRealized)
44526 this._adjustmentFactor *= this._getSizeAdjustment(gridContextualWidth);
44527 };
44528 TablixDimensionRealizationManager.prototype.onEndRenderingSession = function () {
44529 this._adjustmentFactor = 1;
44530 };
44531 TablixDimensionRealizationManager.prototype.onCornerCellRealized = function (item, cell) {
44532 };
44533 TablixDimensionRealizationManager.prototype.onHeaderRealized = function (item, cell, leaf) {
44534 if (leaf) {
44535 this._realizedLeavesCount++;
44536 }
44537 };
44538 Object.defineProperty(TablixDimensionRealizationManager.prototype, "needsToRealize", {
44539 get: function () {
44540 return this._realizedLeavesCount < this._itemsToRealizeCount;
44541 },
44542 enumerable: true,
44543 configurable: true
44544 });
44545 TablixDimensionRealizationManager.prototype._getEstimatedItemsToRealizeCount = function () {
44546 debug.assertFail("PureVirtualMethod: TablixDimensionRealizationManager._calculateItemsToRealize");
44547 };
44548 TablixDimensionRealizationManager.prototype._getSizeAdjustment = function (gridContextualWidth) {
44549 debug.assertFail("PureVirtualMethod: TablixDimensionRealizationManager._getSizeAdjustment");
44550 return 1;
44551 };
44552 return TablixDimensionRealizationManager;
44553 }());
44554 internal.TablixDimensionRealizationManager = TablixDimensionRealizationManager;
44555 /**
44556 * DOM implementation for Row Tablix realization manager.
44557 */
44558 var RowRealizationManager = (function (_super) {
44559 __extends(RowRealizationManager, _super);
44560 function RowRealizationManager() {
44561 _super.apply(this, arguments);
44562 }
44563 Object.defineProperty(RowRealizationManager.prototype, "owner", {
44564 set: function (owner) {
44565 this._owner = owner;
44566 },
44567 enumerable: true,
44568 configurable: true
44569 });
44570 RowRealizationManager.prototype._getOwner = function () {
44571 return this._owner;
44572 };
44573 RowRealizationManager.prototype._getEstimatedItemsToRealizeCount = function () {
44574 this.estimateRowsToRealizeCount();
44575 };
44576 RowRealizationManager.prototype.estimateRowsToRealizeCount = function () {
44577 debug.assertValue(this._owner, '_owner');
44578 if (!this._owner.dimension.model) {
44579 this.itemsToRealizeCount = 0;
44580 return;
44581 }
44582 if (this._owner.alignToEnd)
44583 this.itemsToRealizeCount = this._owner.dimension.getItemsCount() - this._owner.dimension.getIntegerScrollOffset() + 1;
44584 else
44585 this.itemsToRealizeCount = Math.ceil((this._owner.contextualWidthToFill / (this._owner.owner.getEstimatedRowHeight() * this.adjustmentFactor)) + this._owner.dimension.getFractionScrollOffset()) - this._owner.otherLayoutManager.dimension.getDepth() + 1;
44586 };
44587 RowRealizationManager.prototype.getEstimatedRowHierarchyWidth = function () {
44588 if (!this._owner.dimension.model || this._owner.dimension.getItemsCount() === 0)
44589 return 0;
44590 var levels = new RowWidths();
44591 this.updateRowHiearchyEstimatedWidth(this._owner.dimension.model, this._owner.dimension._hierarchyNavigator.getIndex(this._owner.dimension.getFirstVisibleItem(0)), levels);
44592 var levelsArray = levels.items;
44593 var levelCount = levelsArray.length;
44594 var width = 0;
44595 for (var i = 0; i < levelCount; i++) {
44596 var level = levelsArray[i];
44597 if (level.maxNonLeafWidth !== 0)
44598 width += level.maxNonLeafWidth;
44599 else
44600 width += level.maxLeafWidth;
44601 }
44602 return width;
44603 };
44604 RowRealizationManager.prototype.updateRowHiearchyEstimatedWidth = function (items, firstVisibleIndex, levels) {
44605 var hierarchyNavigator = this._owner.owner.owner.hierarchyNavigator;
44606 var binder = this.binder;
44607 var length = hierarchyNavigator.getCount(items);
44608 for (var i = firstVisibleIndex; i < length; i++) {
44609 if (levels.leafCount === this.itemsToRealizeCount)
44610 return;
44611 var item = hierarchyNavigator.getAt(items, i);
44612 var label = binder.getHeaderLabel(item);
44613 var itemWidth = this._owner.getEstimatedHeaderWidth(label, firstVisibleIndex);
44614 var isLeaf = hierarchyNavigator.isLeaf(item);
44615 var l = hierarchyNavigator.getLevel(item);
44616 var level = levels.items[l];
44617 if (!level) {
44618 level = new RowWidth();
44619 levels.items[l] = level;
44620 }
44621 if (isLeaf) {
44622 level.maxLeafWidth = Math.max(level.maxLeafWidth, itemWidth);
44623 levels.leafCount = levels.leafCount + 1;
44624 }
44625 else {
44626 level.maxNonLeafWidth = Math.max(level.maxNonLeafWidth, itemWidth);
44627 this.updateRowHiearchyEstimatedWidth(hierarchyNavigator.getChildren(item), this._owner.dimension.getFirstVisibleChildIndex(item), levels);
44628 }
44629 }
44630 };
44631 RowRealizationManager.prototype._getSizeAdjustment = function (gridContextualWidth) {
44632 return gridContextualWidth / ((this._owner.getRealizedItemsCount() - this._owner.dimension.getFractionScrollOffset()) * this._owner.owner.getEstimatedRowHeight());
44633 };
44634 return RowRealizationManager;
44635 }(TablixDimensionRealizationManager));
44636 internal.RowRealizationManager = RowRealizationManager;
44637 /**
44638 * DOM implementation for Column Tablix realization manager.
44639 */
44640 var ColumnRealizationManager = (function (_super) {
44641 __extends(ColumnRealizationManager, _super);
44642 function ColumnRealizationManager() {
44643 _super.apply(this, arguments);
44644 }
44645 Object.defineProperty(ColumnRealizationManager.prototype, "owner", {
44646 set: function (owner) {
44647 this._owner = owner;
44648 },
44649 enumerable: true,
44650 configurable: true
44651 });
44652 ColumnRealizationManager.prototype._getOwner = function () {
44653 return this._owner;
44654 };
44655 ColumnRealizationManager.prototype._getEstimatedItemsToRealizeCount = function () {
44656 this.estimateColumnsToRealizeCount(this.getEstimatedRowHierarchyWidth());
44657 };
44658 Object.defineProperty(ColumnRealizationManager.prototype, "rowRealizationManager", {
44659 get: function () {
44660 return this._owner.otherLayoutManager.realizationManager;
44661 },
44662 enumerable: true,
44663 configurable: true
44664 });
44665 ColumnRealizationManager.prototype.getEstimatedRowHierarchyWidth = function () {
44666 if (this._owner.otherLayoutManager.done)
44667 return this._owner.getOtherHierarchyContextualHeight();
44668 return this.rowRealizationManager.getEstimatedRowHierarchyWidth() * this.adjustmentFactor;
44669 };
44670 ColumnRealizationManager.prototype.estimateColumnsToRealizeCount = function (rowHierarchyWidth) {
44671 var widthToFill = this._owner.contextualWidthToFill - rowHierarchyWidth;
44672 if (!this._owner.dimension.model || powerbi.Double.lessOrEqualWithPrecision(widthToFill, 0, internal.DimensionLayoutManager._pixelPrecision)) {
44673 this.itemsToRealizeCount = 0;
44674 return;
44675 }
44676 var binder = this.binder;
44677 var hierarchyNavigator = this._owner.owner.owner.hierarchyNavigator;
44678 var startColumnIndex = this._owner.dimension.getIntegerScrollOffset();
44679 var endColumnIndex = this._owner.dimension.getItemsCount();
44680 var columnCount = endColumnIndex - startColumnIndex;
44681 var startRowIndex = this._owner.otherLayoutManager.dimension.getIntegerScrollOffset();
44682 var endRowIndex = this._owner.otherLayoutManager.dimension.getItemsCount();
44683 this.itemsEstimatedContextualWidth = 0;
44684 if (this._owner.alignToEnd) {
44685 this.itemsToRealizeCount = columnCount;
44686 return;
44687 }
44688 for (var i = startColumnIndex; i < endColumnIndex; i++) {
44689 if (powerbi.Double.greaterOrEqualWithPrecision(this.itemsEstimatedContextualWidth, widthToFill, internal.DimensionLayoutManager._pixelPrecision)) {
44690 this.itemsToRealizeCount = i - startColumnIndex;
44691 return;
44692 }
44693 var maxWidth = 0;
44694 var visibleSizeRatio = void 0;
44695 if (i === startColumnIndex) {
44696 visibleSizeRatio = this._owner.getVisibleSizeRatio();
44697 }
44698 else {
44699 visibleSizeRatio = 1;
44700 }
44701 var columnMember = hierarchyNavigator.getLeafAt(this._owner.dimension.model, i);
44702 var label = binder.getHeaderLabel(columnMember);
44703 maxWidth = Math.max(maxWidth, this._owner.getEstimatedHeaderWidth(label, i));
44704 for (var j = startRowIndex; j < endRowIndex; j++) {
44705 var intersection = hierarchyNavigator.getIntersection(hierarchyNavigator.getLeafAt(this._owner.otherLayoutManager.dimension.model, j), columnMember);
44706 label = binder.getCellContent(intersection);
44707 maxWidth = Math.max(maxWidth, this._owner.getEstimatedBodyCellWidth(label));
44708 }
44709 this.itemsEstimatedContextualWidth += maxWidth * visibleSizeRatio * this.adjustmentFactor;
44710 }
44711 this.itemsToRealizeCount = columnCount;
44712 };
44713 ColumnRealizationManager.prototype._getSizeAdjustment = function (gridContextualWidth) {
44714 return gridContextualWidth / (this.getEstimatedRowHierarchyWidth() + this.itemsEstimatedContextualWidth);
44715 };
44716 return ColumnRealizationManager;
44717 }(TablixDimensionRealizationManager));
44718 internal.ColumnRealizationManager = ColumnRealizationManager;
44719 var RowWidths = (function () {
44720 function RowWidths() {
44721 this.items = [];
44722 this.leafCount = 0;
44723 }
44724 return RowWidths;
44725 }());
44726 internal.RowWidths = RowWidths;
44727 var RowWidth = (function () {
44728 function RowWidth() {
44729 this.maxLeafWidth = 0;
44730 this.maxNonLeafWidth = 0;
44731 }
44732 return RowWidth;
44733 }());
44734 internal.RowWidth = RowWidth;
44735 })(internal = controls.internal || (controls.internal = {}));
44736 })(controls = visuals.controls || (visuals.controls = {}));
44737 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
44738})(powerbi || (powerbi = {}));
44739/*
44740 * Power BI Visualizations
44741 *
44742 * Copyright (c) Microsoft Corporation
44743 * All rights reserved.
44744 * MIT License
44745 *
44746 * Permission is hereby granted, free of charge, to any person obtaining a copy
44747 * of this software and associated documentation files (the ""Software""), to deal
44748 * in the Software without restriction, including without limitation the rights
44749 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44750 * copies of the Software, and to permit persons to whom the Software is
44751 * furnished to do so, subject to the following conditions:
44752 *
44753 * The above copyright notice and this permission notice shall be included in
44754 * all copies or substantial portions of the Software.
44755 *
44756 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44757 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44758 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44759 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44760 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44761 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44762 * THE SOFTWARE.
44763 */
44764var powerbi;
44765(function (powerbi) {
44766 var visuals;
44767 (function (visuals) {
44768 var controls;
44769 (function (controls) {
44770 var internal;
44771 (function (internal) {
44772 var TablixCell = (function () {
44773 function TablixCell(presenter, extension, row) {
44774 this._scrollable = false;
44775 this._presenter = presenter;
44776 this.extension = extension;
44777 this._presenter.initialize(this);
44778 this._row = row;
44779 this.item = null;
44780 this.type = null;
44781 this._horizontalOffset = 0;
44782 this._verticalOffset = 0;
44783 this._colSpan = 1;
44784 this._rowSpan = 1;
44785 this._containerWidth = -1;
44786 this._containerHeight = -1;
44787 this.contentHeight = this.contentWidth = 0;
44788 this.position = new internal.TablixUtils.CellPosition();
44789 }
44790 TablixCell.prototype.unfixRowHeight = function () {
44791 this._row.unfixSize();
44792 };
44793 Object.defineProperty(TablixCell.prototype, "colSpan", {
44794 get: function () {
44795 return this._colSpan;
44796 },
44797 set: function (value) {
44798 if (this._colSpan !== value) {
44799 this._presenter.onColumnSpanChanged(value);
44800 this._colSpan = value;
44801 }
44802 },
44803 enumerable: true,
44804 configurable: true
44805 });
44806 Object.defineProperty(TablixCell.prototype, "rowSpan", {
44807 get: function () {
44808 return this._rowSpan;
44809 },
44810 set: function (value) {
44811 if (this._rowSpan !== value) {
44812 this._presenter.onRowSpanChanged(value);
44813 this._rowSpan = value;
44814 this._row.unfixSize();
44815 }
44816 },
44817 enumerable: true,
44818 configurable: true
44819 });
44820 TablixCell.prototype.getCellSpanningHeight = function () {
44821 return this._row.getCellSpanningHeight(this);
44822 };
44823 Object.defineProperty(TablixCell.prototype, "textAlign", {
44824 get: function () {
44825 return this._textAlign;
44826 },
44827 set: function (value) {
44828 if (value !== this._textAlign) {
44829 this._presenter.onTextAlignChanged(value);
44830 this._textAlign = value;
44831 }
44832 },
44833 enumerable: true,
44834 configurable: true
44835 });
44836 Object.defineProperty(TablixCell.prototype, "horizontalOffset", {
44837 get: function () {
44838 return this._horizontalOffset;
44839 },
44840 enumerable: true,
44841 configurable: true
44842 });
44843 Object.defineProperty(TablixCell.prototype, "verticalOffset", {
44844 get: function () {
44845 return this._verticalOffset;
44846 },
44847 enumerable: true,
44848 configurable: true
44849 });
44850 TablixCell.prototype.isScrollable = function () {
44851 return this._scrollable;
44852 };
44853 TablixCell.prototype.clear = function () {
44854 if (this.isScrollable()) {
44855 this.initializeScrolling();
44856 }
44857 this._presenter.onClear();
44858 this.setContainerWidth(-1);
44859 this.setContainerHeight(-1);
44860 this.contentHeight = this.contentWidth = 0;
44861 };
44862 TablixCell.prototype.initializeScrolling = function () {
44863 this._presenter.onInitializeScrolling();
44864 this._horizontalOffset = 0;
44865 this._verticalOffset = 0;
44866 if (this.colSpan === 1)
44867 this.setContainerWidth(-1);
44868 if (this.rowSpan === 1)
44869 this.setContainerHeight(-1);
44870 };
44871 TablixCell.prototype.prepare = function (scrollable) {
44872 if (this.isScrollable())
44873 this.initializeScrolling();
44874 this._scrollable = scrollable;
44875 };
44876 TablixCell.prototype.scrollVertically = function (height, offset) {
44877 // Ceiling the offset because setting a fraction Width on the TD will ceil it
44878 // We need to let the TD and the OuterDiv to align in order for Borders to touch
44879 var offsetInPixels = Math.ceil(-height * offset);
44880 this._verticalOffset = offsetInPixels;
44881 if (this.isScrollable()) {
44882 this._presenter.onVerticalScroll(height, offsetInPixels);
44883 this.setContainerHeight(height + offsetInPixels);
44884 }
44885 else {
44886 this.setContainerHeight(this._row.getCellSpanningHeight(this) + offsetInPixels);
44887 }
44888 };
44889 TablixCell.prototype.scrollHorizontally = function (width, offset) {
44890 if (!this.isScrollable()) {
44891 return;
44892 }
44893 // Ceiling the offset because setting a fraction Width on the TD will ceil it
44894 // We need to let the TD and the OuterDiv to align in order for Borders to touch
44895 var offsetInPixels = Math.ceil(-width * offset);
44896 this._horizontalOffset = offsetInPixels;
44897 this._presenter.onHorizontalScroll(width, offsetInPixels);
44898 this.setContainerWidth(width + offsetInPixels);
44899 };
44900 TablixCell.prototype.setContainerWidth = function (value) {
44901 if (value === this._containerWidth)
44902 return;
44903 this._containerWidth = value;
44904 this._presenter.onContainerWidthChanged(value);
44905 };
44906 Object.defineProperty(TablixCell.prototype, "containerWidth", {
44907 get: function () {
44908 return this._containerWidth;
44909 },
44910 enumerable: true,
44911 configurable: true
44912 });
44913 TablixCell.prototype.setContainerHeight = function (value) {
44914 if (value < 0)
44915 value = -1;
44916 if (value === this._containerHeight)
44917 return;
44918 this._containerHeight = value;
44919 this._presenter.onContinerHeightChanged(value);
44920 };
44921 Object.defineProperty(TablixCell.prototype, "containerHeight", {
44922 get: function () {
44923 return this._containerHeight;
44924 },
44925 enumerable: true,
44926 configurable: true
44927 });
44928 TablixCell.prototype.applyStyle = function (style) {
44929 if (style) {
44930 style.applyStyle(this);
44931 this.contentHeight += style.getExtraBottom() + style.getExtraTop();
44932 this.contentWidth += style.getExtraLeft() + style.getExtraRight();
44933 }
44934 };
44935 TablixCell.prototype.enableHorizontalResize = function (enable, handler) {
44936 this._presenter.enableHorizontalResize(enable, handler);
44937 };
44938 return TablixCell;
44939 }());
44940 internal.TablixCell = TablixCell;
44941 var TablixColumn = (function () {
44942 function TablixColumn(presenter, columnIndex) {
44943 this._presenter = presenter;
44944 this._presenter.initialize(this);
44945 this._containerWidth = -1;
44946 this._width = -1;
44947 this._sizeFixed = false;
44948 this._aligningWidth = -1;
44949 this._fixedToAligningWidth = false;
44950 this._items = [];
44951 this._itemType = null;
44952 this._footerCell = null;
44953 this._columnIndex = columnIndex;
44954 }
44955 TablixColumn.prototype.initialize = function (owner) {
44956 this._owner = owner;
44957 this._realizedRowHeaders = [];
44958 this._realizedColumnHeaders = [];
44959 this._realizedCornerCells = [];
44960 this._realizedBodyCells = [];
44961 };
44962 Object.defineProperty(TablixColumn.prototype, "owner", {
44963 get: function () {
44964 return this._owner;
44965 },
44966 enumerable: true,
44967 configurable: true
44968 });
44969 TablixColumn.prototype.getType = function () {
44970 if (this._realizedCornerCells.length > 0)
44971 return 0 /* CornerCell */;
44972 return 2 /* ColumnHeader */;
44973 };
44974 TablixColumn.prototype.getColumnHeadersOrCorners = function () {
44975 if (this._realizedCornerCells.length > 0)
44976 return this._realizedCornerCells;
44977 return this._realizedColumnHeaders;
44978 };
44979 TablixColumn.prototype.columnHeadersOrCornersEqual = function (newType, headers, hierarchyNavigator) {
44980 if (this._items.length !== headers.length)
44981 return false;
44982 var count = this._items.length;
44983 for (var i = 0; i < count; i++) {
44984 if (!this.columnHeaderOrCornerEquals(this._itemType, this._items[i], newType, headers[i].item, hierarchyNavigator))
44985 return false;
44986 }
44987 return true;
44988 };
44989 Object.defineProperty(TablixColumn.prototype, "itemType", {
44990 get: function () {
44991 return this._itemType;
44992 },
44993 enumerable: true,
44994 configurable: true
44995 });
44996 TablixColumn.prototype.getLeafItem = function () {
44997 if (this._items.length === 0)
44998 return null;
44999 return this._items[this._items.length - 1];
45000 };
45001 TablixColumn.prototype.columnHeaderOrCornerEquals = function (type1, item1, type2, item2, hierarchyNavigator) {
45002 if (type1 !== type2)
45003 return false;
45004 if (type1 === 0 /* CornerCell */) {
45005 if (!hierarchyNavigator.cornerCellItemEquals(item1, item2))
45006 return false;
45007 }
45008 else {
45009 if (!hierarchyNavigator.headerItemEquals(item1, item2))
45010 return false;
45011 }
45012 return true;
45013 };
45014 TablixColumn.prototype.OnLeafRealized = function (hierarchyNavigator) {
45015 // if the headers/corner have changed we should clear the column size to accomodate for the new content
45016 var type = this.getType();
45017 var columnHeadersOrCorners = this.getColumnHeadersOrCorners();
45018 if (this.columnHeadersOrCornersEqual(type, columnHeadersOrCorners, hierarchyNavigator)) {
45019 this.clearSpanningCellsWidth(this._realizedColumnHeaders);
45020 }
45021 else {
45022 var count = columnHeadersOrCorners.length;
45023 this._items = [];
45024 for (var i = 0; i < count; i++) {
45025 this._items.push(columnHeadersOrCorners[i].item);
45026 }
45027 this._itemType = type;
45028 this.clearSize();
45029 }
45030 };
45031 TablixColumn.prototype.clearSpanningCellsWidth = function (cells) {
45032 for (var i = 0; i < cells.length; i++) {
45033 var cell = cells[i];
45034 if (cell.colSpan > 1) {
45035 cell.setContainerWidth(-1);
45036 }
45037 }
45038 };
45039 TablixColumn.prototype.addCornerCell = function (cell) {
45040 cell._column = this;
45041 this._realizedCornerCells.push(cell);
45042 cell.setContainerWidth(this._containerWidth);
45043 };
45044 TablixColumn.prototype.addRowHeader = function (cell) {
45045 cell._column = this;
45046 this._realizedRowHeaders.push(cell);
45047 cell.setContainerWidth(this._containerWidth);
45048 };
45049 TablixColumn.prototype.addColumnHeader = function (cell, isLeaf) {
45050 cell._column = this;
45051 this._realizedColumnHeaders.push(cell);
45052 if (isLeaf) {
45053 cell.setContainerWidth(this._containerWidth);
45054 }
45055 };
45056 TablixColumn.prototype.addBodyCell = function (cell) {
45057 cell._column = this;
45058 this._realizedBodyCells.push(cell);
45059 cell.setContainerWidth(this._containerWidth);
45060 };
45061 Object.defineProperty(TablixColumn.prototype, "footer", {
45062 get: function () {
45063 return this._footerCell;
45064 },
45065 set: function (footerCell) {
45066 this._footerCell = footerCell;
45067 footerCell._column = this;
45068 footerCell.setContainerWidth(this._containerWidth);
45069 },
45070 enumerable: true,
45071 configurable: true
45072 });
45073 TablixColumn.prototype.onResize = function (width) {
45074 if (width === this.getContentContextualWidth())
45075 return;
45076 this._containerWidth = width;
45077 this.setContainerWidth(this._containerWidth);
45078 this._sizeFixed = true;
45079 this._fixedToAligningWidth = false;
45080 this._aligningWidth = -1;
45081 };
45082 TablixColumn.prototype.onResizeEnd = function (width) {
45083 // Invoke resize callback
45084 var gridPresenter = this.owner._presenter;
45085 if (gridPresenter)
45086 gridPresenter.invokeColumnResizeEndCallback(this._columnIndex, width);
45087 };
45088 TablixColumn.prototype.fixSize = function () {
45089 var shouldAlign = this._aligningWidth !== -1;
45090 var switched = shouldAlign !== this._fixedToAligningWidth;
45091 if ((this._sizeFixed && !switched && !shouldAlign))
45092 return;
45093 if (this._aligningWidth === -1) {
45094 this.setContainerWidth(this._containerWidth);
45095 }
45096 else {
45097 this.setContainerWidth(this._aligningWidth);
45098 }
45099 this._sizeFixed = true;
45100 this._fixedToAligningWidth = this._aligningWidth !== -1;
45101 };
45102 TablixColumn.prototype.clearSize = function () {
45103 this._containerWidth = -1;
45104 this.setContainerWidth(this._containerWidth);
45105 this._sizeFixed = false;
45106 };
45107 TablixColumn.prototype.getContentContextualWidth = function () {
45108 return this._containerWidth;
45109 };
45110 TablixColumn.prototype.getCellIContentContextualWidth = function (cell) {
45111 return this._presenter.getCellContentWidth(cell);
45112 };
45113 TablixColumn.prototype.getCellSpanningWidthWithScrolling = function (cell, tablixGrid) {
45114 var width = this.getContextualWidth() + this.getScrollingOffset();
45115 if (cell.colSpan > 1) {
45116 var index = this.getIndex(tablixGrid);
45117 var columns = tablixGrid.realizedColumns;
45118 for (var i = 1; i < cell.colSpan; i++)
45119 width += columns[i + index].getContextualWidth();
45120 }
45121 return width;
45122 };
45123 TablixColumn.prototype.getScrollingOffset = function () {
45124 var offset = 0;
45125 if (this._realizedColumnHeaders.length > 0)
45126 offset = this._realizedColumnHeaders[this._realizedColumnHeaders.length - 1].horizontalOffset;
45127 return offset;
45128 };
45129 TablixColumn.prototype.getContextualWidth = function () {
45130 if (this._width === -1 || this._containerWidth === -1)
45131 this._width = this._presenter.getWidth();
45132 return this._width;
45133 };
45134 TablixColumn.prototype.calculateSize = function () {
45135 if (this._sizeFixed)
45136 return this._containerWidth;
45137 var contentWidth = 0;
45138 for (var _i = 0, _a = this._realizedColumnHeaders; _i < _a.length; _i++) {
45139 var cell = _a[_i];
45140 if (cell.colSpan === 1)
45141 contentWidth = Math.max(contentWidth, this._presenter.getCellContentWidth(cell));
45142 }
45143 for (var _b = 0, _c = this._realizedRowHeaders; _b < _c.length; _b++) {
45144 var cell = _c[_b];
45145 if (cell.colSpan === 1)
45146 contentWidth = Math.max(contentWidth, this._presenter.getCellContentWidth(cell));
45147 }
45148 for (var _d = 0, _e = this._realizedCornerCells; _d < _e.length; _d++) {
45149 var cell = _e[_d];
45150 contentWidth = Math.max(contentWidth, this._presenter.getCellContentWidth(cell));
45151 }
45152 for (var _f = 0, _g = this._realizedBodyCells; _f < _g.length; _f++) {
45153 var cell = _g[_f];
45154 contentWidth = Math.max(contentWidth, this._presenter.getCellContentWidth(cell));
45155 }
45156 if (this._footerCell !== null) {
45157 if (this._footerCell.colSpan === 1)
45158 contentWidth = Math.max(contentWidth, this._presenter.getCellContentWidth(this._footerCell));
45159 }
45160 return this._containerWidth = contentWidth;
45161 };
45162 TablixColumn.prototype.setAligningContextualWidth = function (size) {
45163 this._aligningWidth = size;
45164 };
45165 TablixColumn.prototype.getAligningContextualWidth = function () {
45166 return this._aligningWidth;
45167 };
45168 TablixColumn.prototype.setContainerWidth = function (value) {
45169 for (var _i = 0, _a = this._realizedColumnHeaders; _i < _a.length; _i++) {
45170 var cell = _a[_i];
45171 if (cell.colSpan === 1)
45172 cell.setContainerWidth(value);
45173 }
45174 for (var _b = 0, _c = this._realizedRowHeaders; _b < _c.length; _b++) {
45175 var cell = _c[_b];
45176 if (cell.colSpan === 1)
45177 cell.setContainerWidth(value);
45178 }
45179 for (var _d = 0, _e = this._realizedCornerCells; _d < _e.length; _d++) {
45180 var cell = _e[_d];
45181 cell.setContainerWidth(value);
45182 }
45183 for (var _f = 0, _g = this._realizedBodyCells; _f < _g.length; _f++) {
45184 var cell = _g[_f];
45185 cell.setContainerWidth(value);
45186 }
45187 if (this._footerCell !== null) {
45188 if (this._footerCell.colSpan === 1)
45189 this._footerCell.setContainerWidth(value);
45190 }
45191 this._width = value; // set cell width to new value
45192 };
45193 TablixColumn.prototype.getTablixCell = function () {
45194 var realizedCells = this._realizedColumnHeaders.length > 0 ? this._realizedColumnHeaders : this._realizedCornerCells;
45195 //Debug.assert(realizedCells.length !== 0, "At least on header should have been realized");
45196 return realizedCells[realizedCells.length - 1];
45197 };
45198 TablixColumn.prototype.getIndex = function (grid) {
45199 return grid.realizedColumns.indexOf(this);
45200 };
45201 TablixColumn.prototype.getHeaders = function () {
45202 return this._realizedColumnHeaders;
45203 };
45204 TablixColumn.prototype.getOtherDimensionHeaders = function () {
45205 return this._realizedRowHeaders;
45206 };
45207 TablixColumn.prototype.getCellContextualSpan = function (cell) {
45208 return cell.colSpan;
45209 };
45210 TablixColumn.prototype.getOtherDimensionOwner = function (cell) {
45211 return cell._row;
45212 };
45213 return TablixColumn;
45214 }());
45215 internal.TablixColumn = TablixColumn;
45216 var TablixRow = (function () {
45217 function TablixRow(presenter) {
45218 this._containerHeight = -1;
45219 this._presenter = presenter;
45220 this._presenter.initialize(this);
45221 this._allocatedCells = [];
45222 this._heightFixed = false;
45223 this._containerHeight = -1;
45224 this._height = -1;
45225 }
45226 TablixRow.prototype.initialize = function (owner) {
45227 this._owner = owner;
45228 this._realizedRowHeaders = [];
45229 this._realizedBodyCells = [];
45230 this._realizedCornerCells = [];
45231 this._realizedColumnHeaders = [];
45232 this._realizedCellsCount = 0;
45233 };
45234 Object.defineProperty(TablixRow.prototype, "presenter", {
45235 get: function () {
45236 return this._presenter;
45237 },
45238 enumerable: true,
45239 configurable: true
45240 });
45241 Object.defineProperty(TablixRow.prototype, "owner", {
45242 get: function () {
45243 return this._owner;
45244 },
45245 enumerable: true,
45246 configurable: true
45247 });
45248 TablixRow.prototype.releaseUnusedCells = function (owner) {
45249 this.releaseCells(owner, this._realizedCellsCount);
45250 };
45251 TablixRow.prototype.releaseAllCells = function (owner) {
45252 this.releaseCells(owner, 0);
45253 };
45254 TablixRow.prototype.releaseCells = function (owner, startIndex) {
45255 var cells = this._allocatedCells;
45256 var length = cells.length;
45257 for (var i = startIndex; i < length; i++) {
45258 var cell = cells[i];
45259 owner._unbindCell(cell);
45260 cell.clear();
45261 }
45262 };
45263 TablixRow.prototype.moveScrollableCellsToEnd = function (count) {
45264 var frontIndex = Math.max(this._realizedRowHeaders.length, this._realizedCornerCells.length);
45265 for (var i = frontIndex; i < frontIndex + count; i++) {
45266 var cell = this._allocatedCells[i];
45267 this._presenter.onRemoveCell(cell);
45268 this._presenter.onAppendCell(cell);
45269 this._allocatedCells.push(cell);
45270 }
45271 this._allocatedCells.splice(frontIndex, count);
45272 };
45273 TablixRow.prototype.moveScrollableCellsToStart = function (count) {
45274 var frontIndex = Math.max(this._realizedRowHeaders.length, this._realizedCornerCells.length);
45275 for (var i = frontIndex; i < frontIndex + count; i++) {
45276 var cell = this._allocatedCells.pop();
45277 this._presenter.onRemoveCell(cell);
45278 this._presenter.onInsertCellBefore(cell, this._allocatedCells[frontIndex]);
45279 this._allocatedCells.splice(frontIndex, 0, cell);
45280 }
45281 };
45282 TablixRow.prototype.getOrCreateCornerCell = function (column) {
45283 var cell = this.getOrCreateCell();
45284 cell.prepare(false);
45285 column.addCornerCell(cell);
45286 this._realizedCornerCells.push(cell);
45287 cell.setContainerHeight(this._containerHeight);
45288 return cell;
45289 };
45290 TablixRow.prototype.getOrCreateRowHeader = function (column, scrollable, leaf) {
45291 var cell = this.getOrCreateCell();
45292 cell.prepare(scrollable);
45293 column.addRowHeader(cell);
45294 this._realizedRowHeaders.push(cell);
45295 if (leaf)
45296 cell.setContainerHeight(this._containerHeight);
45297 return cell;
45298 };
45299 TablixRow.prototype.getOrCreateColumnHeader = function (column, scrollable, leaf) {
45300 var cell = this.getOrCreateCell();
45301 cell.prepare(scrollable);
45302 column.addColumnHeader(cell, leaf);
45303 this._realizedColumnHeaders.push(cell);
45304 cell.setContainerHeight(this._containerHeight);
45305 return cell;
45306 };
45307 TablixRow.prototype.getOrCreateBodyCell = function (column, scrollable) {
45308 var cell = this.getOrCreateCell();
45309 cell.prepare(scrollable);
45310 column.addBodyCell(cell);
45311 this._realizedBodyCells.push(cell);
45312 cell.setContainerHeight(this._containerHeight);
45313 return cell;
45314 };
45315 TablixRow.prototype.getOrCreateFooterRowHeader = function (column) {
45316 var cell = this.getOrCreateCell();
45317 cell.prepare(false);
45318 column.footer = cell;
45319 this._realizedRowHeaders.push(cell);
45320 cell.setContainerHeight(this._containerHeight);
45321 return cell;
45322 };
45323 TablixRow.prototype.getOrCreateFooterBodyCell = function (column, scrollable) {
45324 var cell = this.getOrCreateCell();
45325 cell.prepare(scrollable);
45326 column.footer = cell;
45327 this._realizedBodyCells.push(cell);
45328 cell.setContainerHeight(this._containerHeight);
45329 return cell;
45330 };
45331 TablixRow.prototype.getRowHeaderLeafIndex = function () {
45332 var index = -1;
45333 var count = this._allocatedCells.length;
45334 for (var i = 0; i < count; i++) {
45335 if (this._allocatedCells[i].type !== 1 /* RowHeader */)
45336 break;
45337 index++;
45338 }
45339 return index;
45340 };
45341 TablixRow.prototype.getAllocatedCellAt = function (index) {
45342 return this._allocatedCells[index];
45343 };
45344 TablixRow.prototype.moveCellsBy = function (delta) {
45345 if (this._allocatedCells.length === 0)
45346 return;
45347 if (delta > 0) {
45348 var refCell = this._allocatedCells[0];
45349 for (var i = 0; i < delta; i++) {
45350 var cell = this.createCell(this);
45351 this._presenter.onInsertCellBefore(cell, refCell);
45352 this._allocatedCells.unshift(cell);
45353 refCell = cell;
45354 }
45355 }
45356 else {
45357 delta = -delta;
45358 for (var i = 0; i < delta; i++) {
45359 this._presenter.onRemoveCell(this._allocatedCells[i]);
45360 }
45361 this._allocatedCells.splice(0, delta);
45362 }
45363 };
45364 TablixRow.prototype.getRealizedCellCount = function () {
45365 return this._realizedCellsCount;
45366 };
45367 TablixRow.prototype.getRealizedHeadersCount = function () {
45368 return this._realizedRowHeaders.length;
45369 };
45370 TablixRow.prototype.getRealizedHeaderAt = function (index) {
45371 return this._realizedRowHeaders[index];
45372 };
45373 TablixRow.prototype.getTablixCell = function () {
45374 var realizedCells;
45375 if (this._realizedRowHeaders.length > 0) {
45376 realizedCells = this._realizedRowHeaders;
45377 }
45378 else if (this._realizedCornerCells.length > 0) {
45379 realizedCells = this._realizedCornerCells;
45380 }
45381 else {
45382 realizedCells = this._realizedColumnHeaders;
45383 }
45384 //Debug.assert(realizedCells.length !== 0, "At least on header should have been realized");
45385 return realizedCells[realizedCells.length - 1];
45386 };
45387 TablixRow.prototype.getOrCreateEmptySpaceCell = function () {
45388 var cell = this._allocatedCells[this._realizedCellsCount];
45389 if (cell === undefined) {
45390 cell = this.createCell(this);
45391 this._allocatedCells[this._realizedCellsCount] = cell;
45392 this._presenter.onAppendCell(cell);
45393 }
45394 return cell;
45395 };
45396 TablixRow.prototype.createCell = function (row) {
45397 var presenter = this._presenter.createCellPresenter(this._owner.owner.layoutManager.getLayoutKind());
45398 return new TablixCell(presenter, presenter, this);
45399 };
45400 TablixRow.prototype.getOrCreateCell = function () {
45401 var cell = this._allocatedCells[this._realizedCellsCount];
45402 if (cell === undefined) {
45403 cell = this.createCell(this);
45404 this._allocatedCells[this._realizedCellsCount] = cell;
45405 this._presenter.onAppendCell(cell);
45406 }
45407 else {
45408 cell.colSpan = 1;
45409 cell.rowSpan = 1;
45410 }
45411 this._realizedCellsCount = this._realizedCellsCount + 1;
45412 return cell;
45413 };
45414 TablixRow.prototype.onResize = function (height) {
45415 if (height === this.getContentContextualWidth())
45416 return;
45417 this._containerHeight = height;
45418 this.setContentHeight();
45419 this._heightFixed = true;
45420 this.setAligningContextualWidth(-1);
45421 };
45422 TablixRow.prototype.onResizeEnd = function (height) { };
45423 TablixRow.prototype.fixSize = function () {
45424 if (this.sizeFixed())
45425 return;
45426 this.setContentHeight();
45427 this._heightFixed = true;
45428 };
45429 TablixRow.prototype.unfixSize = function () {
45430 this._heightFixed = false;
45431 this._height = -1;
45432 };
45433 TablixRow.prototype.getContentContextualWidth = function () {
45434 return this._containerHeight;
45435 };
45436 TablixRow.prototype.getCellIContentContextualWidth = function (cell) {
45437 return this.presenter.getCellContentHeight(cell);
45438 };
45439 TablixRow.prototype.getCellSpanningHeight = function (cell) {
45440 var height = this.getContextualWidth();
45441 if (cell.rowSpan > 1) {
45442 var index = this.getIndex(this.owner);
45443 var rows = this.owner.realizedRows;
45444 for (var i = 1; i < cell.rowSpan; i++)
45445 height += rows[i + index].getContextualWidth();
45446 }
45447 return height;
45448 };
45449 TablixRow.prototype.getContextualWidth = function () {
45450 if (this._height === -1 || this._containerHeight === -1)
45451 this._height = this._presenter.getHeight();
45452 return this._height;
45453 };
45454 TablixRow.prototype.sizeFixed = function () {
45455 return this._heightFixed;
45456 };
45457 TablixRow.prototype.calculateSize = function () {
45458 if (this._heightFixed)
45459 return this._containerHeight;
45460 var contentHeight = 0;
45461 var count = this._realizedRowHeaders.length;
45462 for (var i = 0; i < count; i++) {
45463 var cell = this._realizedRowHeaders[i];
45464 if (cell.rowSpan === 1)
45465 contentHeight = Math.max(contentHeight, this._presenter.getCellContentHeight(cell));
45466 }
45467 count = this._realizedCornerCells.length;
45468 for (var i = 0; i < count; i++) {
45469 contentHeight = Math.max(contentHeight, this._presenter.getCellContentHeight(this._realizedCornerCells[i]));
45470 }
45471 count = this._realizedColumnHeaders.length;
45472 for (var i = 0; i < count; i++) {
45473 var cell = this._realizedColumnHeaders[i];
45474 if (cell.rowSpan === 1)
45475 contentHeight = Math.max(contentHeight, this._presenter.getCellContentHeight(cell));
45476 }
45477 count = this._realizedBodyCells.length;
45478 for (var i = 0; i < count; i++) {
45479 contentHeight = Math.max(contentHeight, this._presenter.getCellContentHeight(this._realizedBodyCells[i]));
45480 }
45481 return this._containerHeight = contentHeight;
45482 };
45483 TablixRow.prototype.setAligningContextualWidth = function (size) {
45484 // TODO should be implemented when we support variable row heights
45485 };
45486 TablixRow.prototype.getAligningContextualWidth = function () {
45487 // TODO should be implemented when we support variable row heights
45488 return -1;
45489 };
45490 TablixRow.prototype.setContentHeight = function () {
45491 var count = this._realizedRowHeaders.length;
45492 // Need to do them in reverse order so that leaf headers are set first
45493 for (var i = count - 1; i >= 0; i--) {
45494 var cell = this._realizedRowHeaders[i];
45495 cell.setContainerHeight(this._containerHeight);
45496 if (cell.rowSpan > 1)
45497 cell.setContainerHeight(this.getCellSpanningHeight(cell));
45498 }
45499 count = this._realizedCornerCells.length;
45500 for (var i = 0; i < count; i++) {
45501 this._realizedCornerCells[i].setContainerHeight(this._containerHeight);
45502 }
45503 count = this._realizedColumnHeaders.length;
45504 for (var i = 0; i < count; i++) {
45505 var cell = this._realizedColumnHeaders[i];
45506 cell.setContainerHeight(this._containerHeight);
45507 if (cell.rowSpan > 1)
45508 cell.setContainerHeight(this.getCellSpanningHeight(cell));
45509 }
45510 count = this._realizedBodyCells.length;
45511 for (var i = 0; i < count; i++) {
45512 this._realizedBodyCells[i].setContainerHeight(this._containerHeight);
45513 }
45514 this._height = -1;
45515 };
45516 TablixRow.prototype.getIndex = function (grid) {
45517 return grid.realizedRows.indexOf(this);
45518 };
45519 TablixRow.prototype.getHeaders = function () {
45520 return this._realizedRowHeaders;
45521 };
45522 TablixRow.prototype.getOtherDimensionHeaders = function () {
45523 return this._realizedColumnHeaders;
45524 };
45525 TablixRow.prototype.getCellContextualSpan = function (cell) {
45526 return cell.rowSpan;
45527 };
45528 TablixRow.prototype.getOtherDimensionOwner = function (cell) {
45529 return cell._column;
45530 };
45531 return TablixRow;
45532 }());
45533 internal.TablixRow = TablixRow;
45534 var TablixGrid = (function () {
45535 function TablixGrid(presenter) {
45536 this._presenter = presenter;
45537 this._footerRow = null;
45538 }
45539 TablixGrid.prototype.initialize = function (owner, gridHost, footerHost) {
45540 this._owner = owner;
45541 this._presenter.initialize(this, gridHost, footerHost, owner);
45542 this.fillColumnsProportionally = false;
45543 this._realizedRows = [];
45544 this._realizedColumns = [];
45545 this._emptySpaceHeaderCell = null;
45546 this._emptyFooterSpaceCell = null;
45547 };
45548 Object.defineProperty(TablixGrid.prototype, "owner", {
45549 get: function () {
45550 return this._owner;
45551 },
45552 enumerable: true,
45553 configurable: true
45554 });
45555 Object.defineProperty(TablixGrid.prototype, "fillColumnsProportionally", {
45556 get: function () {
45557 return this._fillColumnsProportionally;
45558 },
45559 set: function (value) {
45560 if (this._fillColumnsProportionally === value)
45561 return;
45562 this._fillColumnsProportionally = value;
45563 this._presenter.onFillColumnsProportionallyChanged(value);
45564 },
45565 enumerable: true,
45566 configurable: true
45567 });
45568 Object.defineProperty(TablixGrid.prototype, "realizedColumns", {
45569 get: function () {
45570 return this._realizedColumns;
45571 },
45572 set: function (columns) {
45573 this._realizedColumns = columns;
45574 },
45575 enumerable: true,
45576 configurable: true
45577 });
45578 Object.defineProperty(TablixGrid.prototype, "realizedRows", {
45579 get: function () {
45580 return this._realizedRows;
45581 },
45582 set: function (rows) {
45583 this._realizedRows = rows;
45584 },
45585 enumerable: true,
45586 configurable: true
45587 });
45588 Object.defineProperty(TablixGrid.prototype, "footerRow", {
45589 get: function () {
45590 return this._footerRow;
45591 },
45592 enumerable: true,
45593 configurable: true
45594 });
45595 Object.defineProperty(TablixGrid.prototype, "emptySpaceHeaderCell", {
45596 get: function () {
45597 return this._emptySpaceHeaderCell;
45598 },
45599 enumerable: true,
45600 configurable: true
45601 });
45602 Object.defineProperty(TablixGrid.prototype, "emptySpaceFooterCell", {
45603 get: function () {
45604 return this._emptyFooterSpaceCell;
45605 },
45606 enumerable: true,
45607 configurable: true
45608 });
45609 TablixGrid.prototype.ShowEmptySpaceCells = function (rowSpan, width) {
45610 if (this._realizedRows.length === 0)
45611 return;
45612 if (this._realizedRows.length !== 0 && !this._emptySpaceHeaderCell) {
45613 this._emptySpaceHeaderCell = this._realizedRows[0].getOrCreateEmptySpaceCell();
45614 this._emptySpaceHeaderCell.rowSpan = rowSpan;
45615 this._emptySpaceHeaderCell.colSpan = 1;
45616 this._emptySpaceHeaderCell.setContainerWidth(width);
45617 }
45618 if (this._footerRow && (this._emptyFooterSpaceCell === null)) {
45619 this._emptyFooterSpaceCell = this._footerRow.getOrCreateEmptySpaceCell();
45620 this._emptyFooterSpaceCell.rowSpan = 1;
45621 this._emptyFooterSpaceCell.colSpan = 1;
45622 this._emptyFooterSpaceCell.setContainerWidth(width);
45623 }
45624 };
45625 TablixGrid.prototype.HideEmptySpaceCells = function () {
45626 if (this._emptySpaceHeaderCell) {
45627 this._emptySpaceHeaderCell.clear();
45628 this._emptySpaceHeaderCell = null;
45629 }
45630 if (this._emptyFooterSpaceCell) {
45631 this._emptyFooterSpaceCell.clear();
45632 this._emptyFooterSpaceCell = null;
45633 }
45634 };
45635 TablixGrid.prototype.onStartRenderingSession = function (clear) {
45636 if (clear) {
45637 this.clearRows();
45638 this.clearColumns();
45639 }
45640 };
45641 TablixGrid.prototype.onStartRenderingIteration = function () {
45642 this.initializeRows();
45643 this.initializeColumns();
45644 };
45645 TablixGrid.prototype.onEndRenderingIteration = function () {
45646 var rows = this._rows;
45647 if (rows !== undefined) {
45648 var rowCount = rows.length;
45649 for (var i = 0; i < rowCount; i++) {
45650 rows[i].releaseUnusedCells(this._owner);
45651 }
45652 }
45653 if (this._footerRow) {
45654 this._footerRow.releaseUnusedCells(this._owner);
45655 }
45656 };
45657 TablixGrid.prototype.getOrCreateRow = function (rowIndex) {
45658 var currentRow = this._rows[rowIndex];
45659 if (currentRow === undefined) {
45660 currentRow = new TablixRow(this._presenter.createRowPresenter());
45661 currentRow.initialize(this);
45662 this._presenter.onAppendRow(currentRow);
45663 this._rows[rowIndex] = currentRow;
45664 }
45665 if (this._realizedRows[rowIndex] === undefined) {
45666 this._realizedRows[rowIndex] = currentRow;
45667 }
45668 return currentRow;
45669 };
45670 TablixGrid.prototype.getOrCreateFootersRow = function () {
45671 if (this._footerRow === null) {
45672 this._footerRow = new TablixRow(this._presenter.createRowPresenter());
45673 this._footerRow.initialize(this);
45674 this._presenter.onAddFooterRow(this._footerRow);
45675 }
45676 return this._footerRow;
45677 };
45678 TablixGrid.prototype.moveRowsToEnd = function (moveFromIndex, count) {
45679 for (var i = 0; i < count; i++) {
45680 var row = this._rows[i + moveFromIndex];
45681 debug.assertValue(row, "Invalid Row Index");
45682 row.unfixSize();
45683 this._presenter.onRemoveRow(row);
45684 this._presenter.onAppendRow(row);
45685 this._rows.push(row);
45686 }
45687 this._rows.splice(moveFromIndex, count);
45688 };
45689 TablixGrid.prototype.moveRowsToStart = function (moveToIndex, count) {
45690 var refRow = this._rows[moveToIndex];
45691 debug.assertValue(refRow, "Invalid Row Index");
45692 for (var i = 0; i < count; i++) {
45693 var row = this._rows.pop();
45694 row.unfixSize();
45695 this._presenter.onRemoveRow(row);
45696 this._presenter.onInsertRowBefore(row, refRow);
45697 this._rows.splice(moveToIndex + i, 0, row);
45698 }
45699 };
45700 TablixGrid.prototype.moveColumnsToEnd = function (moveFromIndex, count) {
45701 var firstCol = this._rows[0]._realizedCornerCells.length;
45702 var leafStartDepth = Math.max(this._columns[firstCol]._realizedColumnHeaders.length - 1, 0);
45703 for (var i = leafStartDepth; i < this._rows.length; i++) {
45704 this._rows[i].moveScrollableCellsToEnd(count);
45705 }
45706 for (var i = 0; i < count; i++) {
45707 var column = this._columns[i + moveFromIndex];
45708 //Debug.assertValue(column, "Invalid Column Index");
45709 this._columns.push(column);
45710 }
45711 this._columns.splice(moveFromIndex, count);
45712 };
45713 TablixGrid.prototype.moveColumnsToStart = function (moveToIndex, count) {
45714 var firstCol = this._rows[0]._realizedCornerCells.length;
45715 var leafStartDepth = Math.max(this._columns[firstCol]._realizedColumnHeaders.length - 1, 0);
45716 for (var i = leafStartDepth; i < this._rows.length; i++) {
45717 this._rows[i].moveScrollableCellsToStart(count);
45718 }
45719 for (var i = 0; i < count; i++) {
45720 var column = this._columns.pop();
45721 this._columns.splice(moveToIndex + i, 0, column);
45722 }
45723 };
45724 TablixGrid.prototype.getOrCreateColumn = function (columnIndex) {
45725 var currentColumn = this._columns[columnIndex];
45726 if (currentColumn === undefined) {
45727 currentColumn = new TablixColumn(this._presenter.createColumnPresenter(columnIndex), columnIndex);
45728 currentColumn.initialize(this);
45729 this._columns[columnIndex] = currentColumn;
45730 }
45731 if (this._realizedColumns[columnIndex] === undefined) {
45732 this._realizedColumns[columnIndex] = currentColumn;
45733 }
45734 return currentColumn;
45735 };
45736 TablixGrid.prototype.initializeColumns = function () {
45737 if (!this._columns)
45738 this._columns = [];
45739 var length = this._columns.length;
45740 for (var i = 0; i < length; i++) {
45741 this._columns[i].initialize(this);
45742 }
45743 this._realizedColumns = [];
45744 };
45745 TablixGrid.prototype.clearColumns = function () {
45746 this._columns = null;
45747 this._realizedColumns = null;
45748 };
45749 TablixGrid.prototype.initializeRows = function () {
45750 // make sure rowDimension confirms it and it's not null in the grid
45751 var hasFooter = this._owner.rowDimension.hasFooter() && (this._footerRow !== null);
45752 this._realizedRows = [];
45753 if (!this._rows) {
45754 this._rows = [];
45755 }
45756 var rows = this._rows;
45757 var length = rows.length;
45758 for (var i = 0; i < length; i++) {
45759 rows[i].initialize(this);
45760 }
45761 if (hasFooter) {
45762 if (!this._footerRow) {
45763 this.getOrCreateFootersRow();
45764 }
45765 this._footerRow.initialize(this);
45766 }
45767 };
45768 TablixGrid.prototype.clearRows = function () {
45769 var rows = this._rows;
45770 if (rows) {
45771 var length_1 = rows.length;
45772 for (var i = 0; i < length_1; i++) {
45773 rows[i].releaseAllCells(this._owner);
45774 }
45775 if (this._footerRow)
45776 this._footerRow.releaseAllCells(this._owner);
45777 this._presenter.onClear();
45778 this._footerRow = null;
45779 this._rows = null;
45780 this._realizedRows = null;
45781 }
45782 };
45783 TablixGrid.prototype.getWidth = function () {
45784 return this._presenter.getWidth();
45785 };
45786 TablixGrid.prototype.getHeight = function () {
45787 return this._presenter.getHeight();
45788 };
45789 return TablixGrid;
45790 }());
45791 internal.TablixGrid = TablixGrid;
45792 })(internal = controls.internal || (controls.internal = {}));
45793 })(controls = visuals.controls || (visuals.controls = {}));
45794 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
45795})(powerbi || (powerbi = {}));
45796/*
45797 * Power BI Visualizations
45798 *
45799 * Copyright (c) Microsoft Corporation
45800 * All rights reserved.
45801 * MIT License
45802 *
45803 * Permission is hereby granted, free of charge, to any person obtaining a copy
45804 * of this software and associated documentation files (the ""Software""), to deal
45805 * in the Software without restriction, including without limitation the rights
45806 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45807 * copies of the Software, and to permit persons to whom the Software is
45808 * furnished to do so, subject to the following conditions:
45809 *
45810 * The above copyright notice and this permission notice shall be included in
45811 * all copies or substantial portions of the Software.
45812 *
45813 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45814 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45815 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45816 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45817 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45818 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45819 * THE SOFTWARE.
45820 */
45821var powerbi;
45822(function (powerbi) {
45823 var visuals;
45824 (function (visuals) {
45825 var controls;
45826 (function (controls) {
45827 var internal;
45828 (function (internal) {
45829 var PixelConverter = jsCommon.PixelConverter;
45830 /**
45831 * This class is used for layouts that don't or cannot
45832 * rely on DOM measurements. Instead they compute all required
45833 * widths and heights and store it in this structure.
45834 */
45835 var SizeComputationManager = (function () {
45836 function SizeComputationManager() {
45837 }
45838 Object.defineProperty(SizeComputationManager.prototype, "visibleWidth", {
45839 get: function () {
45840 return this._viewport ? this._viewport.width : 0;
45841 },
45842 enumerable: true,
45843 configurable: true
45844 });
45845 Object.defineProperty(SizeComputationManager.prototype, "visibleHeight", {
45846 get: function () {
45847 return this._viewport ? this._viewport.height : 0;
45848 },
45849 enumerable: true,
45850 configurable: true
45851 });
45852 Object.defineProperty(SizeComputationManager.prototype, "gridWidth", {
45853 get: function () {
45854 return this.visibleWidth;
45855 },
45856 enumerable: true,
45857 configurable: true
45858 });
45859 Object.defineProperty(SizeComputationManager.prototype, "gridHeight", {
45860 get: function () {
45861 return this.visibleHeight;
45862 },
45863 enumerable: true,
45864 configurable: true
45865 });
45866 Object.defineProperty(SizeComputationManager.prototype, "rowHeight", {
45867 get: function () {
45868 return this._cellHeight;
45869 },
45870 enumerable: true,
45871 configurable: true
45872 });
45873 Object.defineProperty(SizeComputationManager.prototype, "cellWidth", {
45874 get: function () {
45875 return this._cellWidth;
45876 },
45877 enumerable: true,
45878 configurable: true
45879 });
45880 Object.defineProperty(SizeComputationManager.prototype, "cellHeight", {
45881 get: function () {
45882 return this._cellHeight;
45883 },
45884 enumerable: true,
45885 configurable: true
45886 });
45887 Object.defineProperty(SizeComputationManager.prototype, "contentWidth", {
45888 get: function () {
45889 return this._cellWidth;
45890 },
45891 enumerable: true,
45892 configurable: true
45893 });
45894 Object.defineProperty(SizeComputationManager.prototype, "contentHeight", {
45895 get: function () {
45896 return this._cellHeight;
45897 },
45898 enumerable: true,
45899 configurable: true
45900 });
45901 SizeComputationManager.prototype.updateColumnCount = function (columnCount) {
45902 this._columnCount = columnCount;
45903 };
45904 SizeComputationManager.prototype.updateRowHeight = function (rowHeight) {
45905 this._cellHeight = rowHeight;
45906 };
45907 SizeComputationManager.prototype.updateScalingFactor = function (scalingFactor) {
45908 this._scalingFactor = scalingFactor;
45909 this._cellWidth = this.computeColumnWidth(this._columnCount);
45910 };
45911 SizeComputationManager.prototype.updateViewport = function (viewport) {
45912 this._viewport = viewport;
45913 this._cellWidth = this.computeColumnWidth(this._columnCount);
45914 this._cellHeight = this.computeColumnHeight();
45915 };
45916 SizeComputationManager.prototype.computeColumnWidth = function (totalColumnCount) {
45917 var scalingFactor = this._scalingFactor;
45918 if (!scalingFactor)
45919 scalingFactor = 1;
45920 var minimumColumnWidth = scalingFactor * SizeComputationManager.TablixMinimumColumnWidth;
45921 var maxAllowedColumns = Math.floor(this._viewport.width / minimumColumnWidth);
45922 return this.fitToColumnCount(maxAllowedColumns, totalColumnCount);
45923 };
45924 SizeComputationManager.prototype.computeColumnHeight = function () {
45925 if (!this.hasImageContent)
45926 return this._cellHeight;
45927 var width = this._viewport.width;
45928 if (width <= 250) {
45929 // Small
45930 return 20;
45931 }
45932 else if (width <= 510) {
45933 // Medium
45934 return 51;
45935 }
45936 else if (width <= 770) {
45937 // Large
45938 return 52;
45939 }
45940 debug.assertFail("Fixed size is only for viewport up to 770px width.");
45941 };
45942 SizeComputationManager.prototype.fitToColumnCount = function (maxAllowedColumnCount, totalColumnCount) {
45943 var columnsToFit = Math.min(maxAllowedColumnCount, totalColumnCount);
45944 return Math.floor(this._viewport.width / columnsToFit);
45945 };
45946 // Minimum size for a column, used to calculate layout
45947 SizeComputationManager.TablixMinimumColumnWidth = 75;
45948 return SizeComputationManager;
45949 }());
45950 internal.SizeComputationManager = SizeComputationManager;
45951 var DimensionLayoutManager = (function () {
45952 function DimensionLayoutManager(owner, grid, realizationManager) {
45953 //debug.assertValue(realizationManager, "Realization Manager must be defined");
45954 this._owner = owner;
45955 this._grid = grid;
45956 this._lastScrollOffset = null;
45957 this._isScrolling = false;
45958 this._fixedSizeEnabled = true;
45959 this._done = false;
45960 this._realizationManager = realizationManager;
45961 }
45962 Object.defineProperty(DimensionLayoutManager.prototype, "owner", {
45963 get: function () {
45964 return this._owner;
45965 },
45966 set: function (owner) {
45967 this._owner = owner;
45968 },
45969 enumerable: true,
45970 configurable: true
45971 });
45972 Object.defineProperty(DimensionLayoutManager.prototype, "realizationManager", {
45973 get: function () {
45974 return this._realizationManager;
45975 },
45976 enumerable: true,
45977 configurable: true
45978 });
45979 Object.defineProperty(DimensionLayoutManager.prototype, "fixedSizeEnabled", {
45980 get: function () {
45981 return this._fixedSizeEnabled;
45982 },
45983 set: function (enable) {
45984 this._fixedSizeEnabled = enable;
45985 },
45986 enumerable: true,
45987 configurable: true
45988 });
45989 DimensionLayoutManager.prototype.onCornerCellRealized = function (item, cell, leaf) {
45990 this._realizationManager.onCornerCellRealized(item, cell);
45991 };
45992 DimensionLayoutManager.prototype.onHeaderRealized = function (item, cell, leaf) {
45993 this._realizationManager.onHeaderRealized(item, cell, leaf);
45994 };
45995 Object.defineProperty(DimensionLayoutManager.prototype, "needsToRealize", {
45996 get: function () {
45997 return this._realizationManager.needsToRealize;
45998 },
45999 enumerable: true,
46000 configurable: true
46001 });
46002 DimensionLayoutManager.prototype.getVisibleSizeRatio = function () {
46003 return 1 - this.dimension.getFractionScrollOffset();
46004 };
46005 Object.defineProperty(DimensionLayoutManager.prototype, "alignToEnd", {
46006 get: function () {
46007 return this._alignToEnd;
46008 },
46009 enumerable: true,
46010 configurable: true
46011 });
46012 Object.defineProperty(DimensionLayoutManager.prototype, "done", {
46013 get: function () {
46014 return this._done;
46015 },
46016 enumerable: true,
46017 configurable: true
46018 });
46019 DimensionLayoutManager.prototype._requiresMeasure = function () {
46020 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._requiresMeasure");
46021 return true;
46022 };
46023 DimensionLayoutManager.prototype.startScrollingSession = function () {
46024 this._isScrolling = true;
46025 };
46026 DimensionLayoutManager.prototype.endScrollingSession = function () {
46027 this._isScrolling = false;
46028 };
46029 DimensionLayoutManager.prototype.isScrolling = function () {
46030 return this._isScrolling;
46031 };
46032 DimensionLayoutManager.prototype.isResizing = function () {
46033 return false;
46034 };
46035 DimensionLayoutManager.prototype.getOtherHierarchyContextualHeight = function () {
46036 var otherDimension = this.dimension.otherDimension;
46037 var count = otherDimension.getDepth();
46038 var contextualHeight = 0;
46039 var items = this._getRealizedItems();
46040 if (items.length > 0) {
46041 for (var i = 0; i < count; i++) {
46042 contextualHeight += items[i].getContextualWidth();
46043 }
46044 }
46045 return contextualHeight;
46046 };
46047 DimensionLayoutManager.prototype._isAutoSized = function () {
46048 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._isAutoSized");
46049 return false;
46050 };
46051 DimensionLayoutManager.prototype.onStartRenderingSession = function () {
46052 this._measureEnabled = this._requiresMeasure();
46053 this._gridOffset = this.dimension.otherDimension.getDepth();
46054 };
46055 DimensionLayoutManager.prototype.onEndRenderingSession = function () {
46056 this._realizationManager.onEndRenderingSession();
46057 this._alignToEnd = false;
46058 this._done = false;
46059 this._measureEnabled = true;
46060 this._sendDimensionsToControl();
46061 };
46062 /**
46063 * Implementing classes must override this to send dimentions to TablixControl.
46064 */
46065 DimensionLayoutManager.prototype._sendDimensionsToControl = function () {
46066 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._sendDimensionsToControl");
46067 };
46068 Object.defineProperty(DimensionLayoutManager.prototype, "measureEnabled", {
46069 get: function () {
46070 return this._measureEnabled;
46071 },
46072 enumerable: true,
46073 configurable: true
46074 });
46075 DimensionLayoutManager.prototype.getFooterContextualWidth = function () {
46076 return 0;
46077 };
46078 DimensionLayoutManager.prototype.onStartRenderingIteration = function (clear, contextualWidth) {
46079 if (this._measureEnabled && !this._done) {
46080 this._contextualWidthToFill = (contextualWidth - this.otherScrollbarContextualWidth) * this.getGridScale() - this.getFooterContextualWidth();
46081 }
46082 this._realizationManager.onStartRenderingIteration();
46083 if (clear) {
46084 this._lastScrollOffset = null;
46085 }
46086 else if (this._lastScrollOffset !== null) {
46087 this.swapElements();
46088 }
46089 };
46090 Object.defineProperty(DimensionLayoutManager.prototype, "allItemsRealized", {
46091 get: function () {
46092 return this.getRealizedItemsCount() - this._gridOffset === this.dimension.getItemsCount() || this.dimension.getItemsCount() === 0;
46093 },
46094 enumerable: true,
46095 configurable: true
46096 });
46097 DimensionLayoutManager.prototype.onEndRenderingIteration = function () {
46098 if (this._done) {
46099 return;
46100 }
46101 if (!this._measureEnabled) {
46102 this._lastScrollOffset = this.dimension.scrollOffset;
46103 this._done = true;
46104 return;
46105 }
46106 var gridContextualWidth = this.getGridContextualWidth();
46107 var filled = powerbi.Double.greaterOrEqualWithPrecision(gridContextualWidth, this._contextualWidthToFill, DimensionLayoutManager._pixelPrecision);
46108 var allRealized = this.allItemsRealized;
46109 var newScrollOffset;
46110 if (filled) {
46111 newScrollOffset = this.scrollForwardToAlignEnd(gridContextualWidth);
46112 }
46113 else {
46114 newScrollOffset = this.scrollBackwardToFill(gridContextualWidth);
46115 }
46116 this._realizationManager.onEndRenderingIteration(gridContextualWidth, filled);
46117 var originalScrollbarVisible = this.dimension.scrollbar.visible;
46118 this.updateScrollbar(gridContextualWidth);
46119 this._done = (filled || allRealized) &&
46120 this.dimension.scrollbar.visible === originalScrollbarVisible &&
46121 powerbi.Double.equalWithPrecision(newScrollOffset, this.dimension.scrollOffset, DimensionLayoutManager._scrollOffsetPrecision);
46122 this.dimension.scrollOffset = newScrollOffset;
46123 this._lastScrollOffset = this.dimension.scrollOffset;
46124 };
46125 DimensionLayoutManager.prototype.getScrollDeltaWithinPage = function () {
46126 if (this._lastScrollOffset !== null) {
46127 var delta = this.dimension.getIntegerScrollOffset() - Math.floor(this._lastScrollOffset);
46128 if (Math.abs(delta) < this.getRealizedItemsCount() - this.dimension.otherDimension.getDepth()) {
46129 return delta;
46130 }
46131 }
46132 return null;
46133 };
46134 DimensionLayoutManager.prototype.swapElements = function () {
46135 var delta = this.getScrollDeltaWithinPage();
46136 if (delta !== null) {
46137 var otherHierarchyDepth = this.dimension.otherDimension.getDepth();
46138 if (Math.abs(delta) < this.getRealizedItemsCount() - otherHierarchyDepth) {
46139 if (delta > 0) {
46140 this._moveElementsToBottom(otherHierarchyDepth, delta);
46141 }
46142 else if (delta < 0) {
46143 this._moveElementsToTop(otherHierarchyDepth, -delta);
46144 }
46145 }
46146 }
46147 };
46148 DimensionLayoutManager.prototype._getRealizedItems = function () {
46149 // abstract
46150 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._getRealizedItems");
46151 return null;
46152 };
46153 DimensionLayoutManager.prototype.getRealizedItemsCount = function () {
46154 var realizedItems = this._getRealizedItems();
46155 return realizedItems.length;
46156 };
46157 DimensionLayoutManager.prototype._moveElementsToBottom = function (moveFromIndex, count) {
46158 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._moveElementsToBottom");
46159 };
46160 DimensionLayoutManager.prototype._moveElementsToTop = function (moveToIndex, count) {
46161 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._moveElementsToTop");
46162 };
46163 DimensionLayoutManager.prototype.isScrollingWithinPage = function () {
46164 return this.getScrollDeltaWithinPage() !== null;
46165 };
46166 DimensionLayoutManager.prototype.getGridContextualWidth = function () {
46167 debug.assertFail("PureVirtualMethod: DimensionLayoutManager.getGridContextualWidth");
46168 return 0;
46169 };
46170 DimensionLayoutManager.prototype.updateScrollbar = function (gridContextualWidth) {
46171 var scrollbar = this.dimension.scrollbar;
46172 scrollbar.viewMin = this.dimension.scrollOffset;
46173 scrollbar.min = 0;
46174 scrollbar.max = this.dimension.getItemsCount();
46175 scrollbar.viewSize = this.getViewSize(gridContextualWidth);
46176 this.dimension.scrollbar.show(this.canScroll(gridContextualWidth));
46177 };
46178 DimensionLayoutManager.prototype.getViewSize = function (gridContextualWidth) {
46179 var count = this.getRealizedItemsCount();
46180 if (count === 0)
46181 return 0;
46182 var startIndex = this._gridOffset;
46183 var sizeInItems = 0;
46184 var sizeInPixels = 0;
46185 var widthToFill = this._contextualWidthToFill;
46186 var scrollableArea = widthToFill - this.getOtherHierarchyContextualHeight();
46187 var error = this.getMeaurementError(gridContextualWidth);
46188 for (var i = startIndex; i < count; i++) {
46189 var visibleRatio = void 0;
46190 if (i === startIndex) {
46191 visibleRatio = this.getVisibleSizeRatio();
46192 }
46193 else
46194 visibleRatio = 1;
46195 var itemContextualWidth = this.getItemContextualWidthWithScrolling(i) * error;
46196 sizeInPixels += itemContextualWidth;
46197 sizeInItems += visibleRatio;
46198 if (powerbi.Double.greaterWithPrecision(sizeInPixels, scrollableArea, DimensionLayoutManager._pixelPrecision)) {
46199 sizeInItems -= ((sizeInPixels - scrollableArea) / itemContextualWidth) * visibleRatio;
46200 break;
46201 }
46202 }
46203 return sizeInItems;
46204 };
46205 DimensionLayoutManager.prototype.isScrollableHeader = function (item, items, index) {
46206 if (index !== 0 || this.dimension.getFractionScrollOffset() === 0) {
46207 return false;
46208 }
46209 var hierarchyNavigator = this.dimension._hierarchyNavigator;
46210 if (hierarchyNavigator.isLeaf(item)) {
46211 return true;
46212 }
46213 var currentItem = item;
46214 var currentItems = items;
46215 do {
46216 currentItems = hierarchyNavigator.getChildren(currentItem);
46217 currentItem = this.dimension.getFirstVisibleItem(hierarchyNavigator.getLevel(currentItem) + 1);
46218 if (currentItem === undefined) {
46219 break;
46220 }
46221 if (!hierarchyNavigator.isLastItem(currentItem, currentItems)) {
46222 return false;
46223 }
46224 } while (!hierarchyNavigator.isLeaf(currentItem));
46225 return true;
46226 };
46227 DimensionLayoutManager.prototype.reachedEnd = function () {
46228 return this.dimension.getIntegerScrollOffset() + (this.getRealizedItemsCount() - this._gridOffset) >= this.dimension.getItemsCount();
46229 };
46230 DimensionLayoutManager.prototype.scrollBackwardToFill = function (gridContextualWidth) {
46231 var newScrollOffset = this.dimension.scrollOffset;
46232 if (this.reachedEnd()) {
46233 var widthToFill = this._contextualWidthToFill - gridContextualWidth;
46234 if (this.dimension.getItemsCount() > 0) {
46235 var averageColumnwidth = gridContextualWidth / (this.getRealizedItemsCount() - this.dimension.getFractionScrollOffset());
46236 newScrollOffset = this.dimension.getValidScrollOffset(Math.floor(this.dimension.scrollOffset - (widthToFill / averageColumnwidth)));
46237 }
46238 this._alignToEnd = !powerbi.Double.equalWithPrecision(newScrollOffset, this.dimension.scrollOffset, DimensionLayoutManager._scrollOffsetPrecision); // this is an aproximate scrolling back, we have to ensure it is aligned to the end of the control
46239 }
46240 return newScrollOffset;
46241 };
46242 DimensionLayoutManager.prototype.getItemContextualWidth = function (index) {
46243 var realizedItems = this._getRealizedItems();
46244 if (index >= realizedItems.length)
46245 return null;
46246 return realizedItems[index].getContextualWidth();
46247 };
46248 DimensionLayoutManager.prototype.getItemContextualWidthWithScrolling = function (index) {
46249 return this.getSizeWithScrolling(this.getItemContextualWidth(index), index);
46250 };
46251 DimensionLayoutManager.prototype.getSizeWithScrolling = function (size, index) {
46252 var ratio;
46253 if (this._gridOffset === index) {
46254 ratio = this.getVisibleSizeRatio();
46255 }
46256 else {
46257 ratio = 1;
46258 }
46259 return size * ratio;
46260 };
46261 DimensionLayoutManager.prototype.getGridContextualWidthFromItems = function () {
46262 var count = this.getRealizedItemsCount();
46263 var contextualWidth = 0;
46264 for (var i = 0; i < count; i++) {
46265 contextualWidth += this.getItemContextualWidthWithScrolling(i);
46266 }
46267 return contextualWidth;
46268 };
46269 DimensionLayoutManager.prototype.getMeaurementError = function (gridContextualWidth) {
46270 return gridContextualWidth / this.getGridContextualWidthFromItems();
46271 };
46272 DimensionLayoutManager.prototype.scrollForwardToAlignEnd = function (gridContextualWidth) {
46273 var newScrollOffset = this.dimension.scrollOffset;
46274 if (this._alignToEnd) {
46275 var withinThreshold = powerbi.Double.equalWithPrecision(gridContextualWidth, this._contextualWidthToFill, DimensionLayoutManager._pixelPrecision);
46276 if (!withinThreshold) {
46277 var count = this.getRealizedItemsCount();
46278 var startIndex = this._gridOffset;
46279 var widthToScroll = gridContextualWidth - this._contextualWidthToFill;
46280 var error = this.getMeaurementError(gridContextualWidth);
46281 for (var i = startIndex; i < count; i++) {
46282 var itemContextualWidth = this.getItemContextualWidth(i) * error;
46283 if (powerbi.Double.lessWithPrecision(itemContextualWidth, widthToScroll, DimensionLayoutManager._pixelPrecision)) {
46284 widthToScroll -= itemContextualWidth;
46285 }
46286 else {
46287 var visibleRatio = startIndex === i ? 1 - this.dimension.getFractionScrollOffset() : 1;
46288 newScrollOffset = this.dimension.getValidScrollOffset(this.dimension.scrollOffset + (i - startIndex) + (widthToScroll * visibleRatio / itemContextualWidth));
46289 break;
46290 }
46291 }
46292 }
46293 this._alignToEnd = !withinThreshold;
46294 }
46295 return newScrollOffset;
46296 };
46297 Object.defineProperty(DimensionLayoutManager.prototype, "dimension", {
46298 get: function () {
46299 debug.assertFail("PureVirtualMethod: DimensionLayoutManager.dimension");
46300 return null;
46301 },
46302 enumerable: true,
46303 configurable: true
46304 });
46305 Object.defineProperty(DimensionLayoutManager.prototype, "otherLayoutManager", {
46306 get: function () {
46307 return this.dimension.otherDimension.layoutManager;
46308 },
46309 enumerable: true,
46310 configurable: true
46311 });
46312 Object.defineProperty(DimensionLayoutManager.prototype, "contextualWidthToFill", {
46313 get: function () {
46314 return this._contextualWidthToFill;
46315 },
46316 enumerable: true,
46317 configurable: true
46318 });
46319 DimensionLayoutManager.prototype.getGridScale = function () {
46320 debug.assertFail("PureVirtualMethod: DimensionLayoutManager.getGridScale");
46321 return 0;
46322 };
46323 Object.defineProperty(DimensionLayoutManager.prototype, "otherScrollbarContextualWidth", {
46324 get: function () {
46325 debug.assertFail("PureVirtualMethod: DimensionLayoutManager.otherScrollbarContextualWidth");
46326 return 0;
46327 },
46328 enumerable: true,
46329 configurable: true
46330 });
46331 DimensionLayoutManager.prototype.getActualContextualWidth = function (gridContextualWidth) {
46332 if (this._isAutoSized() && !this.canScroll(gridContextualWidth))
46333 return gridContextualWidth;
46334 return this._contextualWidthToFill;
46335 };
46336 DimensionLayoutManager.prototype.canScroll = function (gridContextualWidth) {
46337 debug.assertFail("PureVirtualMethod: DimensionLayoutManager.canScroll");
46338 return false;
46339 };
46340 DimensionLayoutManager.prototype.calculateSizes = function () {
46341 if (this.fixedSizeEnabled) {
46342 this.calculateContextualWidths();
46343 this.calculateSpans();
46344 }
46345 };
46346 DimensionLayoutManager.prototype._calculateSize = function (item) {
46347 debug.assertFail("PureVirtualMethod: DimensionLayoutManager._calculateSize");
46348 return null;
46349 };
46350 DimensionLayoutManager.prototype.calculateContextualWidths = function () {
46351 var items = this._getRealizedItems();
46352 var count = items.length;
46353 for (var i = 0; i < count; i++) {
46354 var item = items[i];
46355 if (this.measureEnabled)
46356 item.setAligningContextualWidth(-1);
46357 this._calculateSize(item);
46358 }
46359 };
46360 DimensionLayoutManager.prototype.calculateSpans = function () {
46361 if (this.measureEnabled) {
46362 this.updateNonScrollableItemsSpans();
46363 this.updateScrollableItemsSpans();
46364 }
46365 // TODO override in row layout manager to add footer to calculation, this is required for Matrix
46366 };
46367 DimensionLayoutManager.prototype.updateNonScrollableItemsSpans = function () {
46368 var otherDimensionItems = this.otherLayoutManager._getRealizedItems();
46369 var otherDimensionItemsCount = otherDimensionItems.length;
46370 var startIndex = this.dimension.getDepth();
46371 for (var i = startIndex; i < otherDimensionItemsCount; i++) {
46372 var otherDimensionItem = otherDimensionItems[i];
46373 this.updateSpans(otherDimensionItem, otherDimensionItem.getHeaders());
46374 }
46375 };
46376 DimensionLayoutManager.prototype.updateScrollableItemsSpans = function () {
46377 var otherRealizedItems = this.otherLayoutManager._getRealizedItems();
46378 var otherRealizedItemsCount = Math.min(this.dimension.getDepth(), otherRealizedItems.length);
46379 for (var i = 0; i < otherRealizedItemsCount; i++) {
46380 var otherRealizedItem = otherRealizedItems[i];
46381 this.updateSpans(otherRealizedItem, otherRealizedItem.getOtherDimensionHeaders());
46382 }
46383 };
46384 DimensionLayoutManager.prototype.fixSizes = function () {
46385 if (this.fixedSizeEnabled) {
46386 var items = this._getRealizedItems();
46387 var count = items.length;
46388 for (var i = count - 1; i >= 0; i--) {
46389 items[i].fixSize();
46390 }
46391 }
46392 };
46393 DimensionLayoutManager.prototype.updateSpans = function (otherRealizedItem, cells) {
46394 var realizedItems = this._getRealizedItems();
46395 var cellCount = cells.length;
46396 for (var j = 0; j < cellCount; j++) {
46397 var cell = cells[j];
46398 var owner = otherRealizedItem.getOtherDimensionOwner(cell);
46399 var span = owner.getCellContextualSpan(cell);
46400 if (span > 1) {
46401 var totalSizeInSpan = 0;
46402 var startIndex = owner.getIndex(this._grid);
46403 for (var k = 0; k < span; k++) {
46404 var item = realizedItems[k + startIndex];
46405 totalSizeInSpan += item.getContentContextualWidth();
46406 if (k === span - 1)
46407 this.updateLastChildSize(cell, item, totalSizeInSpan);
46408 }
46409 }
46410 }
46411 };
46412 DimensionLayoutManager.prototype.updateLastChildSize = function (spanningCell, item, totalSpanSize) {
46413 var delta = item.getCellIContentContextualWidth(spanningCell) - totalSpanSize;
46414 if (delta > 0)
46415 item.setAligningContextualWidth(Math.max(item.getAligningContextualWidth(), delta + item.getContentContextualWidth()));
46416 };
46417 DimensionLayoutManager._pixelPrecision = 1.0001;
46418 DimensionLayoutManager._scrollOffsetPrecision = 0.01;
46419 return DimensionLayoutManager;
46420 }());
46421 internal.DimensionLayoutManager = DimensionLayoutManager;
46422 var ResizeState = (function () {
46423 function ResizeState(column, width, scale) {
46424 this.column = column;
46425 this.item = column.getLeafItem();
46426 this.itemType = column.itemType;
46427 this.startColumnWidth = width;
46428 this.resizingDelta = 0;
46429 this.animationFrame = null;
46430 this.scale = scale;
46431 }
46432 ResizeState.prototype.getNewSize = function () {
46433 return this.startColumnWidth + this.resizingDelta;
46434 };
46435 return ResizeState;
46436 }());
46437 internal.ResizeState = ResizeState;
46438 var ColumnLayoutManager = (function (_super) {
46439 __extends(ColumnLayoutManager, _super);
46440 function ColumnLayoutManager(owner, grid, realizationManager) {
46441 _super.call(this, owner, grid, realizationManager);
46442 realizationManager.owner = this;
46443 this.fillProportionally = false;
46444 this._resizeState = null;
46445 }
46446 Object.defineProperty(ColumnLayoutManager.prototype, "dimension", {
46447 get: function () {
46448 return this.owner.owner.columnDimension;
46449 },
46450 enumerable: true,
46451 configurable: true
46452 });
46453 ColumnLayoutManager.prototype.isResizing = function () {
46454 return this._resizeState !== null;
46455 };
46456 Object.defineProperty(ColumnLayoutManager.prototype, "fillProportionally", {
46457 get: function () {
46458 return this._grid.fillColumnsProportionally;
46459 },
46460 set: function (value) {
46461 this._grid.fillColumnsProportionally = value;
46462 },
46463 enumerable: true,
46464 configurable: true
46465 });
46466 ColumnLayoutManager.prototype.getGridScale = function () {
46467 return this._grid._presenter.getScreenToCssRatioX();
46468 };
46469 Object.defineProperty(ColumnLayoutManager.prototype, "otherScrollbarContextualWidth", {
46470 get: function () {
46471 if (this.dimension.otherDimension.scrollbar.visible) {
46472 return controls.HTMLElementUtils.getElementWidth(this.dimension.otherDimension.scrollbar.element);
46473 }
46474 return 0;
46475 },
46476 enumerable: true,
46477 configurable: true
46478 });
46479 ColumnLayoutManager.prototype._getRealizedItems = function () {
46480 if (!this._grid.realizedColumns) {
46481 this._grid.realizedColumns = [];
46482 }
46483 return this._grid.realizedColumns;
46484 };
46485 ColumnLayoutManager.prototype._moveElementsToBottom = function (moveFromIndex, count) {
46486 this._grid.moveColumnsToEnd(moveFromIndex, count);
46487 };
46488 ColumnLayoutManager.prototype._moveElementsToTop = function (moveToIndex, count) {
46489 this._grid.moveColumnsToStart(moveToIndex, count);
46490 };
46491 ColumnLayoutManager.prototype._requiresMeasure = function () {
46492 // if the control is not scrolling in either dimension or is scrolling or is resizing
46493 return (!this.isScrolling() && !this.otherLayoutManager.isScrolling()) || this.isScrolling() || this.isResizing();
46494 };
46495 ColumnLayoutManager.prototype.getGridContextualWidth = function () {
46496 return this._grid.getWidth();
46497 };
46498 ColumnLayoutManager.prototype.getFirstVisibleColumn = function () {
46499 return this._grid.realizedColumns[this._gridOffset];
46500 };
46501 ColumnLayoutManager.prototype._isAutoSized = function () {
46502 return this.owner.owner.autoSizeWidth;
46503 };
46504 ColumnLayoutManager.prototype.applyScrolling = function () {
46505 var columnOffset = this.dimension.getFractionScrollOffset();
46506 var firstVisibleColumnWidth = 0;
46507 if (columnOffset !== 0) {
46508 var firstVisibleColumn = this.getFirstVisibleColumn();
46509 if (firstVisibleColumn !== undefined) {
46510 firstVisibleColumnWidth = firstVisibleColumn.getContextualWidth();
46511 this.scroll(firstVisibleColumn, firstVisibleColumnWidth, columnOffset);
46512 }
46513 }
46514 };
46515 ColumnLayoutManager.prototype.scroll = function (firstVisibleColumn, width, offset) {
46516 this.scrollCells(firstVisibleColumn._realizedColumnHeaders, width, offset);
46517 this.scrollBodyCells(this._grid.realizedRows, width, offset);
46518 if (firstVisibleColumn.footer !== null) {
46519 firstVisibleColumn.footer.scrollHorizontally(width, offset);
46520 }
46521 };
46522 ColumnLayoutManager.prototype.scrollCells = function (cells, width, offset) {
46523 var length = cells.length;
46524 for (var i = 0; i < length; i++) {
46525 cells[i].scrollHorizontally(width, offset);
46526 }
46527 };
46528 ColumnLayoutManager.prototype.scrollBodyCells = function (rows, width, offset) {
46529 var length = rows.length;
46530 var cells;
46531 var cell;
46532 for (var i = 0; i < length; i++) {
46533 cells = rows[i]._realizedBodyCells;
46534 if (cells !== undefined) {
46535 cell = cells[0];
46536 if (cell !== undefined) {
46537 cell.scrollHorizontally(width, offset);
46538 }
46539 }
46540 }
46541 };
46542 ColumnLayoutManager.prototype.onStartResize = function (cell, currentX, currentY) {
46543 this._resizeState = new ResizeState(cell._column, cell._column.getContentContextualWidth(), controls.HTMLElementUtils.getAccumulatedScale(this.owner.owner.container));
46544 };
46545 ColumnLayoutManager.prototype.onResize = function (cell, deltaX, deltaY) {
46546 var _this = this;
46547 if (this.isResizing()) {
46548 this._resizeState.resizingDelta = Math.round(Math.max(deltaX / this._resizeState.scale, ColumnLayoutManager.minColumnWidth - this._resizeState.startColumnWidth));
46549 if (this._resizeState.animationFrame === null)
46550 this._resizeState.animationFrame = requestAnimationFrame(function () { return _this.performResizing(); });
46551 }
46552 };
46553 ColumnLayoutManager.prototype.onEndResize = function (cell) {
46554 if (this.isResizing() && this._resizeState.animationFrame !== null) {
46555 this.performResizing(); // if we reached the end and we are still waiting for the last animation frame, perform the pending resizing and clear the state
46556 }
46557 this.endResizing();
46558 this._resizeState = null;
46559 };
46560 ColumnLayoutManager.prototype.onReset = function (cell) {
46561 this._resizeState = new ResizeState(cell._column, -1, 1);
46562 cell._column.clearSize();
46563 this.endResizing();
46564 this.owner.owner.refresh(false);
46565 this._resizeState = null;
46566 };
46567 ColumnLayoutManager.prototype.updateItemToResizeState = function (realizedColumns) {
46568 if (this._resizeState === null)
46569 return;
46570 var columnCount = realizedColumns.length;
46571 var hierarchyNavigator = this.owner.owner.hierarchyNavigator;
46572 // Only iterate over the columns that belong to column hierachy (i.e. skip the row hierarchy rows)
46573 // as this post-rendering adjustment only applies to them.
46574 var startIndex = this.otherLayoutManager.dimension.getDepth();
46575 for (var i = startIndex; i < columnCount; i++) {
46576 var column = realizedColumns[i];
46577 if (!column.columnHeaderOrCornerEquals(this._resizeState.itemType, this._resizeState.item, column.itemType, column.getLeafItem(), hierarchyNavigator))
46578 continue;
46579 if (column !== this._resizeState.column) {
46580 this._resizeState.column = column;
46581 column.onResize(this._resizeState.getNewSize());
46582 break;
46583 }
46584 }
46585 };
46586 ColumnLayoutManager.prototype.performResizing = function () {
46587 if (this._resizeState === null)
46588 return;
46589 this._resizeState.animationFrame = null;
46590 var newSize = this._resizeState.getNewSize();
46591 this._resizeState.column.onResize(newSize);
46592 this.owner.owner.refresh(false);
46593 };
46594 ColumnLayoutManager.prototype.endResizing = function () {
46595 if (this._resizeState === null)
46596 return;
46597 var newSize = this._resizeState.getNewSize();
46598 this._resizeState.column.onResizeEnd(newSize);
46599 };
46600 /**
46601 * Sends column related data (pixel size, column count, etc) to TablixControl.
46602 */
46603 ColumnLayoutManager.prototype._sendDimensionsToControl = function () {
46604 var gridContextualWidth = this.getGridContextualWidth();
46605 var widthToFill = this.getActualContextualWidth(gridContextualWidth);
46606 var otherContextualHeight = this.getOtherHierarchyContextualHeight();
46607 var scale = this.getGridScale(); // in case of canvas we have to convert the size from device pixel to css pixel
46608 this.owner.owner.updateColumnDimensions(otherContextualHeight / scale, (widthToFill - otherContextualHeight) / scale, this.getViewSize(gridContextualWidth));
46609 };
46610 ColumnLayoutManager.prototype.getEstimatedHeaderWidth = function (label, headerIndex) {
46611 debug.assertFail("PureVirtualMethod: ColumnLayoutManager.getEstimatedHeaderWidth");
46612 return -1;
46613 };
46614 ColumnLayoutManager.prototype.getEstimatedBodyCellWidth = function (content) {
46615 debug.assertFail("PureVirtualMethod: ColumnLayoutManager.getEstimatedBodyCellWidth");
46616 return -1;
46617 };
46618 ColumnLayoutManager.minColumnWidth = 10;
46619 return ColumnLayoutManager;
46620 }(DimensionLayoutManager));
46621 internal.ColumnLayoutManager = ColumnLayoutManager;
46622 var DashboardColumnLayoutManager = (function (_super) {
46623 __extends(DashboardColumnLayoutManager, _super);
46624 function DashboardColumnLayoutManager() {
46625 _super.apply(this, arguments);
46626 }
46627 DashboardColumnLayoutManager.prototype.getEstimatedHeaderWidth = function (label, headerIndex) {
46628 if (this.ignoreColumn(headerIndex))
46629 return 0;
46630 // for dashboard layout it does not matter whether we pass an actual cell or not
46631 return this.owner.getCellWidth(undefined);
46632 };
46633 DashboardColumnLayoutManager.prototype.getEstimatedBodyCellWidth = function (content) {
46634 // for dashboard layout it does not matter whether we pass an actual cell or not
46635 return this.owner.getCellWidth(undefined);
46636 };
46637 DashboardColumnLayoutManager.prototype.canScroll = function (gridContextualWidth) {
46638 return false;
46639 };
46640 DashboardColumnLayoutManager.prototype._calculateSize = function (item) {
46641 var headerIndex = item.getIndex(this._grid);
46642 var computedSize = 0;
46643 if (!this.ignoreColumn(headerIndex)) {
46644 // for dashboard layout it does not matter whether we pass an actual cell or not
46645 computedSize = this.owner.getContentWidth(undefined);
46646 }
46647 item.onResize(computedSize);
46648 item.onResizeEnd(computedSize);
46649 return computedSize;
46650 };
46651 DashboardColumnLayoutManager.prototype.ignoreColumn = function (headerIndex) {
46652 // On the dashboard, we need to return 0 if the row header is static
46653 // (a table or a matrix without row groups)
46654 return headerIndex === 0 && !this.owner.binder.hasRowGroups();
46655 };
46656 return DashboardColumnLayoutManager;
46657 }(ColumnLayoutManager));
46658 internal.DashboardColumnLayoutManager = DashboardColumnLayoutManager;
46659 var CanvasColumnLayoutManager = (function (_super) {
46660 __extends(CanvasColumnLayoutManager, _super);
46661 function CanvasColumnLayoutManager() {
46662 _super.apply(this, arguments);
46663 }
46664 CanvasColumnLayoutManager.prototype.getEstimatedHeaderWidth = function (label, headerIndex) {
46665 // On the canvas the header width depends on the size of the content
46666 return this.owner.getEstimatedTextWidth(label);
46667 };
46668 CanvasColumnLayoutManager.prototype.getEstimatedBodyCellWidth = function (content) {
46669 return this.owner.getEstimatedTextWidth(content);
46670 };
46671 CanvasColumnLayoutManager.prototype.calculateContextualWidths = function () {
46672 var items = this._getRealizedItems();
46673 var columnWidths = [];
46674 for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
46675 var item = items_1[_i];
46676 if (this.measureEnabled)
46677 item.setAligningContextualWidth(-1);
46678 columnWidths.push(this._calculateSize(item));
46679 }
46680 // Save all column widths. Needed when user turns off auto-sizing for column widths.
46681 this.owner.columnWidthsToPersist = columnWidths;
46682 };
46683 CanvasColumnLayoutManager.prototype.canScroll = function (gridContextualWidth) {
46684 return !powerbi.Double.equalWithPrecision(this.dimension.scrollOffset, 0, DimensionLayoutManager._scrollOffsetPrecision) ||
46685 (((this.getRealizedItemsCount() - this._gridOffset) < this.dimension.getItemsCount()) && this._contextualWidthToFill > 0) ||
46686 powerbi.Double.greaterWithPrecision(gridContextualWidth, this._contextualWidthToFill, DimensionLayoutManager._pixelPrecision);
46687 };
46688 CanvasColumnLayoutManager.prototype._calculateSize = function (item) {
46689 return item.calculateSize();
46690 };
46691 return CanvasColumnLayoutManager;
46692 }(ColumnLayoutManager));
46693 internal.CanvasColumnLayoutManager = CanvasColumnLayoutManager;
46694 var RowLayoutManager = (function (_super) {
46695 __extends(RowLayoutManager, _super);
46696 function RowLayoutManager(owner, grid, realizationManager) {
46697 _super.call(this, owner, grid, realizationManager);
46698 realizationManager.owner = this;
46699 }
46700 Object.defineProperty(RowLayoutManager.prototype, "dimension", {
46701 get: function () {
46702 return this.owner.owner.rowDimension;
46703 },
46704 enumerable: true,
46705 configurable: true
46706 });
46707 RowLayoutManager.prototype.getGridScale = function () {
46708 return this._grid._presenter.getScreenToCssRatioY();
46709 };
46710 Object.defineProperty(RowLayoutManager.prototype, "otherScrollbarContextualWidth", {
46711 get: function () {
46712 if (this.dimension.otherDimension.scrollbar.visible) {
46713 return controls.HTMLElementUtils.getElementHeight(this.dimension.otherDimension.scrollbar.element);
46714 }
46715 return 0;
46716 },
46717 enumerable: true,
46718 configurable: true
46719 });
46720 RowLayoutManager.prototype.startScrollingSession = function () {
46721 _super.prototype.startScrollingSession.call(this);
46722 };
46723 RowLayoutManager.prototype._getRealizedItems = function () {
46724 if (!this._grid.realizedRows) {
46725 this._grid.realizedRows = [];
46726 }
46727 return this._grid.realizedRows;
46728 };
46729 RowLayoutManager.prototype._moveElementsToBottom = function (moveFromIndex, count) {
46730 this._grid.moveRowsToEnd(moveFromIndex, count);
46731 };
46732 RowLayoutManager.prototype._moveElementsToTop = function (moveToIndex, count) {
46733 this._grid.moveRowsToStart(moveToIndex, count);
46734 };
46735 RowLayoutManager.prototype._requiresMeasure = function () {
46736 // if the control is not scrolling in either dimension and the column dimension is not resizing or row dimension is scrolling and reaching the end while scrolling
46737 return (!this.isScrolling() && !this.otherLayoutManager.isScrolling() && !this.otherLayoutManager.isResizing())
46738 || (this.isScrolling() && (this.dimension.getIntegerScrollOffset() + (this.getRealizedItemsCount() - this._gridOffset) >= this.dimension.getItemsCount()));
46739 };
46740 RowLayoutManager.prototype.getGridContextualWidth = function () {
46741 return this._grid.getHeight();
46742 };
46743 RowLayoutManager.prototype.getFirstVisibleRow = function () {
46744 return this._grid.realizedRows[this._gridOffset];
46745 };
46746 RowLayoutManager.prototype._isAutoSized = function () {
46747 return this.owner.owner.autoSizeHeight;
46748 };
46749 RowLayoutManager.prototype.applyScrolling = function () {
46750 var rowOffset = this.dimension.getFractionScrollOffset();
46751 var firstVisibleRowHeight = 0;
46752 if (rowOffset !== 0) {
46753 var firstVisibleRow = this.getFirstVisibleRow();
46754 if (firstVisibleRow) {
46755 firstVisibleRowHeight = firstVisibleRow.getContextualWidth();
46756 this.scroll(firstVisibleRow, firstVisibleRowHeight, rowOffset);
46757 }
46758 }
46759 };
46760 RowLayoutManager.prototype.scroll = function (firstVisibleRow, height, offset) {
46761 this.scrollCells(firstVisibleRow._realizedRowHeaders, height, offset);
46762 this.scrollCells(firstVisibleRow._realizedBodyCells, height, offset);
46763 };
46764 RowLayoutManager.prototype.scrollCells = function (cells, height, offset) {
46765 var length = cells.length;
46766 for (var i = 0; i < length; i++) {
46767 cells[i].scrollVertically(height, offset);
46768 }
46769 };
46770 RowLayoutManager.prototype.getFooterContextualWidth = function () {
46771 if (this.owner.owner.rowDimension.hasFooter()) {
46772 if (this.owner.grid.footerRow) {
46773 return this.owner.grid.footerRow.getContextualWidth();
46774 }
46775 }
46776 return 0;
46777 };
46778 RowLayoutManager.prototype.calculateContextualWidths = function () {
46779 _super.prototype.calculateContextualWidths.call(this);
46780 if (this.fixedSizeEnabled) {
46781 var footerRow = this._grid.footerRow;
46782 if (footerRow) {
46783 this._calculateSize(footerRow);
46784 }
46785 }
46786 };
46787 RowLayoutManager.prototype.fixSizes = function () {
46788 _super.prototype.fixSizes.call(this);
46789 if (this.fixedSizeEnabled) {
46790 if (this._grid.footerRow) {
46791 this._grid.footerRow.fixSize();
46792 }
46793 }
46794 };
46795 /**
46796 * Sends row related data (pixel size, column count, etc) to TablixControl.
46797 */
46798 RowLayoutManager.prototype._sendDimensionsToControl = function () {
46799 var gridContextualWidth = this.getGridContextualWidth();
46800 var widthToFill = this.getActualContextualWidth(gridContextualWidth);
46801 var otherContextualHeight = this.getOtherHierarchyContextualHeight();
46802 var scale = this.getGridScale();
46803 this.owner.owner.updateRowDimensions(otherContextualHeight / scale, (widthToFill - otherContextualHeight) / scale, gridContextualWidth / scale, this.getViewSize(gridContextualWidth), (this._grid.footerRow ? this._grid.footerRow.getContextualWidth() / scale : 0));
46804 };
46805 RowLayoutManager.prototype.getEstimatedHeaderWidth = function (label, headerIndex) {
46806 debug.assertFail("PureVirtualMethod: RowLayoutManager.getEstimatedHeaderWidth");
46807 return -1;
46808 };
46809 return RowLayoutManager;
46810 }(DimensionLayoutManager));
46811 internal.RowLayoutManager = RowLayoutManager;
46812 var DashboardRowLayoutManager = (function (_super) {
46813 __extends(DashboardRowLayoutManager, _super);
46814 function DashboardRowLayoutManager() {
46815 _super.apply(this, arguments);
46816 }
46817 DashboardRowLayoutManager.prototype.getEstimatedHeaderWidth = function (label, headerIndex) {
46818 return this.getHeaderWidth(headerIndex);
46819 };
46820 DashboardRowLayoutManager.prototype.canScroll = function (gridContextualWidth) {
46821 return false;
46822 };
46823 DashboardRowLayoutManager.prototype._calculateSize = function (item) {
46824 return item.calculateSize();
46825 };
46826 DashboardRowLayoutManager.prototype.getHeaderWidth = function (headerIndex) {
46827 // On the dashboard, we need to return 0 if the row header is static
46828 // (a table or a matrix without row groups)
46829 if (headerIndex === 0 && !this.owner.binder.hasRowGroups())
46830 return 0;
46831 // for dashboard layout it does not matter whether we pass an actual text or not
46832 return this.owner.getEstimatedTextWidth(undefined);
46833 };
46834 return DashboardRowLayoutManager;
46835 }(RowLayoutManager));
46836 internal.DashboardRowLayoutManager = DashboardRowLayoutManager;
46837 var CanvasRowLayoutManager = (function (_super) {
46838 __extends(CanvasRowLayoutManager, _super);
46839 function CanvasRowLayoutManager() {
46840 _super.apply(this, arguments);
46841 }
46842 CanvasRowLayoutManager.prototype.getEstimatedHeaderWidth = function (label, headerIndex) {
46843 // On the canvas the header width depends on the size of the content
46844 return this.owner.getEstimatedTextWidth(label);
46845 };
46846 CanvasRowLayoutManager.prototype.canScroll = function (gridContextualWidth) {
46847 return !powerbi.Double.equalWithPrecision(this.dimension.scrollOffset, 0, DimensionLayoutManager._scrollOffsetPrecision) ||
46848 (((this.getRealizedItemsCount() - this._gridOffset) < this.dimension.getItemsCount()) && this._contextualWidthToFill > 0) ||
46849 powerbi.Double.greaterWithPrecision(gridContextualWidth, this._contextualWidthToFill, DimensionLayoutManager._pixelPrecision);
46850 };
46851 CanvasRowLayoutManager.prototype._calculateSize = function (item) {
46852 return item.calculateSize();
46853 };
46854 return CanvasRowLayoutManager;
46855 }(RowLayoutManager));
46856 internal.CanvasRowLayoutManager = CanvasRowLayoutManager;
46857 var TablixLayoutManager = (function () {
46858 function TablixLayoutManager(binder, grid, columnLayoutManager, rowLayoutManager) {
46859 this._allowHeaderResize = true;
46860 this._binder = binder;
46861 this._grid = grid;
46862 this._columnLayoutManager = columnLayoutManager;
46863 this._rowLayoutManager = rowLayoutManager;
46864 this._columnWidthsToPersist = [];
46865 }
46866 TablixLayoutManager.prototype.initialize = function (owner) {
46867 this._owner = owner;
46868 this._container = owner.container;
46869 this._gridHost = owner.contentHost;
46870 this._footersHost = owner.footerHost;
46871 this._grid.initialize(owner, this._gridHost, this._footersHost);
46872 };
46873 Object.defineProperty(TablixLayoutManager.prototype, "owner", {
46874 get: function () {
46875 return this._owner;
46876 },
46877 enumerable: true,
46878 configurable: true
46879 });
46880 Object.defineProperty(TablixLayoutManager.prototype, "binder", {
46881 get: function () {
46882 return this._binder;
46883 },
46884 enumerable: true,
46885 configurable: true
46886 });
46887 Object.defineProperty(TablixLayoutManager.prototype, "columnWidthsToPersist", {
46888 get: function () {
46889 return this._columnWidthsToPersist;
46890 },
46891 set: function (columnWidths) {
46892 this._columnWidthsToPersist = columnWidths;
46893 },
46894 enumerable: true,
46895 configurable: true
46896 });
46897 TablixLayoutManager.prototype.getTablixClassName = function () {
46898 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getTablixClassName");
46899 return null;
46900 };
46901 TablixLayoutManager.prototype.getLayoutKind = function () {
46902 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getLayoutKind");
46903 // TODO ckerer: this method should not be necessary when we are done refactoring!
46904 return null;
46905 };
46906 TablixLayoutManager.prototype.getOrCreateColumnHeader = function (item, items, rowIndex, columnIndex) {
46907 var hierarchyNav = this.owner.hierarchyNavigator;
46908 var row = this._grid.getOrCreateRow(rowIndex);
46909 var column = this._grid.getOrCreateColumn(columnIndex + this._columnLayoutManager._gridOffset);
46910 var isLeaf = hierarchyNav.isLeaf(item);
46911 var cell = row.getOrCreateColumnHeader(column, this._columnLayoutManager.isScrollableHeader(item, items, columnIndex), isLeaf);
46912 var rowIdx = hierarchyNav.getLevel(item);
46913 cell.position.row.index = cell.position.row.indexInSiblings = rowIdx;
46914 cell.position.row.isFirst = rowIdx === 0;
46915 cell.position.row.isLast = isLeaf;
46916 var colIdx = hierarchyNav.getIndex(item);
46917 cell.position.column.index = cell.position.row.indexInSiblings = colIdx;
46918 cell.position.column.isFirst = hierarchyNav.areAllParentsFirst(item, items);
46919 cell.position.column.isLast = hierarchyNav.areAllParentsLast(item, items);
46920 this.enableCellHorizontalResize(isLeaf, cell);
46921 return cell;
46922 };
46923 TablixLayoutManager.prototype.getOrCreateRowHeader = function (item, items, rowIndex, columnIndex) {
46924 var hierarchyNav = this.owner.hierarchyNavigator;
46925 var row = this._grid.getOrCreateRow(rowIndex + this._rowLayoutManager._gridOffset);
46926 var column = this._grid.getOrCreateColumn(columnIndex);
46927 var isLeaf = hierarchyNav.isLeaf(item);
46928 var scrollable = this._rowLayoutManager.isScrollableHeader(item, items, rowIndex);
46929 if (row.getRealizedCellCount() === 0) {
46930 this.alignRowHeaderCells(item, row);
46931 }
46932 var cell = row.getOrCreateRowHeader(column, scrollable, hierarchyNav.isLeaf(item));
46933 var rowIdx = hierarchyNav.getIndex(item);
46934 cell.position.row.index = cell.position.row.indexInSiblings = rowIdx;
46935 cell.position.row.isFirst = hierarchyNav.areAllParentsFirst(item, items);
46936 cell.position.row.isLast = hierarchyNav.areAllParentsLast(item, items);
46937 var colIdx = hierarchyNav.getLevel(item);
46938 cell.position.column.index = cell.position.column.indexInSiblings = colIdx;
46939 cell.position.column.isFirst = colIdx === 0;
46940 cell.position.column.isLast = isLeaf;
46941 cell.enableHorizontalResize(false, this._columnLayoutManager);
46942 return cell;
46943 };
46944 TablixLayoutManager.prototype.getOrCreateCornerCell = function (item, rowLevel, columnLevel) {
46945 var row = this._grid.getOrCreateRow(columnLevel);
46946 var column = this._grid.getOrCreateColumn(rowLevel);
46947 var columnDepth = this._columnLayoutManager.dimension.getDepth();
46948 var isLeaf = columnLevel === (columnDepth - 1);
46949 var cell = row.getOrCreateCornerCell(column);
46950 var rowIdx = columnLevel;
46951 cell.position.row.index = cell.position.row.indexInSiblings = rowIdx;
46952 cell.position.row.isFirst = rowIdx === 0;
46953 cell.position.row.isLast = isLeaf;
46954 var colIdx = rowLevel;
46955 cell.position.column.index = cell.position.column.indexInSiblings = colIdx;
46956 cell.position.column.isFirst = colIdx === 0;
46957 cell.position.column.isLast = colIdx === this._rowLayoutManager.dimension.getDepth() - 1;
46958 this.enableCellHorizontalResize(isLeaf, cell);
46959 return cell;
46960 };
46961 TablixLayoutManager.prototype.getOrCreateBodyCell = function (cellItem, rowItem, rowItems, rowIndex, columnIndex) {
46962 var scrollable;
46963 var row = this._grid.getOrCreateRow(rowIndex + this._rowLayoutManager._gridOffset);
46964 var column = this._grid.getOrCreateColumn(columnIndex + this._columnLayoutManager._gridOffset);
46965 if (row._realizedBodyCells.length === 0 && this._owner.columnDimension.getFractionScrollOffset() !== 0) {
46966 scrollable = true;
46967 }
46968 else {
46969 scrollable = this._rowLayoutManager.isScrollableHeader(rowItem, rowItems, rowIndex);
46970 }
46971 var cell = row.getOrCreateBodyCell(column, scrollable);
46972 cell.position = cellItem.position;
46973 cell.enableHorizontalResize(false, this._columnLayoutManager);
46974 return cell;
46975 };
46976 TablixLayoutManager.prototype.getOrCreateFooterBodyCell = function (cellItem, columnIndex) {
46977 var scrollable;
46978 var row = this._grid.getOrCreateFootersRow();
46979 var column = this._grid.getOrCreateColumn(columnIndex + this._columnLayoutManager._gridOffset);
46980 scrollable = (row._realizedBodyCells.length === 0 && this._owner.columnDimension.getFractionScrollOffset() !== 0);
46981 var cell = row.getOrCreateFooterBodyCell(column, scrollable);
46982 cell.position = cellItem.position;
46983 cell.enableHorizontalResize(false, this._columnLayoutManager);
46984 return cell;
46985 };
46986 TablixLayoutManager.prototype.getOrCreateFooterRowHeader = function (item, items) {
46987 var row = this._grid.getOrCreateFootersRow();
46988 var column = this._grid.getOrCreateColumn(0);
46989 //debug.assert(this.owner.hierarchyNavigator.isLeaf(item), "Leaf item expected");
46990 var cell = row.getOrCreateFooterRowHeader(column);
46991 cell.position = undefined;
46992 cell.enableHorizontalResize(false, this._columnLayoutManager);
46993 return cell;
46994 };
46995 TablixLayoutManager.prototype.getVisibleWidth = function () {
46996 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getVisibleWidth");
46997 return -1;
46998 };
46999 TablixLayoutManager.prototype.getVisibleHeight = function () {
47000 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getVisibleHeight");
47001 return -1;
47002 };
47003 TablixLayoutManager.prototype.updateColumnCount = function (rowDimension, columnDimension) {
47004 debug.assertFail("PureVirtualMethod: TablixLayoutManager.updateColumnCount");
47005 };
47006 TablixLayoutManager.prototype.updateViewport = function (viewport) {
47007 debug.assertFail("PureVirtualMethod: TablixLayoutManager.updateViewport");
47008 };
47009 TablixLayoutManager.prototype.getEstimatedRowHeight = function () {
47010 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getEstimatedRowHeight");
47011 return -1;
47012 };
47013 TablixLayoutManager.prototype.getCellWidth = function (cell) {
47014 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getCellWidth");
47015 return -1;
47016 };
47017 TablixLayoutManager.prototype.getContentWidth = function (cell) {
47018 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getContentWidth");
47019 return -1;
47020 };
47021 TablixLayoutManager.prototype.adjustContentSize = function (hasImage) {
47022 // default implementation has no adjustment
47023 };
47024 /**
47025 * This call makes room for parent header cells where neccessary.
47026 * Since HTML cells that span vertically displace other rows,
47027 * room has to be made for spanning headers that leave an exiting
47028 * row to enter the new row that it starts from and removed when
47029 * returning to an entering row.
47030 */
47031 TablixLayoutManager.prototype.alignRowHeaderCells = function (item, currentRow) {
47032 var index = currentRow.getRowHeaderLeafIndex();
47033 if (index === -1) {
47034 return;
47035 }
47036 var rowDimension = this._owner.rowDimension;
47037 var leaf = rowDimension.getFirstVisibleChildLeaf(item);
47038 if (!this.owner.hierarchyNavigator.headerItemEquals(leaf, currentRow.getAllocatedCellAt(index).item)) {
47039 return;
47040 }
47041 currentRow.moveCellsBy(this.owner.hierarchyNavigator.getLevel(leaf) - this.owner.hierarchyNavigator.getLevel(item) - index);
47042 };
47043 Object.defineProperty(TablixLayoutManager.prototype, "grid", {
47044 get: function () {
47045 return this._grid;
47046 },
47047 enumerable: true,
47048 configurable: true
47049 });
47050 Object.defineProperty(TablixLayoutManager.prototype, "rowLayoutManager", {
47051 get: function () {
47052 return this._rowLayoutManager;
47053 },
47054 enumerable: true,
47055 configurable: true
47056 });
47057 Object.defineProperty(TablixLayoutManager.prototype, "columnLayoutManager", {
47058 get: function () {
47059 return this._columnLayoutManager;
47060 },
47061 enumerable: true,
47062 configurable: true
47063 });
47064 TablixLayoutManager.prototype.showEmptySpaceHeader = function () {
47065 debug.assertFail("PureVirtualMethod: TablixLayoutManager.showEmptySpaceHeader");
47066 return false;
47067 };
47068 TablixLayoutManager.prototype.onStartRenderingSession = function (scrollingDimension, parentElement, clear) {
47069 if (this.showEmptySpaceHeader()) {
47070 var cell = this._grid.emptySpaceHeaderCell;
47071 if (cell) {
47072 this._binder.unbindEmptySpaceHeaderCell(cell);
47073 }
47074 cell = this._grid.emptySpaceFooterCell;
47075 if (cell) {
47076 this._binder.unbindEmptySpaceFooterCell(cell);
47077 }
47078 this._grid.HideEmptySpaceCells();
47079 }
47080 this._scrollingDimension = scrollingDimension;
47081 if (this._scrollingDimension) {
47082 this._scrollingDimension.layoutManager.startScrollingSession();
47083 }
47084 this._rowLayoutManager.onStartRenderingSession();
47085 this._columnLayoutManager.onStartRenderingSession();
47086 this._grid.onStartRenderingSession(clear);
47087 var measureEnabled = this._columnLayoutManager.measureEnabled || this._rowLayoutManager.measureEnabled;
47088 if (measureEnabled)
47089 this.measureSampleText(parentElement);
47090 };
47091 TablixLayoutManager.prototype.onEndRenderingSession = function () {
47092 this._rowLayoutManager.onEndRenderingSession();
47093 this._columnLayoutManager.onEndRenderingSession();
47094 if (this._scrollingDimension) {
47095 this._scrollingDimension.layoutManager.endScrollingSession();
47096 }
47097 this._scrollingDimension = null;
47098 if (this.showEmptySpaceHeader()) {
47099 var emptySpace = this._columnLayoutManager.contextualWidthToFill - this._columnLayoutManager.getGridContextualWidth();
47100 if (emptySpace > 0) {
47101 this._grid.ShowEmptySpaceCells(this._owner.columnDimension.getDepth(), emptySpace);
47102 var cell = this._grid.emptySpaceHeaderCell;
47103 if (cell) {
47104 this._binder.bindEmptySpaceHeaderCell(cell);
47105 }
47106 cell = this._grid.emptySpaceFooterCell;
47107 if (cell) {
47108 this._binder.bindEmptySpaceFooterCell(cell);
47109 }
47110 }
47111 }
47112 };
47113 TablixLayoutManager.prototype.onStartRenderingIteration = function (clear) {
47114 this._rowLayoutManager.onStartRenderingIteration(clear, this.getVisibleHeight());
47115 this._columnLayoutManager.onStartRenderingIteration(clear, this.getVisibleWidth());
47116 this._grid.onStartRenderingIteration();
47117 };
47118 TablixLayoutManager.prototype.onEndRenderingIteration = function () {
47119 this._grid.onEndRenderingIteration();
47120 // ANDREMI: Comment out for static tablix
47121 this._columnLayoutManager.calculateSizes(); // calculate the entire grid first without altering the tree to avoid multiple measure pass invoking
47122 this._rowLayoutManager.calculateSizes();
47123 this._columnLayoutManager.fixSizes(); // now assign the sizes
47124 this._rowLayoutManager.fixSizes();
47125 this._columnLayoutManager.updateItemToResizeState(this._grid.realizedColumns); // if we are in a middle of a resize, the column to resize might have been swaped during the render, restore its resize state
47126 this._columnLayoutManager.applyScrolling();
47127 this._rowLayoutManager.applyScrolling();
47128 this._columnLayoutManager.onEndRenderingIteration();
47129 this._rowLayoutManager.onEndRenderingIteration();
47130 return this._columnLayoutManager.done && this._rowLayoutManager.done;
47131 };
47132 TablixLayoutManager.prototype.onCornerCellRealized = function (item, cell) {
47133 var columnLeaf = this.owner.hierarchyNavigator.isColumnHierarchyLeaf(item);
47134 var rowLeaf = this.owner.hierarchyNavigator.isRowHierarchyLeaf(item);
47135 if (columnLeaf)
47136 cell._column.OnLeafRealized(this._owner.hierarchyNavigator);
47137 this._columnLayoutManager.onCornerCellRealized(item, cell, columnLeaf);
47138 this._rowLayoutManager.onCornerCellRealized(item, cell, rowLeaf);
47139 };
47140 TablixLayoutManager.prototype.onRowHeaderRealized = function (item, cell) {
47141 var hierarchyNavigator = this._owner.hierarchyNavigator;
47142 var leaf = hierarchyNavigator.isLeaf(item);
47143 var tablixCell = cell;
47144 if (tablixCell.colSpan > 1)
47145 tablixCell.setContainerWidth(-1);
47146 this._rowLayoutManager.onHeaderRealized(item, cell, leaf);
47147 };
47148 TablixLayoutManager.prototype.onRowHeaderFooterRealized = function (item, cell) {
47149 };
47150 TablixLayoutManager.prototype.onColumnHeaderRealized = function (item, cell) {
47151 var hierarchyNavigator = this._owner.hierarchyNavigator;
47152 var leaf = hierarchyNavigator.isLeaf(item);
47153 if (leaf)
47154 cell._column.OnLeafRealized(this._owner.hierarchyNavigator);
47155 this._columnLayoutManager.onHeaderRealized(item, cell, leaf);
47156 };
47157 TablixLayoutManager.prototype.onBodyCellRealized = function (item, cell) {
47158 };
47159 TablixLayoutManager.prototype.onBodyCellFooterRealized = function (item, cell) {
47160 };
47161 TablixLayoutManager.prototype.setAllowHeaderResize = function (value) {
47162 this._allowHeaderResize = value;
47163 };
47164 TablixLayoutManager.prototype.enableCellHorizontalResize = function (isLeaf, cell) {
47165 var enableCellHorizontalResize = isLeaf && this._allowHeaderResize;
47166 cell.enableHorizontalResize(enableCellHorizontalResize, this._columnLayoutManager);
47167 };
47168 TablixLayoutManager.prototype.getEstimatedTextWidth = function (label) {
47169 debug.assertFail("PureVirtualMethod: TablixLayoutManager.getEstimatedTextWidth");
47170 return -1;
47171 };
47172 TablixLayoutManager.prototype.measureSampleText = function (parentElement) {
47173 debug.assertFail("PureVirtualMethod: TablixLayoutManager.measureSampleText");
47174 };
47175 return TablixLayoutManager;
47176 }());
47177 internal.TablixLayoutManager = TablixLayoutManager;
47178 var DashboardTablixLayoutManager = (function (_super) {
47179 __extends(DashboardTablixLayoutManager, _super);
47180 function DashboardTablixLayoutManager(binder, sizeComputationManager, grid, rowRealizationManager, columnRealizationManager) {
47181 var dashboardColumnLayoutManager = new DashboardColumnLayoutManager(null, grid, columnRealizationManager);
47182 var dashboardRowLayoutManager = new DashboardRowLayoutManager(null, grid, rowRealizationManager);
47183 _super.call(this, binder, grid, dashboardColumnLayoutManager, dashboardRowLayoutManager);
47184 dashboardColumnLayoutManager.owner = this;
47185 dashboardRowLayoutManager.owner = this;
47186 this._sizeComputationManager = sizeComputationManager;
47187 }
47188 DashboardTablixLayoutManager.createLayoutManager = function (binder) {
47189 // computed sizes are shared between layout manager and grid presenter
47190 var sizeComputationManager = new SizeComputationManager();
47191 return new DashboardTablixLayoutManager(binder, sizeComputationManager, new internal.TablixGrid(new internal.DashboardTablixGridPresenter(sizeComputationManager)), new internal.RowRealizationManager(binder), new internal.ColumnRealizationManager(binder));
47192 };
47193 DashboardTablixLayoutManager.prototype.getTablixClassName = function () {
47194 return "tablixDashboard";
47195 };
47196 DashboardTablixLayoutManager.prototype.getLayoutKind = function () {
47197 return 1 /* DashboardTile */;
47198 };
47199 DashboardTablixLayoutManager.prototype.showEmptySpaceHeader = function () {
47200 return false;
47201 };
47202 DashboardTablixLayoutManager.prototype.measureSampleText = function (parentElement) {
47203 var textProperties = powerbi.TextMeasurementService.getSvgMeasurementProperties(parentElement);
47204 this._characterHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(textProperties);
47205 this._sizeComputationManager.updateRowHeight(this._characterHeight);
47206 var actualTextSize = PixelConverter.toPoint(parseFloat(textProperties.fontSize));
47207 var scalingFactor = actualTextSize / controls.TablixDefaultTextSize;
47208 this._sizeComputationManager.updateScalingFactor(powerbi.Double.toIncrement(scalingFactor, 0.05));
47209 };
47210 DashboardTablixLayoutManager.prototype.getVisibleWidth = function () {
47211 return this._sizeComputationManager.visibleWidth;
47212 };
47213 DashboardTablixLayoutManager.prototype.getVisibleHeight = function () {
47214 return this._sizeComputationManager.visibleHeight;
47215 };
47216 DashboardTablixLayoutManager.prototype.getCellWidth = function (cell) {
47217 return this._sizeComputationManager.cellWidth;
47218 };
47219 DashboardTablixLayoutManager.prototype.getContentWidth = function (cell) {
47220 return this._sizeComputationManager.contentWidth;
47221 };
47222 DashboardTablixLayoutManager.prototype.getEstimatedTextWidth = function (label) {
47223 // On the dashboard it does not matter what text we render,
47224 // we always use the same content width
47225 return this._sizeComputationManager.contentWidth;
47226 };
47227 DashboardTablixLayoutManager.prototype.adjustContentSize = function (hasImage) {
47228 this._sizeComputationManager.hasImageContent = hasImage;
47229 };
47230 DashboardTablixLayoutManager.prototype.updateColumnCount = function (rowDimension, columnDimension) {
47231 // The total number of columns is the number (depth) of row groups + the number of (leaf) column group instances
47232 var rowDimensionDepth = rowDimension ? rowDimension.getDepth() : 0;
47233 var columnInstances = columnDimension ? columnDimension.getItemsCount() : 0;
47234 var totalColumnCount = rowDimensionDepth + columnInstances;
47235 // Adjust the column count by the static row header (if any)
47236 if (!this.binder.hasRowGroups())
47237 totalColumnCount--;
47238 this._sizeComputationManager.updateColumnCount(totalColumnCount);
47239 };
47240 DashboardTablixLayoutManager.prototype.updateViewport = function (viewport) {
47241 this._sizeComputationManager.updateViewport(viewport);
47242 };
47243 DashboardTablixLayoutManager.prototype.getEstimatedRowHeight = function () {
47244 return this._characterHeight;
47245 };
47246 return DashboardTablixLayoutManager;
47247 }(TablixLayoutManager));
47248 internal.DashboardTablixLayoutManager = DashboardTablixLayoutManager;
47249 var CanvasTablixLayoutManager = (function (_super) {
47250 __extends(CanvasTablixLayoutManager, _super);
47251 function CanvasTablixLayoutManager(binder, grid, rowRealizationManager, columnRealizationManager) {
47252 var canvasColumnLayoutManager = new CanvasColumnLayoutManager(null, grid, columnRealizationManager);
47253 var canvasRowLayoutManager = new CanvasRowLayoutManager(null, grid, rowRealizationManager);
47254 _super.call(this, binder, grid, canvasColumnLayoutManager, canvasRowLayoutManager);
47255 canvasColumnLayoutManager.owner = this;
47256 canvasRowLayoutManager.owner = this;
47257 }
47258 CanvasTablixLayoutManager.createLayoutManager = function (binder, columnWidthManager) {
47259 return new CanvasTablixLayoutManager(binder, new internal.TablixGrid(new controls.internal.CanvasTablixGridPresenter(columnWidthManager)), new internal.RowRealizationManager(binder), new internal.ColumnRealizationManager(binder));
47260 };
47261 CanvasTablixLayoutManager.prototype.getTablixClassName = function () {
47262 return "tablixCanvas";
47263 };
47264 CanvasTablixLayoutManager.prototype.getLayoutKind = function () {
47265 return 0 /* Canvas */;
47266 };
47267 CanvasTablixLayoutManager.prototype.measureSampleText = function (parentElement) {
47268 // TODO: Use TextMeasurementService once the DOM methods are fixed (they are not working right now)
47269 var textDiv = controls.internal.TablixUtils.createDiv();
47270 textDiv.style.cssFloat = 'left';
47271 textDiv.style.whiteSpace = 'nowrap';
47272 textDiv.style.overflow = 'hidden';
47273 textDiv.style.lineHeight = 'normal';
47274 parentElement.appendChild(textDiv);
47275 var textNode = document.createTextNode("a");
47276 textDiv.appendChild(textNode);
47277 this.characterWidth = controls.HTMLElementUtils.getElementWidth(textDiv);
47278 this.characterHeight = controls.HTMLElementUtils.getElementHeight(textDiv);
47279 textDiv.removeChild(textNode);
47280 parentElement.removeChild(textDiv);
47281 };
47282 CanvasTablixLayoutManager.prototype.showEmptySpaceHeader = function () {
47283 return !this._columnLayoutManager.fillProportionally;
47284 };
47285 CanvasTablixLayoutManager.prototype.getVisibleWidth = function () {
47286 if (this._columnLayoutManager.measureEnabled) {
47287 if (this._owner.autoSizeWidth && this._owner.maxWidth) {
47288 return this._owner.maxWidth;
47289 }
47290 else {
47291 return controls.HTMLElementUtils.getElementWidth(this._container);
47292 }
47293 }
47294 return -1;
47295 };
47296 CanvasTablixLayoutManager.prototype.getVisibleHeight = function () {
47297 if (this._rowLayoutManager.measureEnabled) {
47298 if (this._owner.autoSizeHeight && this._owner.maxHeight) {
47299 return this._owner.maxHeight;
47300 }
47301 else {
47302 return controls.HTMLElementUtils.getElementHeight(this._container);
47303 }
47304 }
47305 return -1;
47306 };
47307 CanvasTablixLayoutManager.prototype.getCellWidth = function (cell) {
47308 return controls.HTMLElementUtils.getElementWidth(cell._presenter.tableCell);
47309 };
47310 CanvasTablixLayoutManager.prototype.getContentWidth = function (cell) {
47311 return controls.HTMLElementUtils.getElementWidth(cell._presenter.contentElement);
47312 };
47313 CanvasTablixLayoutManager.prototype.getEstimatedTextWidth = function (text) {
47314 return text ? text.length * this.characterWidth : 0;
47315 };
47316 CanvasTablixLayoutManager.prototype.updateColumnCount = function (rowDimension, columnDimension) {
47317 // We currently only need to update model information when using dashboard layouts
47318 };
47319 CanvasTablixLayoutManager.prototype.updateViewport = function (viewport) {
47320 // We currently only need to update model information when using dashboard layouts
47321 };
47322 CanvasTablixLayoutManager.prototype.getEstimatedRowHeight = function () {
47323 return this.characterHeight;
47324 };
47325 return CanvasTablixLayoutManager;
47326 }(TablixLayoutManager));
47327 internal.CanvasTablixLayoutManager = CanvasTablixLayoutManager;
47328 })(internal = controls.internal || (controls.internal = {}));
47329 })(controls = visuals.controls || (visuals.controls = {}));
47330 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
47331})(powerbi || (powerbi = {}));
47332/*
47333 * Power BI Visualizations
47334 *
47335 * Copyright (c) Microsoft Corporation
47336 * All rights reserved.
47337 * MIT License
47338 *
47339 * Permission is hereby granted, free of charge, to any person obtaining a copy
47340 * of this software and associated documentation files (the ""Software""), to deal
47341 * in the Software without restriction, including without limitation the rights
47342 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
47343 * copies of the Software, and to permit persons to whom the Software is
47344 * furnished to do so, subject to the following conditions:
47345 *
47346 * The above copyright notice and this permission notice shall be included in
47347 * all copies or substantial portions of the Software.
47348 *
47349 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47350 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47351 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47352 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47353 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47354 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47355 * THE SOFTWARE.
47356 */
47357var powerbi;
47358(function (powerbi) {
47359 var visuals;
47360 (function (visuals) {
47361 var controls;
47362 (function (controls) {
47363 var HTMLElementUtils;
47364 (function (HTMLElementUtils) {
47365 function clearChildren(element) {
47366 if (!element) {
47367 return;
47368 }
47369 while (element.hasChildNodes()) {
47370 element.removeChild(element.firstChild);
47371 }
47372 }
47373 HTMLElementUtils.clearChildren = clearChildren;
47374 function setElementTop(element, top) {
47375 element.style.top = top + "px";
47376 }
47377 HTMLElementUtils.setElementTop = setElementTop;
47378 function setElementLeft(element, left) {
47379 element.style.left = left + "px";
47380 }
47381 HTMLElementUtils.setElementLeft = setElementLeft;
47382 function setElementHeight(element, height) {
47383 if (HTMLElementUtils.isAutoSize(height))
47384 element.style.height = "";
47385 else
47386 element.style.height = height + "px";
47387 }
47388 HTMLElementUtils.setElementHeight = setElementHeight;
47389 function setElementWidth(element, width) {
47390 if (HTMLElementUtils.isAutoSize(width))
47391 element.style.width = "";
47392 else
47393 element.style.width = width + "px";
47394 }
47395 HTMLElementUtils.setElementWidth = setElementWidth;
47396 function getElementWidth(element) {
47397 return element.offsetWidth;
47398 }
47399 HTMLElementUtils.getElementWidth = getElementWidth;
47400 function getElementHeight(element) {
47401 return element.offsetHeight;
47402 }
47403 HTMLElementUtils.getElementHeight = getElementHeight;
47404 function isAutoSize(size) {
47405 return size === -1;
47406 }
47407 HTMLElementUtils.isAutoSize = isAutoSize;
47408 function getAccumulatedScale(element) {
47409 var scale = 1;
47410 while (element) {
47411 scale *= HTMLElementUtils.getScale(element);
47412 element = element.parentElement;
47413 }
47414 return scale;
47415 }
47416 HTMLElementUtils.getAccumulatedScale = getAccumulatedScale;
47417 /**
47418 * Get scale of element, return 1 when not scaled.
47419 */
47420 function getScale(element) {
47421 element = $(element);
47422 var str = element.css('-webkit-transform') ||
47423 element.css('-moz-transform') ||
47424 element.css('-ms-transform') ||
47425 element.css('-o-transform') ||
47426 element.css('transform');
47427 return (str && (str.match(/\d*\.\d*/) && Number(str.match(/\d*\.\d*/)[0]) ||
47428 str.match(/\d+/) && Number(str.match(/\d+/)[0]))) || 1;
47429 }
47430 HTMLElementUtils.getScale = getScale;
47431 })(HTMLElementUtils = controls.HTMLElementUtils || (controls.HTMLElementUtils = {}));
47432 })(controls = visuals.controls || (visuals.controls = {}));
47433 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
47434})(powerbi || (powerbi = {}));
47435var powerbi;
47436(function (powerbi) {
47437 var visuals;
47438 (function (visuals) {
47439 var controls;
47440 (function (controls) {
47441 var internal;
47442 (function (internal) {
47443 var DomFactory = InJs.DomFactory;
47444 var DataViewObjectDefinitions = powerbi.data.DataViewObjectDefinitions;
47445 var DataViewRoleWildCard = powerbi.data.DataViewRoleWildcard;
47446 var TablixObjects;
47447 (function (TablixObjects) {
47448 TablixObjects.ObjectGeneral = "general";
47449 TablixObjects.ObjectGrid = "grid";
47450 TablixObjects.ObjectColumnHeaders = "columnHeaders";
47451 TablixObjects.ObjectRowHeaders = "rowHeaders";
47452 TablixObjects.ObjectValues = "values";
47453 TablixObjects.ObjectTotal = "total";
47454 TablixObjects.ObjectSubTotals = "subTotals";
47455 /**
47456 * Represents a DataViewObjects property related to the Tablix
47457 */
47458 var TablixProperty = (function () {
47459 /**
47460 * Creates a new TablixProperty
47461 * @param {string} objectName Object Name
47462 * @param {string} propertyName Property Name
47463 * @param {any} defaultValue Default value of the Property
47464 * @param {ObjectValueGetterFunction} getterFuntion Function used to get the Property value from the Objects
47465 */
47466 function TablixProperty(objectName, propertyName, defaultValue, getterFuntion) {
47467 this.objectName = objectName;
47468 this.propertyName = propertyName;
47469 this.defaultValue = defaultValue;
47470 this.getterFuntion = getterFuntion;
47471 }
47472 /**
47473 * Gets the PropertyIdentifier for the Property
47474 * @returns PropertyIdentifier for the Property
47475 */
47476 TablixProperty.prototype.getPropertyID = function () {
47477 return { objectName: this.objectName, propertyName: this.propertyName };
47478 };
47479 /**
47480 * Gets the value of the Property from the Objects
47481 * @param {DataViewObjects} objects DataView Objects to get the value from
47482 * @param {boolean} useDefault True to fall back to the Default value if the Property is missing from the objects. False to return undefined
47483 * @returns Value of the property
47484 */
47485 TablixProperty.prototype.getValue = function (objects) {
47486 // We use this when we intend to have undefined for missing properties. Useful in letting styles fallback to CSS if not defined
47487 return this.getterFuntion(objects, this.getPropertyID(), this.defaultValue);
47488 };
47489 return TablixProperty;
47490 }());
47491 TablixObjects.TablixProperty = TablixProperty;
47492 // Per Column
47493 TablixObjects.PropColumnFormatString = new TablixProperty(TablixObjects.ObjectGeneral, 'formatString', undefined, powerbi.DataViewObjects.getValue);
47494 // General
47495 TablixObjects.PropGeneralAutoSizeColumns = new TablixProperty(TablixObjects.ObjectGeneral, 'autoSizeColumnWidth', true, powerbi.DataViewObjects.getValue);
47496 TablixObjects.PropGeneralTextSize = new TablixProperty(TablixObjects.ObjectGeneral, 'textSize', 8, powerbi.DataViewObjects.getValue);
47497 TablixObjects.PropGeneralTableTotals = new TablixProperty(TablixObjects.ObjectGeneral, 'totals', true, powerbi.DataViewObjects.getValue);
47498 TablixObjects.PropGeneralMatrixRowSubtotals = new TablixProperty(TablixObjects.ObjectGeneral, 'rowSubtotals', true, powerbi.DataViewObjects.getValue);
47499 TablixObjects.PropGeneralMatrixColumnSubtotals = new TablixProperty(TablixObjects.ObjectGeneral, 'columnSubtotals', true, powerbi.DataViewObjects.getValue);
47500 //Grid
47501 TablixObjects.PropGridVertical = new TablixProperty(TablixObjects.ObjectGrid, 'gridVertical', false, powerbi.DataViewObjects.getValue);
47502 TablixObjects.PropGridVerticalColor = new TablixProperty(TablixObjects.ObjectGrid, 'gridVerticalColor', "#E8E8E8", powerbi.DataViewObjects.getFillColor);
47503 TablixObjects.PropGridVerticalWeight = new TablixProperty(TablixObjects.ObjectGrid, 'gridVerticalWeight', 1, powerbi.DataViewObjects.getValue);
47504 TablixObjects.PropGridHorizontalTable = new TablixProperty(TablixObjects.ObjectGrid, 'gridHorizontal', true, powerbi.DataViewObjects.getValue);
47505 TablixObjects.PropGridHorizontalMatrix = new TablixProperty(TablixObjects.ObjectGrid, 'gridHorizontal', false, powerbi.DataViewObjects.getValue);
47506 TablixObjects.PropGridHorizontalColor = new TablixProperty(TablixObjects.ObjectGrid, 'gridHorizontalColor', "#E8E8E8", powerbi.DataViewObjects.getFillColor);
47507 TablixObjects.PropGridHorizontalWeight = new TablixProperty(TablixObjects.ObjectGrid, 'gridHorizontalWeight', 1, powerbi.DataViewObjects.getValue);
47508 TablixObjects.PropGridRowPadding = new TablixProperty(TablixObjects.ObjectGrid, 'rowPadding', 0, powerbi.DataViewObjects.getValue);
47509 TablixObjects.PropGridOutlineColor = new TablixProperty(TablixObjects.ObjectGrid, 'outlineColor', "#CCC", powerbi.DataViewObjects.getFillColor);
47510 TablixObjects.PropGridOutlineWeight = new TablixProperty(TablixObjects.ObjectGrid, 'outlineWeight', 1, powerbi.DataViewObjects.getValue);
47511 TablixObjects.PropGridImageHeight = new TablixProperty(TablixObjects.ObjectGrid, 'imageHeight', 75, powerbi.DataViewObjects.getValue);
47512 // Column Headers
47513 TablixObjects.PropColumnsFontColor = new TablixProperty(TablixObjects.ObjectColumnHeaders, 'fontColor', "#666", powerbi.DataViewObjects.getFillColor);
47514 TablixObjects.PropColumnsBackColor = new TablixProperty(TablixObjects.ObjectColumnHeaders, 'backColor', undefined, powerbi.DataViewObjects.getFillColor);
47515 TablixObjects.PropColumnsOutline = new TablixProperty(TablixObjects.ObjectColumnHeaders, 'outline', "BottomOnly", powerbi.DataViewObjects.getValue);
47516 // Row Headers
47517 TablixObjects.PropRowsFontColor = new TablixProperty(TablixObjects.ObjectRowHeaders, 'fontColor', "#666", powerbi.DataViewObjects.getFillColor);
47518 TablixObjects.PropRowsBackColor = new TablixProperty(TablixObjects.ObjectRowHeaders, 'backColor', undefined, powerbi.DataViewObjects.getFillColor);
47519 TablixObjects.PropRowsOutline = new TablixProperty(TablixObjects.ObjectRowHeaders, 'outline', "RightOnly", powerbi.DataViewObjects.getValue);
47520 // Values
47521 TablixObjects.PropValuesBackColor = new TablixProperty(TablixObjects.ObjectValues, 'backColor', undefined, powerbi.DataViewObjects.getFillColor);
47522 TablixObjects.PropValuesFontColorPrimary = new TablixProperty(TablixObjects.ObjectValues, 'fontColorPrimary', "#333", powerbi.DataViewObjects.getFillColor);
47523 TablixObjects.PropValuesBackColorPrimary = new TablixProperty(TablixObjects.ObjectValues, 'backColorPrimary', undefined, powerbi.DataViewObjects.getFillColor);
47524 TablixObjects.PropValuesFontColorSecondary = new TablixProperty(TablixObjects.ObjectValues, 'fontColorSecondary', "#333", powerbi.DataViewObjects.getFillColor);
47525 TablixObjects.PropValuesBackColorSecondary = new TablixProperty(TablixObjects.ObjectValues, 'backColorSecondary', undefined, powerbi.DataViewObjects.getFillColor);
47526 TablixObjects.PropValuesOutline = new TablixProperty(TablixObjects.ObjectValues, 'outline', "None", powerbi.DataViewObjects.getValue);
47527 TablixObjects.PropValuesUrlIconProp = new TablixProperty(TablixObjects.ObjectValues, 'urlIcon', false, powerbi.DataViewObjects.getValue);
47528 // Total
47529 TablixObjects.PropTotalFontColor = new TablixProperty(TablixObjects.ObjectTotal, 'fontColor', "#333", powerbi.DataViewObjects.getFillColor);
47530 TablixObjects.PropTotalBackColor = new TablixProperty(TablixObjects.ObjectTotal, 'backColor', undefined, powerbi.DataViewObjects.getFillColor);
47531 TablixObjects.PropTotalOutline = new TablixProperty(TablixObjects.ObjectTotal, 'outline', "TopOnly", powerbi.DataViewObjects.getValue);
47532 // SubTotals
47533 TablixObjects.PropSubTotalsFontColor = new TablixProperty(TablixObjects.ObjectSubTotals, 'fontColor', "#333", powerbi.DataViewObjects.getFillColor);
47534 TablixObjects.PropSubTotalsBackColor = new TablixProperty(TablixObjects.ObjectSubTotals, 'backColor', undefined, powerbi.DataViewObjects.getFillColor);
47535 TablixObjects.PropSubTotalsOutline = new TablixProperty(TablixObjects.ObjectSubTotals, 'outline', "TopOnly", powerbi.DataViewObjects.getValue);
47536 /**
47537 * Get the DataViewObject from the DataView
47538 * @param {DataView} dataview The DataView
47539 * @returns DataViewObjects (dataView.metadata.objects)
47540 */
47541 function getMetadadataObjects(dataview) {
47542 if (dataview && dataview.metadata)
47543 return dataview.metadata.objects;
47544 return null;
47545 }
47546 TablixObjects.getMetadadataObjects = getMetadadataObjects;
47547 function enumerateObjectRepetition(enumeration, dataView, tablixType) {
47548 debug.assertValue(enumeration, 'enumeration should be defined');
47549 debug.assertValue(dataView, "dataView can't be undefined");
47550 // We currently only support Table
47551 if (tablixType !== controls.TablixType.Table)
47552 return;
47553 var columns = getTableColumnMetadata(dataView);
47554 for (var _i = 0, columns_1 = columns; _i < columns_1.length; _i++) {
47555 var column = columns_1[_i];
47556 var repetition = {
47557 selector: {
47558 data: [DataViewRoleWildCard.fromRoles(['Values'])],
47559 metadata: column.queryName,
47560 },
47561 objects: (_a = {},
47562 _a[TablixObjects.ObjectValues] = {
47563 formattingProperties: [TablixObjects.PropValuesBackColor.propertyName]
47564 },
47565 _a
47566 )
47567 };
47568 enumeration.push(repetition);
47569 }
47570 var _a;
47571 }
47572 TablixObjects.enumerateObjectRepetition = enumerateObjectRepetition;
47573 function enumerateObjectInstances(options, enumeration, dataView, tablixType) {
47574 debug.assertValue(dataView, "dataView can't be undefined");
47575 var objects = getMetadadataObjects(dataView);
47576 var totalsShown = true;
47577 if (tablixType === controls.TablixType.Table) {
47578 totalsShown = shouldShowTableTotalsOption(dataView) && shouldShowTableTotals(objects);
47579 }
47580 else {
47581 totalsShown =
47582 (shouldShowColumnSubtotalsOption(dataView) && shouldShowColumnSubtotals(objects)) ||
47583 (shouldShowRowSubtotalsOption(dataView) && shouldShowRowSubtotals(objects));
47584 }
47585 switch (options.objectName) {
47586 case TablixObjects.ObjectGeneral:
47587 enumerateGeneralOptions(enumeration, objects, tablixType, dataView);
47588 break;
47589 case TablixObjects.ObjectGrid:
47590 enumerateGridOptions(enumeration, objects, tablixType);
47591 break;
47592 case TablixObjects.ObjectColumnHeaders:
47593 enumerateColumnHeadersOptions(enumeration, objects);
47594 break;
47595 case TablixObjects.ObjectRowHeaders:
47596 enumerateRowHeadersOptions(enumeration, objects);
47597 break;
47598 case TablixObjects.ObjectValues:
47599 enumerateValuesOptions(enumeration, objects, tablixType);
47600 break;
47601 case TablixObjects.ObjectTotal:
47602 if (totalsShown)
47603 enumerateTotalOptions(enumeration, objects);
47604 break;
47605 case TablixObjects.ObjectSubTotals:
47606 if (totalsShown)
47607 enumerateSubTotalsOptions(enumeration, objects);
47608 break;
47609 default:
47610 break;
47611 }
47612 }
47613 TablixObjects.enumerateObjectInstances = enumerateObjectInstances;
47614 function enumerateGeneralOptions(enumeration, objects, tablixType, dataView) {
47615 var visualObjectinstance = {
47616 selector: null,
47617 objectName: TablixObjects.ObjectGeneral,
47618 properties: {
47619 autoSizeColumnWidth: TablixObjects.PropGeneralAutoSizeColumns.getValue(objects),
47620 textSize: TablixObjects.PropGeneralTextSize.getValue(objects),
47621 }
47622 };
47623 var properties = visualObjectinstance.properties;
47624 // Total and SubTotals
47625 switch (tablixType) {
47626 case controls.TablixType.Table:
47627 if (shouldShowTableTotalsOption(dataView))
47628 properties[TablixObjects.PropGeneralTableTotals.propertyName] = shouldShowTableTotals(objects);
47629 break;
47630 case controls.TablixType.Matrix:
47631 if (shouldShowRowSubtotalsOption(dataView))
47632 properties[TablixObjects.PropGeneralMatrixRowSubtotals.propertyName] = shouldShowRowSubtotals(objects);
47633 if (shouldShowColumnSubtotalsOption(dataView))
47634 properties[TablixObjects.PropGeneralMatrixColumnSubtotals.propertyName] = shouldShowColumnSubtotals(objects);
47635 break;
47636 }
47637 enumeration.pushInstance(visualObjectinstance);
47638 }
47639 TablixObjects.enumerateGeneralOptions = enumerateGeneralOptions;
47640 function enumerateGridOptions(enumeration, objects, tablixType) {
47641 var visualObjectinstance = {
47642 selector: null,
47643 objectName: TablixObjects.ObjectGeneral,
47644 properties: {}
47645 };
47646 var properties = visualObjectinstance.properties;
47647 // Vertical Grid
47648 var verticalGridEnabled = TablixObjects.PropGridVertical.getValue(objects);
47649 properties[TablixObjects.PropGridVertical.propertyName] = verticalGridEnabled;
47650 if (verticalGridEnabled) {
47651 properties[TablixObjects.PropGridVerticalColor.propertyName] = TablixObjects.PropGridVerticalColor.getValue(objects);
47652 properties[TablixObjects.PropGridVerticalWeight.propertyName] = TablixObjects.PropGridVerticalWeight.getValue(objects);
47653 }
47654 // Horizontal Grid
47655 var horizontalGridEnabled = (tablixType === controls.TablixType.Table ? TablixObjects.PropGridHorizontalTable : TablixObjects.PropGridHorizontalMatrix).getValue(objects);
47656 properties[(tablixType === controls.TablixType.Table ? TablixObjects.PropGridHorizontalTable : TablixObjects.PropGridHorizontalMatrix).propertyName] = horizontalGridEnabled;
47657 if (horizontalGridEnabled) {
47658 properties[TablixObjects.PropGridHorizontalColor.propertyName] = TablixObjects.PropGridHorizontalColor.getValue(objects);
47659 properties[TablixObjects.PropGridHorizontalWeight.propertyName] = TablixObjects.PropGridHorizontalWeight.getValue(objects);
47660 }
47661 // Row Padding
47662 properties[TablixObjects.PropGridRowPadding.propertyName] = TablixObjects.PropGridRowPadding.getValue(objects);
47663 // Outline
47664 properties[TablixObjects.PropGridOutlineColor.propertyName] = TablixObjects.PropGridOutlineColor.getValue(objects);
47665 properties[TablixObjects.PropGridOutlineWeight.propertyName] = TablixObjects.PropGridOutlineWeight.getValue(objects);
47666 // Image Height
47667 properties[TablixObjects.PropGridImageHeight.propertyName] = TablixObjects.PropGridImageHeight.getValue(objects);
47668 enumeration.pushInstance(visualObjectinstance);
47669 }
47670 TablixObjects.enumerateGridOptions = enumerateGridOptions;
47671 function enumerateColumnHeadersOptions(enumeration, objects) {
47672 enumeration.pushInstance({
47673 selector: null,
47674 objectName: TablixObjects.ObjectColumnHeaders,
47675 properties: {
47676 fontColor: TablixObjects.PropColumnsFontColor.getValue(objects),
47677 backColor: TablixObjects.PropColumnsBackColor.getValue(objects),
47678 outline: TablixObjects.PropColumnsOutline.getValue(objects),
47679 }
47680 });
47681 }
47682 TablixObjects.enumerateColumnHeadersOptions = enumerateColumnHeadersOptions;
47683 function enumerateRowHeadersOptions(enumeration, objects) {
47684 enumeration.pushInstance({
47685 selector: null,
47686 objectName: TablixObjects.ObjectRowHeaders,
47687 properties: {
47688 fontColor: TablixObjects.PropRowsFontColor.getValue(objects),
47689 backColor: TablixObjects.PropRowsBackColor.getValue(objects),
47690 outline: TablixObjects.PropRowsOutline.getValue(objects),
47691 }
47692 });
47693 }
47694 TablixObjects.enumerateRowHeadersOptions = enumerateRowHeadersOptions;
47695 function enumerateValuesOptions(enumeration, objects, tablixType) {
47696 var instance = {
47697 selector: null,
47698 objectName: TablixObjects.ObjectValues,
47699 properties: {
47700 fontColorPrimary: TablixObjects.PropValuesFontColorPrimary.getValue(objects),
47701 backColorPrimary: TablixObjects.PropValuesBackColorPrimary.getValue(objects),
47702 fontColorSecondary: TablixObjects.PropValuesFontColorSecondary.getValue(objects),
47703 backColorSecondary: TablixObjects.PropValuesBackColorSecondary.getValue(objects),
47704 outline: TablixObjects.PropValuesOutline.getValue(objects),
47705 }
47706 };
47707 if (tablixType === controls.TablixType.Table)
47708 instance.properties[TablixObjects.PropValuesUrlIconProp.propertyName] = TablixObjects.PropValuesUrlIconProp.getValue(objects);
47709 enumeration.pushInstance(instance);
47710 }
47711 TablixObjects.enumerateValuesOptions = enumerateValuesOptions;
47712 function enumerateTotalOptions(enumeration, objects) {
47713 enumeration.pushInstance({
47714 selector: null,
47715 objectName: TablixObjects.ObjectTotal,
47716 properties: {
47717 fontColor: TablixObjects.PropTotalFontColor.getValue(objects),
47718 backColor: TablixObjects.PropTotalBackColor.getValue(objects),
47719 outline: TablixObjects.PropTotalOutline.getValue(objects),
47720 }
47721 });
47722 }
47723 TablixObjects.enumerateTotalOptions = enumerateTotalOptions;
47724 function enumerateSubTotalsOptions(enumeration, objects) {
47725 enumeration.pushInstance({
47726 selector: null,
47727 objectName: TablixObjects.ObjectSubTotals,
47728 properties: {
47729 fontColor: TablixObjects.PropSubTotalsFontColor.getValue(objects),
47730 backColor: TablixObjects.PropSubTotalsBackColor.getValue(objects),
47731 }
47732 });
47733 }
47734 TablixObjects.enumerateSubTotalsOptions = enumerateSubTotalsOptions;
47735 function getTableObjects(dataView) {
47736 var objects = getMetadadataObjects(dataView);
47737 var formattingProperties = {
47738 general: {
47739 autoSizeColumnWidth: TablixObjects.PropGeneralAutoSizeColumns.getValue(objects),
47740 textSize: TablixObjects.PropGeneralTextSize.getValue(objects),
47741 totals: shouldShowTableTotals(objects),
47742 },
47743 };
47744 formattingProperties.grid = {
47745 gridVertical: TablixObjects.PropGridVertical.getValue(objects),
47746 gridVerticalColor: TablixObjects.PropGridVerticalColor.getValue(objects),
47747 gridVerticalWeight: TablixObjects.PropGridVerticalWeight.getValue(objects),
47748 gridHorizontal: TablixObjects.PropGridHorizontalTable.getValue(objects),
47749 gridHorizontalColor: TablixObjects.PropGridHorizontalColor.getValue(objects),
47750 gridHorizontalWeight: TablixObjects.PropGridHorizontalWeight.getValue(objects),
47751 outlineColor: TablixObjects.PropGridOutlineColor.getValue(objects),
47752 outlineWeight: TablixObjects.PropGridOutlineWeight.getValue(objects),
47753 rowPadding: TablixObjects.PropGridRowPadding.getValue(objects),
47754 imageHeight: TablixObjects.PropGridImageHeight.getValue(objects),
47755 };
47756 formattingProperties.columnHeaders = {
47757 fontColor: TablixObjects.PropColumnsFontColor.getValue(objects),
47758 backColor: TablixObjects.PropColumnsBackColor.getValue(objects),
47759 outline: TablixObjects.PropColumnsOutline.getValue(objects),
47760 };
47761 formattingProperties.values = {
47762 fontColorPrimary: TablixObjects.PropValuesFontColorPrimary.getValue(objects),
47763 backColorPrimary: TablixObjects.PropValuesBackColorPrimary.getValue(objects),
47764 fontColorSecondary: TablixObjects.PropValuesFontColorSecondary.getValue(objects),
47765 backColorSecondary: TablixObjects.PropValuesBackColorSecondary.getValue(objects),
47766 outline: TablixObjects.PropValuesOutline.getValue(objects),
47767 urlIcon: TablixObjects.PropValuesUrlIconProp.getValue(objects),
47768 };
47769 formattingProperties.total = {
47770 fontColor: TablixObjects.PropTotalFontColor.getValue(objects),
47771 backColor: TablixObjects.PropTotalBackColor.getValue(objects),
47772 outline: TablixObjects.PropTotalOutline.getValue(objects),
47773 };
47774 return formattingProperties;
47775 }
47776 TablixObjects.getTableObjects = getTableObjects;
47777 function getMatrixObjects(dataView) {
47778 var objects = getMetadadataObjects(dataView);
47779 var formattingProperties = {
47780 general: {
47781 autoSizeColumnWidth: TablixObjects.PropGeneralAutoSizeColumns.getValue(objects),
47782 textSize: TablixObjects.PropGeneralTextSize.getValue(objects),
47783 rowSubtotals: shouldShowRowSubtotals(objects),
47784 columnSubtotals: shouldShowColumnSubtotals(objects),
47785 },
47786 };
47787 formattingProperties.grid = {
47788 gridVertical: TablixObjects.PropGridVertical.getValue(objects),
47789 gridVerticalColor: TablixObjects.PropGridVerticalColor.getValue(objects),
47790 gridVerticalWeight: TablixObjects.PropGridVerticalWeight.getValue(objects),
47791 gridHorizontal: TablixObjects.PropGridHorizontalMatrix.getValue(objects),
47792 gridHorizontalColor: TablixObjects.PropGridHorizontalColor.getValue(objects),
47793 gridHorizontalWeight: TablixObjects.PropGridHorizontalWeight.getValue(objects),
47794 outlineColor: TablixObjects.PropGridOutlineColor.getValue(objects),
47795 outlineWeight: TablixObjects.PropGridOutlineWeight.getValue(objects),
47796 rowPadding: TablixObjects.PropGridRowPadding.getValue(objects),
47797 imageHeight: TablixObjects.PropGridImageHeight.getValue(objects),
47798 };
47799 formattingProperties.columnHeaders = {
47800 fontColor: TablixObjects.PropColumnsFontColor.getValue(objects),
47801 backColor: TablixObjects.PropColumnsBackColor.getValue(objects),
47802 outline: TablixObjects.PropColumnsOutline.getValue(objects),
47803 };
47804 formattingProperties.rowHeaders = {
47805 fontColor: TablixObjects.PropRowsFontColor.getValue(objects),
47806 backColor: TablixObjects.PropRowsBackColor.getValue(objects),
47807 outline: TablixObjects.PropRowsOutline.getValue(objects),
47808 };
47809 formattingProperties.values = {
47810 fontColorPrimary: TablixObjects.PropValuesFontColorPrimary.getValue(objects),
47811 backColorPrimary: TablixObjects.PropValuesBackColorPrimary.getValue(objects),
47812 fontColorSecondary: TablixObjects.PropValuesFontColorSecondary.getValue(objects),
47813 backColorSecondary: TablixObjects.PropValuesBackColorSecondary.getValue(objects),
47814 outline: TablixObjects.PropValuesOutline.getValue(objects),
47815 };
47816 formattingProperties.subtotals = {
47817 fontColor: TablixObjects.PropSubTotalsFontColor.getValue(objects),
47818 backColor: TablixObjects.PropSubTotalsBackColor.getValue(objects),
47819 outline: TablixObjects.PropSubTotalsOutline.getValue(objects),
47820 };
47821 return formattingProperties;
47822 }
47823 TablixObjects.getMatrixObjects = getMatrixObjects;
47824 /**
47825 * Generate default objects for the Table/Matrix to set default styling
47826 * @param {TablixType} tablixType Tablix Type: table | matrix
47827 * @returns DataViewObjects that can be attached to the DataViewMetadata
47828 */
47829 function generateTablixDefaultObjects(tablixType) {
47830 return {
47831 general: [{
47832 selector: null,
47833 properties: {
47834 textSize: DataViewObjectDefinitions.encodePropertyValue(12, { numeric: true }),
47835 totals: DataViewObjectDefinitions.encodePropertyValue(false, { bool: true }),
47836 }
47837 }],
47838 };
47839 }
47840 TablixObjects.generateTablixDefaultObjects = generateTablixDefaultObjects;
47841 function getTextSizeInPx(textSize) {
47842 return jsCommon.PixelConverter.fromPoint(textSize);
47843 }
47844 TablixObjects.getTextSizeInPx = getTextSizeInPx;
47845 function shouldShowTableTotals(objects) {
47846 return TablixObjects.PropGeneralTableTotals.getValue(objects);
47847 }
47848 TablixObjects.shouldShowTableTotals = shouldShowTableTotals;
47849 function shouldShowTableTotalsOption(dataView) {
47850 if (dataView && dataView.table && !_.isEmpty(dataView.table.columns)) {
47851 var columns = dataView.table.columns;
47852 if (_.some(columns, function (column) { return column.discourageAggregationAcrossGroups; }))
47853 return false;
47854 }
47855 return true;
47856 }
47857 function getTableColumnMetadata(dataView) {
47858 if (!dataView || !dataView.table || _.isEmpty(dataView.table.columns))
47859 return;
47860 return dataView.table.columns;
47861 }
47862 function shouldShowRowSubtotals(objects) {
47863 return TablixObjects.PropGeneralMatrixRowSubtotals.getValue(objects);
47864 }
47865 TablixObjects.shouldShowRowSubtotals = shouldShowRowSubtotals;
47866 function shouldShowRowSubtotalsOption(dataView) {
47867 return !(dataView &&
47868 dataView.matrix &&
47869 dataView.matrix.rows &&
47870 isDiscourageAggregationAcrossGroups(dataView.matrix.rows.levels));
47871 }
47872 function shouldShowColumnSubtotals(objects) {
47873 return TablixObjects.PropGeneralMatrixColumnSubtotals.getValue(objects);
47874 }
47875 TablixObjects.shouldShowColumnSubtotals = shouldShowColumnSubtotals;
47876 function shouldShowColumnSubtotalsOption(dataView) {
47877 return !(dataView &&
47878 dataView.matrix &&
47879 dataView.matrix.columns &&
47880 isDiscourageAggregationAcrossGroups(dataView.matrix.columns.levels));
47881 }
47882 TablixObjects.shouldShowColumnSubtotalsOption = shouldShowColumnSubtotalsOption;
47883 function isDiscourageAggregationAcrossGroups(levels) {
47884 var lastLevel = _.last(levels);
47885 // If the last item is not Aggregatable, disable totals option since there will be no totals at all to display
47886 // However, if the non-aggregatable filed is in the middle, there are totals showing up in matrix.
47887 // Therefore, we still allow users to turn it off
47888 return lastLevel && _.some(lastLevel.sources, function (source) { return source.discourageAggregationAcrossGroups; });
47889 }
47890 TablixObjects.isDiscourageAggregationAcrossGroups = isDiscourageAggregationAcrossGroups;
47891 })(TablixObjects = internal.TablixObjects || (internal.TablixObjects = {}));
47892 var TablixUtils;
47893 (function (TablixUtils) {
47894 TablixUtils.CssClassTablixDiv = "tablixDiv"; // Any DIV inside the table (outer and inner)
47895 TablixUtils.CssClassContentElement = "tablixCellContentElement"; // Outer DIV
47896 TablixUtils.CssClassContentHost = "tablixCellContentHost"; // Inner DIV
47897 TablixUtils.CssClassTablixHeader = "tablixHeader"; // Any Header in the Table/Matrix
47898 TablixUtils.CssClassTablixColumnHeaderLeaf = "tablixColumnHeaderLeaf"; // Leaf Column Headers
47899 TablixUtils.CssClassTablixValueNumeric = "tablixValueNumeric"; // Numeric cells, will also be applied to all Matrix body cells
47900 TablixUtils.CssClassTablixValueTotal = "tablixValueTotal"; // Total cells, will also be applied to subtotal Matrix body cells
47901 TablixUtils.CssClassValueURLIcon = "powervisuals-glyph url-icon tablixUrlIconGlyph"; // Any <a> Tag
47902 TablixUtils.CssClassValueURLIconContainer = "tablixValueUrlIcon"; // Container for the <a> tag
47903 TablixUtils.CssClassMatrixRowHeaderLeaf = "matrixRowHeaderLeaf"; // Matrix Leaf Row Headers
47904 TablixUtils.CssClassMatrixRowHeaderSubTotal = "matrixRowHeaderSubTotal"; // Matrix SubTotal Row Headers
47905 TablixUtils.CssClassTableFooter = 'tableFooterCell'; // Any cell in the Footer area
47906 TablixUtils.CssClassTableBodyCell = 'tableBodyCell'; // Any cell in the Table Body
47907 TablixUtils.CssClassTableBodyCellBottom = 'tableBodyCellBottom'; // Bottom-Most Body cell
47908 TablixUtils.StringNonBreakingSpace = '&nbsp;';
47909 TablixUtils.UnitOfMeasurement = 'px';
47910 var SortIconContainerClassName = "tablixSortIconContainer";
47911 TablixUtils.CellPaddingLeft = 10;
47912 TablixUtils.CellPaddingRight = 5;
47913 TablixUtils.CellPaddingLeftMatrixTotal = 5;
47914 TablixUtils.FontFamilyCell = "'Segoe UI','wf_segoe-ui_normal', helvetica, arial, sans-serif";
47915 TablixUtils.FontFamilyHeader = "'Segoe UI','wf_segoe-ui_normal', helvetica, arial, sans-serif";
47916 TablixUtils.FontFamilyTotal = "'Segoe UI Bold','wf_segoe-ui_bold', helvetica, arial, sans-serif";
47917 TablixUtils.FontColorCells = "#333";
47918 TablixUtils.FontColorHeaders = "#666";
47919 var EdgeSettings = (function () {
47920 function EdgeSettings(weight, color) {
47921 this.applyParams(true, weight, color);
47922 }
47923 EdgeSettings.prototype.applyParams = function (shown, weight, color) {
47924 if (shown) {
47925 this.weight = weight == null ? 0 : weight;
47926 this.color = color == null ? 'black' : color;
47927 }
47928 else {
47929 this.weight = 0;
47930 this.color = 'black';
47931 }
47932 };
47933 EdgeSettings.prototype.getCSS = function () {
47934 var css = [];
47935 if (_.isNumber(this.weight)) {
47936 css.push(this.weight + TablixUtils.UnitOfMeasurement);
47937 if (this.color)
47938 css.push(this.color);
47939 css.push('solid');
47940 }
47941 return css.join(' ');
47942 };
47943 return EdgeSettings;
47944 }());
47945 TablixUtils.EdgeSettings = EdgeSettings;
47946 /**
47947 * Style parameters for each Cell
47948 */
47949 var CellStyle = (function () {
47950 function CellStyle() {
47951 this.borders = {};
47952 this.paddings = { top: 0, left: TablixUtils.CellPaddingLeft, bottom: 0, right: TablixUtils.CellPaddingRight };
47953 // Initializing values with empty string would cause CSS attributes to not be set if they are undefined
47954 this.fontFamily = "";
47955 this.fontColor = "";
47956 this.backColor = "";
47957 this.hasImage = false;
47958 }
47959 /**
47960 * Sets the Inline style for the Cell
47961 * @param {ITablixCell} cell Cell to set style to
47962 */
47963 CellStyle.prototype.applyStyle = function (cell) {
47964 var div = cell.extension.contentHost;
47965 var style = div.style;
47966 style.fontFamily = this.fontFamily;
47967 style.color = this.fontColor;
47968 style.backgroundColor = this.backColor;
47969 /**
47970 * We are setting the borders as inset shadow
47971 * This way we can control how intersecting borders would look like when they have different colors
47972 */
47973 var borderShadow = [];
47974 style.border = "none";
47975 if (this.borders.left) {
47976 borderShadow.push("inset " + this.borders.left.weight + TablixUtils.UnitOfMeasurement + " 0 0 0 " + this.borders.left.color);
47977 }
47978 if (this.borders.right) {
47979 borderShadow.push("inset -" + this.borders.right.weight + TablixUtils.UnitOfMeasurement + " 0 0 0 " + this.borders.right.color);
47980 }
47981 if (this.borders.top) {
47982 borderShadow.push("inset 0 " + this.borders.top.weight + TablixUtils.UnitOfMeasurement + " 0 0 " + this.borders.top.color);
47983 }
47984 if (this.borders.bottom) {
47985 borderShadow.push("inset 0 -" + this.borders.bottom.weight + TablixUtils.UnitOfMeasurement + " 0 0 " + this.borders.bottom.color);
47986 }
47987 style.boxShadow = borderShadow.join(', ');
47988 style.paddingTop = ((this.paddings.top == null ? 0 : this.paddings.top) + (this.borders.top == null ? 0 : this.borders.top.weight)) + TablixUtils.UnitOfMeasurement;
47989 style.paddingRight = ((this.paddings.right == null ? TablixUtils.CellPaddingRight : this.paddings.right) + (this.borders.right == null ? 0 : this.borders.right.weight)) + TablixUtils.UnitOfMeasurement;
47990 style.paddingBottom = ((this.paddings.bottom == null ? 0 : this.paddings.bottom) + (this.borders.bottom == null ? 0 : this.borders.bottom.weight)) + TablixUtils.UnitOfMeasurement;
47991 style.paddingLeft = ((this.paddings.left == null ? TablixUtils.CellPaddingLeft : this.paddings.left) + (this.borders.left == null ? 0 : this.borders.left.weight)) + TablixUtils.UnitOfMeasurement;
47992 };
47993 CellStyle.prototype.getExtraTop = function () {
47994 var extra = 0;
47995 if (this.paddings.top)
47996 extra += this.paddings.top;
47997 if (this.borders.top)
47998 extra += this.borders.top.weight;
47999 return extra;
48000 };
48001 CellStyle.prototype.getExtraBottom = function () {
48002 var extra = 0;
48003 if (this.paddings.bottom)
48004 extra += this.paddings.bottom;
48005 if (this.borders.bottom)
48006 extra += this.borders.bottom.weight;
48007 return extra;
48008 };
48009 CellStyle.prototype.getExtraRight = function () {
48010 var extra = 0;
48011 if (this.paddings.right)
48012 extra += this.paddings.right;
48013 if (this.borders.right)
48014 extra += this.borders.right.weight;
48015 return extra;
48016 };
48017 CellStyle.prototype.getExtraLeft = function () {
48018 var extra = 0;
48019 if (this.paddings.left)
48020 extra += this.paddings.left;
48021 if (this.borders.left)
48022 extra += this.borders.left.weight;
48023 return extra;
48024 };
48025 return CellStyle;
48026 }());
48027 TablixUtils.CellStyle = CellStyle;
48028 /**
48029 * Index within a dimension (row/column)
48030 */
48031 var DimensionPosition = (function () {
48032 function DimensionPosition() {
48033 }
48034 return DimensionPosition;
48035 }());
48036 TablixUtils.DimensionPosition = DimensionPosition;
48037 /**
48038 * Poistion information about the cell
48039 */
48040 var CellPosition = (function () {
48041 function CellPosition() {
48042 this.row = new DimensionPosition();
48043 this.column = new DimensionPosition();
48044 }
48045 CellPosition.prototype.isMatch = function (position) {
48046 return this.column.index === position.column.index &&
48047 this.row.index === position.row.index;
48048 };
48049 return CellPosition;
48050 }());
48051 TablixUtils.CellPosition = CellPosition;
48052 var TablixVisualCell = (function () {
48053 function TablixVisualCell(dataPoint, isTotal, columnMetadata, formatter) {
48054 this.dataPoint = dataPoint;
48055 this.columnMetadata = columnMetadata;
48056 this.formatter = formatter;
48057 this.isTotal = isTotal;
48058 this.position = new TablixUtils.CellPosition();
48059 }
48060 Object.defineProperty(TablixVisualCell.prototype, "textContent", {
48061 get: function () {
48062 if (this.dataPoint == null)
48063 return '';
48064 if (this.formatter)
48065 return this.formatter(this.dataPoint, this.columnMetadata, TablixObjects.PropColumnFormatString.getPropertyID());
48066 else
48067 return this.dataPoint;
48068 },
48069 enumerable: true,
48070 configurable: true
48071 });
48072 ;
48073 Object.defineProperty(TablixVisualCell.prototype, "domContent", {
48074 get: function () {
48075 if (this.columnMetadata && isValidStatusGraphic(this.columnMetadata.kpi, this.textContent))
48076 return createKpiDom(this.columnMetadata.kpi, this.textContent);
48077 },
48078 enumerable: true,
48079 configurable: true
48080 });
48081 ;
48082 Object.defineProperty(TablixVisualCell.prototype, "isNumeric", {
48083 get: function () {
48084 if (this.columnMetadata)
48085 return this.columnMetadata.type.numeric && !this.columnMetadata.kpi;
48086 },
48087 enumerable: true,
48088 configurable: true
48089 });
48090 ;
48091 Object.defineProperty(TablixVisualCell.prototype, "isUrl", {
48092 get: function () {
48093 if (this.columnMetadata)
48094 return visuals.converterHelper.isWebUrlColumn(this.columnMetadata);
48095 },
48096 enumerable: true,
48097 configurable: true
48098 });
48099 ;
48100 Object.defineProperty(TablixVisualCell.prototype, "isImage", {
48101 get: function () {
48102 if (this.columnMetadata)
48103 return visuals.converterHelper.isImageUrlColumn(this.columnMetadata);
48104 },
48105 enumerable: true,
48106 configurable: true
48107 });
48108 Object.defineProperty(TablixVisualCell.prototype, "isValidUrl", {
48109 get: function () {
48110 return jsCommon.UrlUtils.isValidImageUrl(this.textContent);
48111 },
48112 enumerable: true,
48113 configurable: true
48114 });
48115 ;
48116 TablixVisualCell.prototype.isMatch = function (item) {
48117 return this.position.isMatch(item.position) && this.backColor === item.backColor;
48118 };
48119 return TablixVisualCell;
48120 }());
48121 TablixUtils.TablixVisualCell = TablixVisualCell;
48122 function createTable() {
48123 return document.createElement("table");
48124 }
48125 TablixUtils.createTable = createTable;
48126 function createDiv() {
48127 var div = document.createElement("div");
48128 div.className = "tablixDiv";
48129 return div;
48130 }
48131 TablixUtils.createDiv = createDiv;
48132 function resetCellCssClass(cell) {
48133 cell.extension.contentElement.className = TablixUtils.CssClassTablixDiv + " " + TablixUtils.CssClassContentElement;
48134 cell.extension.contentHost.className = TablixUtils.CssClassTablixDiv + " " + TablixUtils.CssClassContentHost;
48135 }
48136 TablixUtils.resetCellCssClass = resetCellCssClass;
48137 function addCellCssClass(cell, style) {
48138 cell.extension.contentHost.className += " " + style;
48139 }
48140 TablixUtils.addCellCssClass = addCellCssClass;
48141 /**
48142 * Clears all inline styles (border, fontColor, background) and resets CSS classes
48143 * Performed with unbind-<Cell>
48144 */
48145 function clearCellStyle(cell) {
48146 cell.extension.contentHost.className = "";
48147 cell.extension.contentHost.style.cssText = "";
48148 }
48149 TablixUtils.clearCellStyle = clearCellStyle;
48150 function clearCellTextAndTooltip(cell) {
48151 cell.extension.contentHost.textContent = '';
48152 cell.extension.contentHost.removeAttribute('title');
48153 cell.contentHeight = cell.contentWidth = 0;
48154 controls.HTMLElementUtils.clearChildren(cell.extension.contentHost);
48155 }
48156 TablixUtils.clearCellTextAndTooltip = clearCellTextAndTooltip;
48157 function setCellTextAndTooltip(cell, text) {
48158 var val = visuals.TextUtil.replaceSpaceWithNBSP(text);
48159 cell.extension.contentHost.textContent = val;
48160 cell.extension.contentHost.title = val;
48161 }
48162 TablixUtils.setCellTextAndTooltip = setCellTextAndTooltip;
48163 function isValidSortClick(e) {
48164 var colHeader = e.target;
48165 var x = e.offsetX;
48166 return x >= 0 && x < colHeader.offsetWidth - internal.TablixResizer.resizeHandleSize;
48167 }
48168 TablixUtils.isValidSortClick = isValidSortClick;
48169 function appendATagToBodyCell(value, cell, urlIcon) {
48170 var element = cell.extension.contentHost;
48171 var atag = null;
48172 if (element.childElementCount === 0) {
48173 atag = document.createElement('a');
48174 element.appendChild(atag);
48175 }
48176 else {
48177 atag = element.children[0];
48178 }
48179 atag.href = value;
48180 atag.target = '_blank';
48181 atag.title = value;
48182 if (urlIcon === true) {
48183 atag.className = TablixUtils.CssClassValueURLIcon;
48184 element.className = TablixUtils.CssClassValueURLIconContainer;
48185 }
48186 else {
48187 atag.innerText = value;
48188 }
48189 }
48190 TablixUtils.appendATagToBodyCell = appendATagToBodyCell;
48191 function appendImgTagToBodyCell(value, cell, imageHeight) {
48192 var element = cell.extension.contentHost;
48193 var imgContainer = TablixUtils.createDiv();
48194 var imgTag = document.createElement('img');
48195 imgContainer.style.height = imageHeight + "px";
48196 imgContainer.style.width = "100%";
48197 imgContainer.style.textAlign = "center";
48198 imgTag.src = value;
48199 imgTag.style.maxHeight = "100%";
48200 imgTag.style.maxWidth = "100%";
48201 imgContainer.appendChild(imgTag);
48202 element.appendChild(imgContainer);
48203 }
48204 TablixUtils.appendImgTagToBodyCell = appendImgTagToBodyCell;
48205 function createKpiDom(kpi, kpiValue) {
48206 debug.assertValue(kpi, 'kpi');
48207 debug.assertValue(kpiValue, 'kpiValue');
48208 var className = visuals.KpiUtil.getClassForKpi(kpi, kpiValue) || '';
48209 return DomFactory.div()
48210 .addClass(className)
48211 .css({
48212 'display': 'inline-block',
48213 'vertical-align': 'bottom',
48214 'margin': '0',
48215 });
48216 }
48217 TablixUtils.createKpiDom = createKpiDom;
48218 function isValidStatusGraphic(kpi, kpiValue) {
48219 if (!kpi || kpiValue === undefined) {
48220 return false;
48221 }
48222 return !!visuals.KpiUtil.getClassForKpi(kpi, kpiValue);
48223 }
48224 TablixUtils.isValidStatusGraphic = isValidStatusGraphic;
48225 function getCustomSortEventArgs(queryName, sortDirection) {
48226 var sortDescriptors = [{
48227 queryName: queryName,
48228 sortDirection: sortDirection
48229 }];
48230 return { sortDescriptors: sortDescriptors };
48231 }
48232 TablixUtils.getCustomSortEventArgs = getCustomSortEventArgs;
48233 function reverseSort(sortDirection) {
48234 return sortDirection === 2 /* Descending */ ? 1 /* Ascending */ : 2 /* Descending */;
48235 }
48236 TablixUtils.reverseSort = reverseSort;
48237 function createColumnHeaderWithSortIcon(item, cell) {
48238 var colHeaderContainer = TablixUtils.createDiv();
48239 if (item.sort) {
48240 var itemSort = item.sort;
48241 colHeaderContainer.appendChild(createSortIcon(itemSort, true));
48242 colHeaderContainer.appendChild(createSortIcon(reverseSort(itemSort), false));
48243 }
48244 else {
48245 colHeaderContainer.appendChild(createSortIcon(2 /* Descending */, false));
48246 }
48247 var colHeaderTitle = TablixUtils.createDiv();
48248 // Preserving trailing and leading spaces
48249 var title = item ? visuals.TextUtil.replaceSpaceWithNBSP(item.displayName) : '';
48250 colHeaderTitle.textContent = title;
48251 colHeaderContainer.appendChild(colHeaderTitle);
48252 cell.extension.contentHost.title = title;
48253 cell.extension.contentHost.appendChild(colHeaderContainer);
48254 }
48255 TablixUtils.createColumnHeaderWithSortIcon = createColumnHeaderWithSortIcon;
48256 function createSortIcon(sort, isSorted) {
48257 var imgSort = document.createElement('i');
48258 imgSort.className = SortIconContainerClassName +
48259 " " + (isSorted ? "sorted" : "future") +
48260 " " + (sort === 1 /* Ascending */ ? "powervisuals-glyph caret-up" : "powervisuals-glyph caret-down");
48261 return imgSort;
48262 }
48263 function checkSortIconExists(cell) {
48264 for (var i = 0, len = cell.extension.contentElement.childElementCount; i < len; i++) {
48265 var element = cell.extension.contentElement.children.item(i);
48266 if (element.classList.contains(SortIconContainerClassName))
48267 return true;
48268 }
48269 return false;
48270 }
48271 function removeSortIcons(cell) {
48272 if (!checkSortIconExists(cell))
48273 return;
48274 $(cell.extension.contentElement).find('.' + SortIconContainerClassName).remove();
48275 }
48276 TablixUtils.removeSortIcons = removeSortIcons;
48277 })(TablixUtils = internal.TablixUtils || (internal.TablixUtils = {}));
48278 })(internal = controls.internal || (controls.internal = {}));
48279 })(controls = visuals.controls || (visuals.controls = {}));
48280 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
48281})(powerbi || (powerbi = {}));
48282/*
48283 * Power BI Visualizations
48284 *
48285 * Copyright (c) Microsoft Corporation
48286 * All rights reserved.
48287 * MIT License
48288 *
48289 * Permission is hereby granted, free of charge, to any person obtaining a copy
48290 * of this software and associated documentation files (the ""Software""), to deal
48291 * in the Software without restriction, including without limitation the rights
48292 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48293 * copies of the Software, and to permit persons to whom the Software is
48294 * furnished to do so, subject to the following conditions:
48295 *
48296 * The above copyright notice and this permission notice shall be included in
48297 * all copies or substantial portions of the Software.
48298 *
48299 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48300 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48301 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48302 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48303 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48304 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48305 * THE SOFTWARE.
48306 */
48307/*
48308 * Power BI Visualizations
48309 *
48310 * Copyright (c) Microsoft Corporation
48311 * All rights reserved.
48312 * MIT License
48313 *
48314 * Permission is hereby granted, free of charge, to any person obtaining a copy
48315 * of this software and associated documentation files (the ""Software""), to deal
48316 * in the Software without restriction, including without limitation the rights
48317 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48318 * copies of the Software, and to permit persons to whom the Software is
48319 * furnished to do so, subject to the following conditions:
48320 *
48321 * The above copyright notice and this permission notice shall be included in
48322 * all copies or substantial portions of the Software.
48323 *
48324 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48325 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48326 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48327 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48328 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48329 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48330 * THE SOFTWARE.
48331 */
48332/*
48333 * Power BI Visualizations
48334 *
48335 * Copyright (c) Microsoft Corporation
48336 * All rights reserved.
48337 * MIT License
48338 *
48339 * Permission is hereby granted, free of charge, to any person obtaining a copy
48340 * of this software and associated documentation files (the ""Software""), to deal
48341 * in the Software without restriction, including without limitation the rights
48342 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48343 * copies of the Software, and to permit persons to whom the Software is
48344 * furnished to do so, subject to the following conditions:
48345 *
48346 * The above copyright notice and this permission notice shall be included in
48347 * all copies or substantial portions of the Software.
48348 *
48349 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48350 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48351 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48352 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48353 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48354 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48355 * THE SOFTWARE.
48356 */
48357/*
48358 * Power BI Visualizations
48359 *
48360 * Copyright (c) Microsoft Corporation
48361 * All rights reserved.
48362 * MIT License
48363 *
48364 * Permission is hereby granted, free of charge, to any person obtaining a copy
48365 * of this software and associated documentation files (the ""Software""), to deal
48366 * in the Software without restriction, including without limitation the rights
48367 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48368 * copies of the Software, and to permit persons to whom the Software is
48369 * furnished to do so, subject to the following conditions:
48370 *
48371 * The above copyright notice and this permission notice shall be included in
48372 * all copies or substantial portions of the Software.
48373 *
48374 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48375 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48376 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48377 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48378 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48379 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48380 * THE SOFTWARE.
48381 */
48382var powerbi;
48383(function (powerbi) {
48384 var visuals;
48385 (function (visuals) {
48386 var controls;
48387 (function (controls) {
48388 controls.TablixDefaultTextSize = jsCommon.TextSizeDefaults.TextSizeMin;
48389 var TablixControl = (function () {
48390 function TablixControl(hierarchyNavigator, layoutManager, binder, parentDomElement, options) {
48391 var _this = this;
48392 this.scrollBarElementWidth = 9;
48393 // Options (fontSize set after container initialized)
48394 this.options = options;
48395 var isInteractive = options.interactive;
48396 this.isTouchEnabled = isInteractive && options.enableTouchSupport;
48397 // Main Div
48398 this.mainDiv = controls.internal.TablixUtils.createDiv();
48399 this.mainDiv.classList.add(TablixControl.TablixTableAreaClassName);
48400 // Footer Div
48401 this.footerDiv = controls.internal.TablixUtils.createDiv();
48402 this.footerDiv.classList.add(TablixControl.TablixFooterClassName);
48403 if (this.isTouchEnabled)
48404 this.InitializeTouchSupport();
48405 this.gridDimensions = {};
48406 this.containerElement = controls.internal.TablixUtils.createDiv();
48407 this.className = layoutManager.getTablixClassName();
48408 this.autoSizeWidth = false;
48409 this.autoSizeHeight = false;
48410 this.fontFamily = controls.internal.TablixUtils.FontFamilyCell;
48411 this.fontColor = controls.internal.TablixUtils.FontColorCells;
48412 this.fontSize = options.fontSize;
48413 parentDomElement.className = TablixControl.TablixContainerClassName;
48414 parentDomElement.appendChild(this.containerElement);
48415 this.containerElement.addEventListener("mousewheel", function (e) { _this.onMouseWheel(e); });
48416 this.containerElement.addEventListener("DOMMouseScroll", function (e) { _this.onFireFoxMouseWheel(e); });
48417 this.containerElement.appendChild(this.mainDiv);
48418 this.containerElement.appendChild(this.footerDiv);
48419 if (this.isTouchEnabled) {
48420 this.touchInterpreter.initTouch(this.mainDiv, null, false);
48421 this.footerTouchInterpreter.initTouch(this.footerDiv, this.mainDiv, false);
48422 }
48423 this.controlLayoutManager = layoutManager;
48424 this.controlLayoutManager.initialize(this);
48425 this.hierarchyTablixNavigator = hierarchyNavigator;
48426 this.binder = binder;
48427 this.columnDim = new controls.TablixColumnDimension(this);
48428 this.rowDim = new controls.TablixRowDimension(this);
48429 this.columnDim._otherDimension = this.rowDimension;
48430 this.rowDim._otherDimension = this.columnDimension;
48431 this.InitializeScrollbars();
48432 if (!isInteractive) {
48433 this.scrollbarWidth = 0;
48434 }
48435 this.updateHorizontalPosition();
48436 this.updateVerticalPosition();
48437 this.updateFooterVisibility();
48438 this.lastRenderingArgs = {};
48439 }
48440 TablixControl.prototype.InitializeTouchSupport = function () {
48441 this.touchManager = new controls.TouchUtils.TouchManager();
48442 this.touchInterpreter = new controls.TouchUtils.TouchEventInterpreter(this.touchManager);
48443 this.footerTouchInterpreter = new controls.TouchUtils.TouchEventInterpreter(this.touchManager);
48444 this.columnTouchDelegate = new controls.ColumnTouchDelegate(new controls.TouchUtils.Rectangle());
48445 this.rowTouchDelegate = new controls.RowTouchDelegate(new controls.TouchUtils.Rectangle());
48446 this.bodyTouchDelegate = new controls.BodyTouchDelegate(new controls.TouchUtils.Rectangle());
48447 this.footerTouchDelegate = new controls.ColumnTouchDelegate(new controls.TouchUtils.Rectangle());
48448 this.columnTouchDelegate.setHandler(this, this.onTouchEvent);
48449 this.rowTouchDelegate.setHandler(this, this.onTouchEvent);
48450 this.bodyTouchDelegate.setHandler(this, this.onTouchEvent);
48451 this.footerTouchDelegate.setHandler(this, this.onTouchEvent);
48452 this.touchManager.addTouchRegion(this.columnTouchDelegate.dimension, this.columnTouchDelegate, this.columnTouchDelegate);
48453 this.touchManager.addTouchRegion(this.rowTouchDelegate.dimension, this.rowTouchDelegate, this.rowTouchDelegate);
48454 this.touchManager.addTouchRegion(this.bodyTouchDelegate.dimension, this.bodyTouchDelegate, this.bodyTouchDelegate);
48455 this.touchManager.addTouchRegion(this.footerTouchDelegate.dimension, this.footerTouchDelegate, this.footerTouchDelegate);
48456 };
48457 TablixControl.prototype.InitializeScrollbars = function () {
48458 // Row Dimension
48459 this.rowDim._initializeScrollbar(this.containerElement, null, this.options.layoutKind);
48460 var rowDimensionScrollbarStyle = this.rowDim.scrollbar.element.style;
48461 rowDimensionScrollbarStyle.position = "absolute";
48462 rowDimensionScrollbarStyle.top = "0" + TablixControl.UnitOfMeasurement;
48463 rowDimensionScrollbarStyle.right = "0" + TablixControl.UnitOfMeasurement;
48464 this.rowDim.scrollbar.width = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48465 // Default to true which is the more common case to avoid an extra rendering iteration
48466 // when first rendering the visual
48467 this.rowDim.scrollbar.show(true);
48468 // Column Dimension
48469 this.columnDim._initializeScrollbar(this.containerElement, null, this.options.layoutKind);
48470 var columnDimensionScrollbarStyle = this.columnDim.scrollbar.element.style;
48471 columnDimensionScrollbarStyle.position = "absolute";
48472 columnDimensionScrollbarStyle.left = "0" + TablixControl.UnitOfMeasurement;
48473 columnDimensionScrollbarStyle.bottom = "0" + TablixControl.UnitOfMeasurement;
48474 this.columnDim.scrollbar.height = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48475 this.columnDim.scrollbar.show(false);
48476 };
48477 Object.defineProperty(TablixControl.prototype, "container", {
48478 get: function () {
48479 return this.containerElement;
48480 },
48481 enumerable: true,
48482 configurable: true
48483 });
48484 Object.defineProperty(TablixControl.prototype, "contentHost", {
48485 get: function () {
48486 return this.mainDiv;
48487 },
48488 enumerable: true,
48489 configurable: true
48490 });
48491 Object.defineProperty(TablixControl.prototype, "footerHost", {
48492 get: function () {
48493 return this.footerDiv;
48494 },
48495 enumerable: true,
48496 configurable: true
48497 });
48498 Object.defineProperty(TablixControl.prototype, "className", {
48499 set: function (value) {
48500 this.containerElement.className = value;
48501 },
48502 enumerable: true,
48503 configurable: true
48504 });
48505 Object.defineProperty(TablixControl.prototype, "hierarchyNavigator", {
48506 get: function () {
48507 return this.hierarchyTablixNavigator;
48508 },
48509 enumerable: true,
48510 configurable: true
48511 });
48512 TablixControl.prototype.getBinder = function () {
48513 return this.binder;
48514 };
48515 Object.defineProperty(TablixControl.prototype, "autoSizeWidth", {
48516 get: function () {
48517 return this._autoSizeWidth;
48518 },
48519 set: function (value) {
48520 this._autoSizeWidth = value;
48521 if (!value) {
48522 this.containerElement.style.minWidth = this.containerElement.style.maxWidth = "none";
48523 }
48524 },
48525 enumerable: true,
48526 configurable: true
48527 });
48528 Object.defineProperty(TablixControl.prototype, "autoSizeHeight", {
48529 get: function () {
48530 return this._autoSizeHeight;
48531 },
48532 set: function (value) {
48533 if (!value) {
48534 this.containerElement.style.minHeight = this.containerElement.style.maxHeight = "none";
48535 }
48536 },
48537 enumerable: true,
48538 configurable: true
48539 });
48540 Object.defineProperty(TablixControl.prototype, "maxWidth", {
48541 get: function () {
48542 return this.maximumWidth;
48543 },
48544 set: function (value) {
48545 this.maximumWidth = value;
48546 this.containerElement.style.maxWidth = this.maximumWidth + TablixControl.UnitOfMeasurement;
48547 },
48548 enumerable: true,
48549 configurable: true
48550 });
48551 Object.defineProperty(TablixControl.prototype, "viewport", {
48552 get: function () {
48553 return this.viewPort;
48554 },
48555 set: function (value) {
48556 this.viewPort = value;
48557 this.containerElement.style.width = this.viewPort.width + TablixControl.UnitOfMeasurement;
48558 this.containerElement.style.height = this.viewPort.height + TablixControl.UnitOfMeasurement;
48559 this.rowDim.scrollbar.invalidateArrange();
48560 this.columnDim.scrollbar.invalidateArrange();
48561 this.controlLayoutManager.updateViewport(this.viewPort);
48562 },
48563 enumerable: true,
48564 configurable: true
48565 });
48566 Object.defineProperty(TablixControl.prototype, "maxHeight", {
48567 get: function () {
48568 return this.maximumHeight;
48569 },
48570 set: function (value) {
48571 this.maximumHeight = value;
48572 this.containerElement.style.maxHeight = this.maximumHeight + TablixControl.UnitOfMeasurement;
48573 },
48574 enumerable: true,
48575 configurable: true
48576 });
48577 Object.defineProperty(TablixControl.prototype, "minWidth", {
48578 get: function () {
48579 return this.minimumWidth;
48580 },
48581 set: function (value) {
48582 this.minimumWidth = value;
48583 this.containerElement.style.minWidth = this.minimumWidth + TablixControl.UnitOfMeasurement;
48584 },
48585 enumerable: true,
48586 configurable: true
48587 });
48588 Object.defineProperty(TablixControl.prototype, "minHeight", {
48589 get: function () {
48590 return this.minimumHeight;
48591 },
48592 set: function (value) {
48593 this.minimumHeight = value;
48594 this.containerElement.style.minHeight = this.minimumHeight + TablixControl.UnitOfMeasurement;
48595 },
48596 enumerable: true,
48597 configurable: true
48598 });
48599 Object.defineProperty(TablixControl.prototype, "fontSize", {
48600 get: function () {
48601 return this.textFontSize;
48602 },
48603 set: function (value) {
48604 this.textFontSize = !value ? TablixControl.DefaultFontSize : value;
48605 this.containerElement.style.fontSize = this.textFontSize;
48606 },
48607 enumerable: true,
48608 configurable: true
48609 });
48610 Object.defineProperty(TablixControl.prototype, "fontFamily", {
48611 get: function () {
48612 return this.textFontFamily;
48613 },
48614 set: function (value) {
48615 this.textFontFamily = value;
48616 this.containerElement.style.fontFamily = value;
48617 },
48618 enumerable: true,
48619 configurable: true
48620 });
48621 Object.defineProperty(TablixControl.prototype, "fontColor", {
48622 get: function () {
48623 return this.textFontColor;
48624 },
48625 set: function (value) {
48626 this.textFontColor = value;
48627 this.containerElement.style.color = value;
48628 },
48629 enumerable: true,
48630 configurable: true
48631 });
48632 Object.defineProperty(TablixControl.prototype, "scrollbarWidth", {
48633 set: function (value) {
48634 this.scrollBarElementWidth = value;
48635 this.rowDim.scrollbar.width = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48636 this.columnDim.scrollbar.height = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48637 },
48638 enumerable: true,
48639 configurable: true
48640 });
48641 TablixControl.prototype.updateModels = function (resetScrollOffsets, rowModel, columnModel) {
48642 this.rowDim.model = rowModel;
48643 this.rowDim.modelDepth = this.hierarchyNavigator.getRowHierarchyDepth();
48644 this.columnDim.model = columnModel;
48645 this.columnDim.modelDepth = this.hierarchyNavigator.getColumnHierarchyDepth();
48646 if (resetScrollOffsets) {
48647 this.rowDim.scrollOffset = 0;
48648 this.columnDim.scrollOffset = 0;
48649 }
48650 this.layoutManager.updateColumnCount(this.rowDim, this.columnDim);
48651 };
48652 TablixControl.prototype.updateColumnDimensions = function (rowHierarchyWidth, columnHierarchyWidth, count) {
48653 var gridDimensions = this.gridDimensions;
48654 gridDimensions.columnCount = count;
48655 gridDimensions.rowHierarchyWidth = rowHierarchyWidth;
48656 gridDimensions.columnHierarchyWidth = columnHierarchyWidth;
48657 };
48658 TablixControl.prototype.updateRowDimensions = function (columnHierarchyHeight, rowHierarchyHeight, rowHierarchyContentHeight, count, footerHeight) {
48659 var gridDimensions = this.gridDimensions;
48660 gridDimensions.rowCount = count;
48661 gridDimensions.rowHierarchyHeight = rowHierarchyHeight;
48662 gridDimensions.rowHierarchyContentHeight = rowHierarchyContentHeight;
48663 gridDimensions.columnHierarchyHeight = columnHierarchyHeight;
48664 gridDimensions.footerHeight = footerHeight;
48665 };
48666 TablixControl.prototype.updateTouchDimensions = function () {
48667 var gridDimensions = this.gridDimensions;
48668 this.columnTouchDelegate.resize(gridDimensions.rowHierarchyWidth, 0, gridDimensions.columnHierarchyWidth, gridDimensions.columnHierarchyHeight);
48669 this.columnTouchDelegate.setScrollDensity(gridDimensions.columnCount / gridDimensions.columnHierarchyWidth);
48670 this.rowTouchDelegate.resize(0, gridDimensions.columnHierarchyHeight, gridDimensions.rowHierarchyWidth, gridDimensions.rowHierarchyHeight);
48671 this.rowTouchDelegate.setScrollDensity(gridDimensions.rowCount / gridDimensions.rowHierarchyHeight);
48672 this.bodyTouchDelegate.resize(gridDimensions.rowHierarchyWidth, gridDimensions.columnHierarchyHeight, gridDimensions.columnHierarchyWidth, gridDimensions.rowHierarchyHeight);
48673 this.bodyTouchDelegate.setScrollDensity(gridDimensions.columnCount / gridDimensions.columnHierarchyWidth, gridDimensions.rowCount / gridDimensions.rowHierarchyHeight);
48674 this.footerTouchDelegate.resize(gridDimensions.rowHierarchyWidth, gridDimensions.columnHierarchyHeight + gridDimensions.rowHierarchyHeight, gridDimensions.columnHierarchyWidth, gridDimensions.footerHeight);
48675 this.footerTouchDelegate.setScrollDensity(gridDimensions.columnCount / gridDimensions.columnHierarchyWidth);
48676 };
48677 TablixControl.prototype.onMouseWheel = function (e) {
48678 var dimension = this.determineDimensionToScroll();
48679 if (dimension)
48680 dimension.scrollbar.onMouseWheel(e);
48681 };
48682 TablixControl.prototype.onFireFoxMouseWheel = function (e) {
48683 var dimension = this.determineDimensionToScroll();
48684 if (dimension)
48685 dimension.scrollbar.onFireFoxMouseWheel(e);
48686 };
48687 TablixControl.prototype.determineDimensionToScroll = function () {
48688 if (this.rowDim.scrollbar.visible)
48689 return this.rowDim;
48690 // In the absence of the vertical scrollbar, we scroll the
48691 // horizontal scrollbar.
48692 if (this.columnDim.scrollbar.visible)
48693 return this.columnDim;
48694 return null;
48695 };
48696 Object.defineProperty(TablixControl.prototype, "layoutManager", {
48697 get: function () {
48698 return this.controlLayoutManager;
48699 },
48700 enumerable: true,
48701 configurable: true
48702 });
48703 Object.defineProperty(TablixControl.prototype, "columnDimension", {
48704 get: function () {
48705 return this.columnDim;
48706 },
48707 enumerable: true,
48708 configurable: true
48709 });
48710 Object.defineProperty(TablixControl.prototype, "rowDimension", {
48711 get: function () {
48712 return this.rowDim;
48713 },
48714 enumerable: true,
48715 configurable: true
48716 });
48717 TablixControl.prototype.refresh = function (clear) {
48718 this.render(clear, null);
48719 };
48720 TablixControl.prototype._onScrollAsync = function (dimension) {
48721 var _this = this;
48722 requestAnimationFrame(function () { _this.performPendingScroll(dimension); });
48723 };
48724 TablixControl.prototype.performPendingScroll = function (dimension) {
48725 this.render(false, dimension);
48726 };
48727 TablixControl.prototype.updateHorizontalPosition = function () {
48728 if (this.rowDim.scrollbar.visible) {
48729 this.columnDim.scrollbar.element.style.right = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48730 this.footerDiv.style.right = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48731 this.mainDiv.style.right = this.scrollBarElementWidth + TablixControl.UnitOfMeasurement;
48732 }
48733 else {
48734 this.columnDim.scrollbar.element.style.right = "0" + TablixControl.UnitOfMeasurement;
48735 this.mainDiv.style.right = "0" + TablixControl.UnitOfMeasurement;
48736 this.footerDiv.style.right = "0" + TablixControl.UnitOfMeasurement;
48737 }
48738 };
48739 TablixControl.prototype.updateFooterVisibility = function () {
48740 if (this.rowDim.hasFooter() ? (this.footerDiv.style.display !== "block") : (this.footerDiv.style.display !== "none")) {
48741 if (this.rowDim.hasFooter()) {
48742 this.footerDiv.style.display = "block";
48743 }
48744 else {
48745 this.footerDiv.style.display = "none";
48746 }
48747 }
48748 };
48749 TablixControl.prototype.updateVerticalPosition = function () {
48750 var hasVerticalScrollbar = this.rowDim.scrollbar.visible;
48751 // TODO: ideally the tablix control would not know about where it is rendered but the layout manager
48752 // would provider that information; we should refactor the layout manager so that getLayoutKind is not needed anymore.
48753 var isDashboardTile = this.controlLayoutManager.getLayoutKind() === 1 /* DashboardTile */;
48754 var showFooter = hasVerticalScrollbar || isDashboardTile;
48755 if (showFooter) {
48756 var mainBottom = this.footerDiv.offsetHeight;
48757 var footerBottom = 0;
48758 var verticalScrollbarBottom = 0;
48759 // If we have a horizontal scrollbar, we need to adjust the bottom
48760 // value by the scrollbar width
48761 var hasHorizontalScrollbar = this.columnDim.scrollbar.visible;
48762 if (hasHorizontalScrollbar) {
48763 mainBottom += this.scrollBarElementWidth;
48764 footerBottom += this.scrollBarElementWidth;
48765 verticalScrollbarBottom = this.scrollBarElementWidth;
48766 }
48767 this.mainDiv.style.bottom = mainBottom + TablixControl.UnitOfMeasurement;
48768 this.rowDim.scrollbar.element.style.bottom = verticalScrollbarBottom + TablixControl.UnitOfMeasurement;
48769 this.footerDiv.style.bottom = footerBottom + TablixControl.UnitOfMeasurement;
48770 // With a vertical scrollbar, the footer is always rendered at the bottom
48771 this.footerDiv.style.removeProperty("top");
48772 }
48773 else {
48774 // Without a vertical scrollbar, the footer is rendered below the last row;
48775 // this is controlled by the top value only
48776 this.footerDiv.style.top = this.gridDimensions.rowHierarchyContentHeight + TablixControl.UnitOfMeasurement;
48777 this.footerDiv.style.removeProperty("bottom");
48778 this.mainDiv.style.removeProperty("bottom");
48779 }
48780 };
48781 TablixControl.prototype.alreadyRendered = function (scrollingDimension) {
48782 if (scrollingDimension !== this.lastRenderingArgs.scrollingDimension ||
48783 this.rowDimension.scrollOffset !== this.lastRenderingArgs.rowScrollOffset ||
48784 this.columnDimension.scrollOffset !== this.lastRenderingArgs.columnScrollOffset) {
48785 return false;
48786 }
48787 return true;
48788 };
48789 TablixControl.prototype.render = function (clear, scrollingDimension) {
48790 // at time of rendering always ensure the scroll offset is valid
48791 this.columnDim.makeScrollOffsetValid();
48792 this.rowDim.makeScrollOffsetValid();
48793 if (clear || scrollingDimension === null) {
48794 this.lastRenderingArgs = {};
48795 }
48796 else if (this.alreadyRendered(scrollingDimension)) {
48797 return;
48798 }
48799 var done = false;
48800 this.renderIterationCount = 0;
48801 this.controlLayoutManager.onStartRenderingSession(scrollingDimension, this.mainDiv, clear);
48802 var binder = this.binder;
48803 binder.onStartRenderingSession();
48804 var priorFooterHeight = this.gridDimensions.footerHeight;
48805 var priorRowHierarchyHeight = this.gridDimensions.rowHierarchyHeight;
48806 var priorRowHierarchyContentHeight = this.gridDimensions.rowHierarchyContentHeight;
48807 while (!done && this.renderIterationCount < TablixControl.MaxRenderIterationCount) {
48808 var hScrollbarVisibility = this.columnDim.scrollbar.visible;
48809 var vScrollbarVisibility = this.rowDim.scrollbar.visible;
48810 this.columnDim._onStartRenderingIteration();
48811 this.rowDim._onStartRenderingIteration();
48812 this.controlLayoutManager.onStartRenderingIteration(clear);
48813 // These calls add cells to the table.
48814 // Column needs to be rendered before rows as the row call will pair up with columns to produce the body cells.
48815 this.renderCorner();
48816 this.columnDim._render();
48817 this.rowDim._render();
48818 done = this.controlLayoutManager.onEndRenderingIteration();
48819 this.columnDim._onEndRenderingIteration();
48820 this.rowDim._onEndRenderingIteration();
48821 if ((hScrollbarVisibility !== this.columnDim.scrollbar.visible)) {
48822 this.updateVerticalPosition();
48823 }
48824 if (vScrollbarVisibility !== this.rowDim.scrollbar.visible) {
48825 this.updateHorizontalPosition();
48826 }
48827 this.renderIterationCount++;
48828 }
48829 this.controlLayoutManager.onEndRenderingSession();
48830 binder.onEndRenderingSession();
48831 if (this.isTouchEnabled)
48832 this.updateTouchDimensions();
48833 this.lastRenderingArgs.rowScrollOffset = this.rowDimension.scrollOffset;
48834 this.lastRenderingArgs.columnScrollOffset = this.columnDimension.scrollOffset;
48835 this.updateContainerDimensions();
48836 var lastRenderingArgs = this.lastRenderingArgs;
48837 lastRenderingArgs.rowScrollOffset = this.rowDimension.scrollOffset;
48838 lastRenderingArgs.columnScrollOffset = this.columnDimension.scrollOffset;
48839 lastRenderingArgs.scrollingDimension = scrollingDimension;
48840 if (priorFooterHeight !== this.gridDimensions.footerHeight ||
48841 priorRowHierarchyHeight !== this.gridDimensions.rowHierarchyHeight ||
48842 priorRowHierarchyContentHeight !== this.gridDimensions.rowHierarchyContentHeight) {
48843 this.updateVerticalPosition();
48844 }
48845 // NOTE: it is critical that we refresh the scrollbars only after the vertical
48846 // position was updated above; otherwise the measurements can be incorrect.
48847 if (this.options.interactive) {
48848 this.columnDim.scrollbar.refresh();
48849 this.rowDim.scrollbar.refresh();
48850 }
48851 };
48852 TablixControl.prototype.updateContainerDimensions = function () {
48853 var gridDimensions = this.gridDimensions;
48854 if (this._autoSizeWidth) {
48855 var vScrollBarWidth = this.rowDim.scrollbar.visible ? this.scrollBarElementWidth : 0;
48856 this.containerElement.style.width =
48857 gridDimensions.rowHierarchyWidth +
48858 gridDimensions.columnHierarchyWidth +
48859 vScrollBarWidth +
48860 TablixControl.UnitOfMeasurement;
48861 }
48862 if (this._autoSizeHeight) {
48863 var hScrollBarHeight = this.columnDim.scrollbar.visible ? this.scrollBarElementWidth : 0;
48864 this.containerElement.style.height =
48865 gridDimensions.columnHierarchyHeight +
48866 gridDimensions.rowHierarchyHeight +
48867 gridDimensions.footerHeight +
48868 hScrollBarHeight +
48869 TablixControl.UnitOfMeasurement;
48870 }
48871 };
48872 TablixControl.prototype.cornerCellMatch = function (item, cell) {
48873 var previousItem = cell.item;
48874 return cell.type === 0 /* CornerCell */ && previousItem && this.hierarchyTablixNavigator.cornerCellItemEquals(item, previousItem);
48875 };
48876 TablixControl.prototype.renderCorner = function () {
48877 var columnDepth = this.columnDim.getDepth();
48878 var rowDepth = this.rowDim.getDepth();
48879 for (var i = 0; i < columnDepth; i++) {
48880 for (var j = 0; j < rowDepth; j++) {
48881 var item = this.hierarchyTablixNavigator.getCorner(j, i);
48882 var cell = this.controlLayoutManager.getOrCreateCornerCell(item, j, i);
48883 var match = this.cornerCellMatch(item, cell);
48884 if (!match) {
48885 this._unbindCell(cell);
48886 cell.type = 0 /* CornerCell */;
48887 cell.item = item;
48888 this.binder.bindCornerCell(item, cell);
48889 }
48890 this.controlLayoutManager.onCornerCellRealized(item, cell);
48891 }
48892 }
48893 };
48894 TablixControl.prototype._unbindCell = function (cell) {
48895 switch (cell.type) {
48896 case 3 /* BodyCell */:
48897 this.binder.unbindBodyCell(cell.item, cell);
48898 break;
48899 case 2 /* ColumnHeader */:
48900 this.binder.unbindColumnHeader(cell.item, cell);
48901 break;
48902 case 1 /* RowHeader */:
48903 this.binder.unbindRowHeader(cell.item, cell);
48904 break;
48905 case 0 /* CornerCell */:
48906 this.binder.unbindCornerCell(cell.item, cell);
48907 }
48908 cell.item = null;
48909 cell.type = null;
48910 };
48911 TablixControl.prototype.onTouchEvent = function (args) {
48912 var colShift;
48913 var rowShift;
48914 var that;
48915 if ((args) && (args.length > 0)) {
48916 if (("columnDim" in args[0]) && ("rowDim" in args[0])) {
48917 that = args[0];
48918 colShift = that.columnDim.scrollbar.visible ? args[1] : 0;
48919 rowShift = that.rowDim.scrollbar.visible ? args[2] : 0;
48920 that.columnDim.scrollbar.viewMin = Math.max(0, that.columnDim.scrollbar.viewMin + colShift);
48921 that.columnDim.scrollOffset = Math.max(0, that.columnDim.scrollOffset + colShift);
48922 that.rowDim.scrollbar.viewMin = Math.max(0, that.rowDim.scrollbar.viewMin + rowShift);
48923 that.rowDim.scrollOffset = Math.max(0, that.rowDim.scrollOffset + rowShift);
48924 if (colShift === 0) {
48925 that._onScrollAsync(that.rowDim);
48926 }
48927 else if (rowShift === 0) {
48928 that._onScrollAsync(that.columnDim);
48929 }
48930 else {
48931 that._onScrollAsync(null);
48932 }
48933 }
48934 }
48935 };
48936 TablixControl.UnitOfMeasurement = 'px';
48937 TablixControl.TablixContainerClassName = 'tablixContainer';
48938 TablixControl.TablixTableAreaClassName = "tablixTableArea";
48939 TablixControl.TablixFooterClassName = "tableFooterArea";
48940 TablixControl.DefaultFontSize = jsCommon.PixelConverter.fromPoint(controls.TablixDefaultTextSize);
48941 /*
48942 * This is workaround for the infinite loop in rendering
48943 * BugID: 6518621
48944 * ToDo: Investigate the underlying cause for rendering to never report completion
48945 * Rendering typically require 3-5 iterations to complete, so 10 is enough
48946 */
48947 TablixControl.MaxRenderIterationCount = 10;
48948 return TablixControl;
48949 }());
48950 controls.TablixControl = TablixControl;
48951 })(controls = visuals.controls || (visuals.controls = {}));
48952 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
48953})(powerbi || (powerbi = {}));
48954/*
48955 * Power BI Visualizations
48956 *
48957 * Copyright (c) Microsoft Corporation
48958 * All rights reserved.
48959 * MIT License
48960 *
48961 * Permission is hereby granted, free of charge, to any person obtaining a copy
48962 * of this software and associated documentation files (the ""Software""), to deal
48963 * in the Software without restriction, including without limitation the rights
48964 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48965 * copies of the Software, and to permit persons to whom the Software is
48966 * furnished to do so, subject to the following conditions:
48967 *
48968 * The above copyright notice and this permission notice shall be included in
48969 * all copies or substantial portions of the Software.
48970 *
48971 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48972 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48973 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48974 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48975 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48976 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48977 * THE SOFTWARE.
48978 */
48979var powerbi;
48980(function (powerbi) {
48981 var visuals;
48982 (function (visuals) {
48983 var controls;
48984 (function (controls) {
48985 var TablixDimension = (function () {
48986 function TablixDimension(tablixControl) {
48987 this._scrollStep = 0.1;
48988 this._owner = tablixControl;
48989 this._hierarchyNavigator = tablixControl.hierarchyNavigator;
48990 this._binder = tablixControl.getBinder();
48991 this._tablixLayoutManager = tablixControl.layoutManager;
48992 this.scrollOffset = 0;
48993 }
48994 TablixDimension.prototype._onStartRenderingIteration = function () {
48995 this.updateScrollPosition();
48996 };
48997 TablixDimension.prototype._onEndRenderingIteration = function () {
48998 };
48999 TablixDimension.prototype.getValidScrollOffset = function (scrollOffset) {
49000 return Math.min(Math.max(scrollOffset, 0), Math.max(this.getItemsCount() - this._scrollStep, 0));
49001 };
49002 TablixDimension.prototype.makeScrollOffsetValid = function () {
49003 this.scrollOffset = this.getValidScrollOffset(this.scrollOffset);
49004 };
49005 TablixDimension.prototype.getIntegerScrollOffset = function () {
49006 return Math.floor(this.scrollOffset);
49007 };
49008 TablixDimension.prototype.getFractionScrollOffset = function () {
49009 return this.scrollOffset - this.getIntegerScrollOffset();
49010 };
49011 Object.defineProperty(TablixDimension.prototype, "scrollbar", {
49012 get: function () {
49013 return this._scrollbar;
49014 },
49015 enumerable: true,
49016 configurable: true
49017 });
49018 TablixDimension.prototype.getFirstVisibleItem = function (level) {
49019 return this._scrollItems[level];
49020 };
49021 TablixDimension.prototype.getFirstVisibleChild = function (item) {
49022 return this._hierarchyNavigator.getAt(this._hierarchyNavigator.getChildren(item), this.getFirstVisibleChildIndex(item));
49023 };
49024 TablixDimension.prototype.getFirstVisibleChildIndex = function (item) {
49025 var startItem = this.getFirstVisibleItem(this._hierarchyNavigator.getLevel(item) + 1);
49026 var firstVisibleIndex;
49027 if (startItem === undefined || (startItem !== undefined && this._hierarchyNavigator.getParent(startItem) !== item)) {
49028 firstVisibleIndex = 0;
49029 }
49030 else {
49031 firstVisibleIndex = this._hierarchyNavigator.getIndex(startItem);
49032 }
49033 return firstVisibleIndex;
49034 };
49035 TablixDimension.prototype._initializeScrollbar = function (parentElement, touchDiv, layoutKind) {
49036 var _this = this;
49037 this._scrollbar = this._createScrollbar(parentElement, layoutKind);
49038 this._scrollbar._onscroll.push(function (e) { return _this.onScroll(); });
49039 if (touchDiv) {
49040 this.scrollbar.initTouch(touchDiv, true);
49041 touchDiv.style.setProperty("-ms-touch-action", "pinch-zoom");
49042 }
49043 };
49044 TablixDimension.prototype.getItemsCount = function () {
49045 return this.model ? this._hierarchyNavigator.getLeafCount(this.model) : 0;
49046 };
49047 TablixDimension.prototype.getDepth = function () {
49048 return this.modelDepth;
49049 };
49050 TablixDimension.prototype.onScroll = function () {
49051 this.scrollOffset = this._scrollbar.viewMin;
49052 this._owner._onScrollAsync(this);
49053 };
49054 Object.defineProperty(TablixDimension.prototype, "otherDimension", {
49055 get: function () {
49056 return this._otherDimension;
49057 },
49058 enumerable: true,
49059 configurable: true
49060 });
49061 Object.defineProperty(TablixDimension.prototype, "layoutManager", {
49062 get: function () {
49063 return this._layoutManager;
49064 },
49065 enumerable: true,
49066 configurable: true
49067 });
49068 TablixDimension.prototype._createScrollbar = function (parentElement, layoutKind) {
49069 // abstract
49070 debug.assertFail("PureVirtualMethod: TablixDimension._createScrollbar");
49071 return null;
49072 };
49073 TablixDimension.prototype.updateScrollPosition = function () {
49074 this._scrollItems = [];
49075 if (!this.model) {
49076 return;
49077 }
49078 var firstVisibleScrollIndex = this.getIntegerScrollOffset();
49079 var firstVisible = this._hierarchyNavigator.getLeafAt(this.model, firstVisibleScrollIndex);
49080 if (!firstVisible) {
49081 return;
49082 }
49083 this._firstVisibleScrollIndex = firstVisibleScrollIndex;
49084 do {
49085 this._scrollItems[this._hierarchyNavigator.getLevel(firstVisible)] = firstVisible;
49086 firstVisible = this._hierarchyNavigator.getParent(firstVisible);
49087 } while (firstVisible !== null);
49088 };
49089 return TablixDimension;
49090 }());
49091 controls.TablixDimension = TablixDimension;
49092 var TablixRowDimension = (function (_super) {
49093 __extends(TablixRowDimension, _super);
49094 function TablixRowDimension(tablixControl) {
49095 _super.call(this, tablixControl);
49096 this._layoutManager = this._tablixLayoutManager.rowLayoutManager;
49097 this._footer = null;
49098 }
49099 TablixRowDimension.prototype.setFooter = function (footerHeader) {
49100 this._footer = footerHeader;
49101 this._owner.updateFooterVisibility();
49102 };
49103 TablixRowDimension.prototype.hasFooter = function () {
49104 return (this._footer !== null);
49105 };
49106 /**
49107 * This method first populates the footer followed by each row and their correlating body cells from top to bottom.
49108 */
49109 TablixRowDimension.prototype._render = function () {
49110 var firstVisibleRowItem = this.getFirstVisibleItem(0);
49111 if (this.hasFooter()) {
49112 this.addFooterRowHeader(this._footer);
49113 this.addFooterBodyCells(this._footer);
49114 }
49115 if (firstVisibleRowItem !== undefined) {
49116 this.addNodes(this.model, 0, this.getDepth(), this._hierarchyNavigator.getIndex(firstVisibleRowItem));
49117 }
49118 };
49119 TablixRowDimension.prototype._createScrollbar = function (parentElement, layoutKind) {
49120 return new controls.VerticalScrollbar(parentElement, layoutKind);
49121 };
49122 /**
49123 * This function is a recursive call (with its recursive behavior in addNode()) that will navigate
49124 * through the row hierarchy in DFS (Depth First Search) order and continue into a single row
49125 * upto its estimated edge.
49126 */
49127 TablixRowDimension.prototype.addNodes = function (items, rowIndex, depth, firstVisibleIndex) {
49128 var count = this._hierarchyNavigator.getCount(items);
49129 //for loop explores children of current "items"
49130 for (var i = firstVisibleIndex; i < count; i++) {
49131 if (!this._layoutManager.needsToRealize) {
49132 return;
49133 }
49134 var item = this._hierarchyNavigator.getAt(items, i);
49135 var cell = this.addNode(item, items, rowIndex, depth);
49136 rowIndex += cell.rowSpan; //next node is bumped down according cells vertical span
49137 }
49138 };
49139 TablixRowDimension.prototype.getFirstVisibleChildLeaf = function (item) {
49140 var leaf = item;
49141 while (!this._hierarchyNavigator.isLeaf(leaf)) {
49142 leaf = this.getFirstVisibleChild(leaf);
49143 }
49144 return leaf;
49145 };
49146 TablixRowDimension.prototype.bindRowHeader = function (item, cell) {
49147 this._binder.bindRowHeader(item, cell);
49148 };
49149 /**
49150 * This method can be thought of as the continuation of addNodes() as it continues the DFS (Depth First Search)
49151 * started from addNodes(). This function also handles ending the recursion with "_needsToRealize" being set to
49152 * false.
49153 *
49154 * Once the body cells are reached, populating is done linearly with addBodyCells().
49155 */
49156 TablixRowDimension.prototype.addNode = function (item, items, rowIndex, depth) {
49157 var previousCount;
49158 var rowHeaderCell = this._tablixLayoutManager.getOrCreateRowHeader(item, items, rowIndex, this._hierarchyNavigator.getLevel(item));
49159 var match = this.rowHeaderMatch(item, rowHeaderCell);
49160 if (!match) {
49161 this._owner._unbindCell(rowHeaderCell);
49162 rowHeaderCell.type = 1 /* RowHeader */;
49163 rowHeaderCell.item = item;
49164 rowHeaderCell.unfixRowHeight();
49165 }
49166 if (this._hierarchyNavigator.isLeaf(item)) {
49167 rowHeaderCell.colSpan = depth - this._hierarchyNavigator.getLevel(item);
49168 rowHeaderCell.rowSpan = 1;
49169 if (!match)
49170 this.bindRowHeader(item, rowHeaderCell);
49171 this._tablixLayoutManager.onRowHeaderRealized(item, rowHeaderCell);
49172 this.addBodyCells(item, items, rowIndex);
49173 }
49174 else {
49175 previousCount = this._layoutManager.getRealizedItemsCount();
49176 this.addNodes(this._hierarchyNavigator.getChildren(item), rowIndex, depth, this.getFirstVisibleChildIndex(item));
49177 rowHeaderCell.colSpan = 1;
49178 rowHeaderCell.rowSpan = this._layoutManager.getRealizedItemsCount() - previousCount + 1;
49179 if (!match)
49180 this.bindRowHeader(item, rowHeaderCell);
49181 this._tablixLayoutManager.onRowHeaderRealized(item, rowHeaderCell);
49182 }
49183 return rowHeaderCell;
49184 };
49185 TablixRowDimension.prototype.rowHeaderMatch = function (item, cell) {
49186 var previousItem = cell.item;
49187 return cell.type === 1 /* RowHeader */ && previousItem && this._hierarchyNavigator.headerItemEquals(item, previousItem);
49188 };
49189 TablixRowDimension.prototype.addBodyCells = function (item, items, rowIndex) {
49190 var firstVisibleColumnIndex = this._otherDimension.getIntegerScrollOffset();
49191 var columnCount = this._otherDimension._layoutManager.getRealizedItemsCount() - this.getDepth();
49192 var hierarchyNavigator = this._hierarchyNavigator;
49193 var otherModel = this._otherDimension.model;
49194 var layoutManager = this._tablixLayoutManager;
49195 for (var i = 0; i < columnCount; i++) {
49196 //get column header "item" by index to pair up with row header to find corelating body cell
49197 var cellItem = hierarchyNavigator.getIntersection(item, hierarchyNavigator.getLeafAt(otherModel, firstVisibleColumnIndex + i));
49198 var cell = layoutManager.getOrCreateBodyCell(cellItem, item, items, rowIndex, i);
49199 this.bindBodyCell(cellItem, cell);
49200 layoutManager.onBodyCellRealized(cellItem, cell);
49201 }
49202 };
49203 TablixRowDimension.prototype.bindBodyCell = function (item, cell) {
49204 var match = this.bodyCelMatch(item, cell);
49205 if (!match) {
49206 this._owner._unbindCell(cell);
49207 cell.type = 3 /* BodyCell */;
49208 cell.item = item;
49209 cell.unfixRowHeight();
49210 this._binder.bindBodyCell(item, cell);
49211 }
49212 };
49213 TablixRowDimension.prototype.addFooterRowHeader = function (item) {
49214 var cell = this._tablixLayoutManager.getOrCreateFooterRowHeader(item, this.model);
49215 cell.colSpan = this.getDepth();
49216 var match = this.rowHeaderMatch(item, cell);
49217 if (!match) {
49218 this._owner._unbindCell(cell);
49219 cell.type = 1 /* RowHeader */;
49220 cell.item = item;
49221 cell.unfixRowHeight();
49222 this.bindRowHeader(item, cell);
49223 this._tablixLayoutManager.onRowHeaderFooterRealized(item, cell);
49224 }
49225 };
49226 TablixRowDimension.prototype.addFooterBodyCells = function (rowItem) {
49227 var firstVisibleColumnIndex = this._otherDimension.getIntegerScrollOffset();
49228 var columnCount = this._otherDimension.layoutManager.getRealizedItemsCount() - this.getDepth();
49229 var layoutManager = this._tablixLayoutManager;
49230 for (var i = 0; i < columnCount; i++) {
49231 //get column header "item" by index to pair up with row header to find corelating body cell
49232 var columnItem = this._hierarchyNavigator.getLeafAt(this._otherDimension.model, firstVisibleColumnIndex + i);
49233 //get corelating body cell and bind it
49234 var item = this._hierarchyNavigator.getIntersection(rowItem, columnItem);
49235 var cell = layoutManager.getOrCreateFooterBodyCell(item, i);
49236 this.bindBodyCell(item, cell);
49237 layoutManager.onBodyCellFooterRealized(item, cell);
49238 }
49239 };
49240 TablixRowDimension.prototype.bodyCelMatch = function (item, cell) {
49241 var previousItem = cell.item;
49242 return cell.type === 3 /* BodyCell */ && previousItem && this._hierarchyNavigator.bodyCellItemEquals(item, previousItem);
49243 };
49244 return TablixRowDimension;
49245 }(TablixDimension));
49246 controls.TablixRowDimension = TablixRowDimension;
49247 var TablixColumnDimension = (function (_super) {
49248 __extends(TablixColumnDimension, _super);
49249 function TablixColumnDimension(tablixControl) {
49250 _super.call(this, tablixControl);
49251 this._layoutManager = this._tablixLayoutManager.columnLayoutManager;
49252 }
49253 TablixColumnDimension.prototype._render = function () {
49254 var firstVisibleColumnItem = this.getFirstVisibleItem(0);
49255 if (firstVisibleColumnItem !== undefined) {
49256 this.addNodes(this.model, 0, this.getDepth(), this._hierarchyNavigator.getIndex(firstVisibleColumnItem));
49257 }
49258 };
49259 TablixColumnDimension.prototype._createScrollbar = function (parentElement, layoutKind) {
49260 var scrollbar = new controls.HorizontalScrollbar(parentElement, layoutKind);
49261 // Set smallest increment of the scrollbar to 0.2 rows
49262 scrollbar.smallIncrement = 0.2;
49263 return scrollbar;
49264 };
49265 TablixColumnDimension.prototype.addNodes = function (items, columnIndex, depth, firstVisibleIndex) {
49266 var count = this._hierarchyNavigator.getCount(items);
49267 for (var i = firstVisibleIndex; i < count; i++) {
49268 if (!this._layoutManager.needsToRealize) {
49269 return;
49270 }
49271 var cell = this.addNode(this._hierarchyNavigator.getAt(items, i), items, columnIndex, depth);
49272 columnIndex += cell.colSpan;
49273 }
49274 };
49275 TablixColumnDimension.prototype.addNode = function (item, items, columnIndex, depth) {
49276 var cell = this._tablixLayoutManager.getOrCreateColumnHeader(item, items, this._hierarchyNavigator.getLevel(item), columnIndex);
49277 var match = this.columnHeaderMatch(item, cell);
49278 if (!match) {
49279 this._owner._unbindCell(cell);
49280 cell.type = 2 /* ColumnHeader */;
49281 cell.item = item;
49282 cell.unfixRowHeight();
49283 }
49284 if (this._hierarchyNavigator.isLeaf(item)) {
49285 cell.rowSpan = depth - this._hierarchyNavigator.getLevel(item);
49286 }
49287 else {
49288 var previousCount = this._layoutManager.getRealizedItemsCount();
49289 this.addNodes(this._hierarchyNavigator.getChildren(item), columnIndex, depth, this.getFirstVisibleChildIndex(item));
49290 // In case we have a grand total with multiple measures, the multi-measures will be direct children
49291 // There can be difference in level > 1. In this case, we want the Total cell to have rowspan = the difference
49292 var childrenLevelDifference = this._hierarchyNavigator.getChildrenLevelDifference(item);
49293 if (childrenLevelDifference === Infinity)
49294 cell.rowSpan = 1;
49295 else
49296 cell.rowSpan = childrenLevelDifference;
49297 cell.colSpan = this._layoutManager.getRealizedItemsCount() - previousCount + 1;
49298 }
49299 if (!match)
49300 this._binder.bindColumnHeader(item, cell);
49301 this._tablixLayoutManager.onColumnHeaderRealized(item, cell);
49302 return cell;
49303 };
49304 TablixColumnDimension.prototype.columnHeaderMatch = function (item, cell) {
49305 var previousItem = cell.item;
49306 return cell.type === 2 /* ColumnHeader */ && previousItem && this._hierarchyNavigator.headerItemEquals(item, previousItem);
49307 };
49308 return TablixColumnDimension;
49309 }(TablixDimension));
49310 controls.TablixColumnDimension = TablixColumnDimension;
49311 })(controls = visuals.controls || (visuals.controls = {}));
49312 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
49313})(powerbi || (powerbi = {}));
49314/*
49315 * Power BI Visualizations
49316 *
49317 * Copyright (c) Microsoft Corporation
49318 * All rights reserved.
49319 * MIT License
49320 *
49321 * Permission is hereby granted, free of charge, to any person obtaining a copy
49322 * of this software and associated documentation files (the ""Software""), to deal
49323 * in the Software without restriction, including without limitation the rights
49324 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49325 * copies of the Software, and to permit persons to whom the Software is
49326 * furnished to do so, subject to the following conditions:
49327 *
49328 * The above copyright notice and this permission notice shall be included in
49329 * all copies or substantial portions of the Software.
49330 *
49331 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49332 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49333 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49334 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49335 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49336 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
49337 * THE SOFTWARE.
49338 */
49339var powerbi;
49340(function (powerbi) {
49341 var visuals;
49342 (function (visuals) {
49343 var controls;
49344 (function (controls) {
49345 /**
49346 * This class represents the touch region of the column headers (this can also apply to footer/total).
49347 * This class is reponsible for interpreting gestures in terms of pixels to changes in column position.
49348 *
49349 * Unlike the table body, this can only scroll in one direction.
49350 */
49351 var ColumnTouchDelegate = (function () {
49352 /**
49353 * @constructor
49354 * @param region Location and area of the touch region in respect to its HTML element.
49355 */
49356 function ColumnTouchDelegate(region) {
49357 this.dim = region;
49358 this.averageSize = 1; //default
49359 this.handlers = null;
49360 this.tablixControl = null;
49361 }
49362 Object.defineProperty(ColumnTouchDelegate.prototype, "dimension", {
49363 get: function () {
49364 return this.dim;
49365 },
49366 enumerable: true,
49367 configurable: true
49368 });
49369 /**
49370 * Sets the amount of columns to be shifted per delta in pixels.
49371 *
49372 * @param xRatio Column to pixel ratio (# columns / # pixels).
49373 */
49374 ColumnTouchDelegate.prototype.setScrollDensity = function (xRatio) {
49375 this.averageSize = xRatio;
49376 };
49377 /**
49378 * Resize element.
49379 *
49380 * @param x X location from upper left of listened HTML element.
49381 * @param y Y location from upper left of listened HTML element.
49382 * @param width Width of area to listen for events.
49383 * @param height Height of area to listen for events.
49384 */
49385 ColumnTouchDelegate.prototype.resize = function (x, y, width, height) {
49386 this.dim.x = x;
49387 this.dim.y = y;
49388 this.dim.width = width;
49389 this.dim.height = height;
49390 };
49391 /**
49392 * @see IPixelToItem.
49393 */
49394 ColumnTouchDelegate.prototype.getPixelToItem = function (x, y, dx, dy, down) {
49395 return new controls.TouchUtils.TouchEvent(x * this.averageSize, 0, down, -dx * this.averageSize, 0);
49396 };
49397 /**
49398 * Fires event to Tablix Control to scroll with the event passed from the TouchManager.
49399 *
49400 * @param e Event recieved from touch manager.
49401 */
49402 ColumnTouchDelegate.prototype.touchEvent = function (e) {
49403 var args = [];
49404 args[0] = this.tablixControl;
49405 args[1] = e.dx;
49406 args[2] = e.dy;
49407 if (this.handlers) {
49408 controls.fire([this.handlers], args);
49409 }
49410 };
49411 /**
49412 * Asigns handler for scrolling when scroll event is fired.
49413 *
49414 * @param tablixObj TablixControl that's handling the fired event.
49415 * @param handlerCall The call to be made (EXAMPLE: handlerCall = object.method;).
49416 */
49417 ColumnTouchDelegate.prototype.setHandler = function (tablixObj, handlerCall) {
49418 this.handlers = handlerCall;
49419 this.tablixControl = tablixObj;
49420 };
49421 return ColumnTouchDelegate;
49422 }());
49423 controls.ColumnTouchDelegate = ColumnTouchDelegate;
49424 /**
49425 * This class represents the touch region of the row headers (left or right side aligned).
49426 * This class is reponsible for interpreting gestures in terms of pixels to changes in row position.
49427 *
49428 * Unlike the table body, this can only scroll in one direction.
49429 */
49430 var RowTouchDelegate = (function () {
49431 /**
49432 * @constructor
49433 * @param region Location and area of the touch region in respect to its HTML element.
49434 */
49435 function RowTouchDelegate(region) {
49436 this.dim = region;
49437 this.averageSize = 30; //default
49438 this.handlers = null;
49439 this.tablixControl = null;
49440 }
49441 Object.defineProperty(RowTouchDelegate.prototype, "dimension", {
49442 get: function () {
49443 return this.dim;
49444 },
49445 enumerable: true,
49446 configurable: true
49447 });
49448 /**
49449 * Sets the amount of rows to be shifted per delta in pixels.
49450 *
49451 * @param yRatio Row to pixel ratio (# rows / # pixels).
49452 */
49453 RowTouchDelegate.prototype.setScrollDensity = function (yRatio) {
49454 this.averageSize = yRatio;
49455 };
49456 /**
49457 * Resize element.
49458 * @param x X location from upper left of listened HTML element.
49459 * @param y Y location from upper left of listened HTML element.
49460 * @param width Width of area to listen for events.
49461 * @param height Height of area to listen for events.
49462 */
49463 RowTouchDelegate.prototype.resize = function (x, y, width, height) {
49464 this.dim.x = x;
49465 this.dim.y = y;
49466 this.dim.width = width;
49467 this.dim.height = height;
49468 };
49469 /**
49470 * @see: IPixelToItem
49471 */
49472 RowTouchDelegate.prototype.getPixelToItem = function (x, y, dx, dy, down) {
49473 var event = new controls.TouchUtils.TouchEvent(0, y * this.averageSize, down, 0, -dy * this.averageSize);
49474 return event;
49475 };
49476 /**
49477 * Fires event to Tablix Control to scroll with the event passed from the TouchManager.
49478 *
49479 * @param e Event recieved from touch manager.
49480 */
49481 RowTouchDelegate.prototype.touchEvent = function (e) {
49482 var args = [];
49483 args[0] = this.tablixControl;
49484 args[1] = e.dx;
49485 args[2] = e.dy;
49486 if (this.handlers) {
49487 controls.fire([this.handlers], args);
49488 }
49489 };
49490 /**
49491 * Asigns handler for scrolling when scroll event is fired.
49492 *
49493 * @param tablixObj TablixControl that's handling the fired event.
49494 * @param handlerCall The call to be made (EXAMPLE: handlerCall = object.method;).
49495 */
49496 RowTouchDelegate.prototype.setHandler = function (tablixObj, handlerCall) {
49497 this.handlers = handlerCall;
49498 this.tablixControl = tablixObj;
49499 };
49500 return RowTouchDelegate;
49501 }());
49502 controls.RowTouchDelegate = RowTouchDelegate;
49503 /**
49504 * This class represents the touch region covering the body of the table.
49505 * This class is reponsible for interpreting gestures in terms of pixels to
49506 * changes in row and column position.
49507 */
49508 var BodyTouchDelegate = (function () {
49509 /**
49510 * @constructor
49511 * @param region Location and area of the touch region in respect to its HTML element.
49512 */
49513 function BodyTouchDelegate(region) {
49514 this.dim = region;
49515 this.averageSizeX = BodyTouchDelegate.DefaultAverageSizeX;
49516 this.averageSizeY = BodyTouchDelegate.DefaultAverageSizeY;
49517 this.handlers = null;
49518 this.tablixControl = null;
49519 }
49520 Object.defineProperty(BodyTouchDelegate.prototype, "dimension", {
49521 /**
49522 * Returns dimension.
49523 *
49524 * @return The dimentions of the region this delegate listens to.
49525 */
49526 get: function () {
49527 return this.dim;
49528 },
49529 enumerable: true,
49530 configurable: true
49531 });
49532 /**
49533 * Sets the amount of rows and columns to be shifted per delta in pixels.
49534 *
49535 * @param xRatio Column to pixel ratio (# columns / # pixels)
49536 * @param yRatio Row to pixel ratio (# rows / # pixels)
49537 */
49538 BodyTouchDelegate.prototype.setScrollDensity = function (xRatio, yRatio) {
49539 this.averageSizeX = xRatio;
49540 this.averageSizeY = yRatio;
49541 };
49542 /**
49543 * Resize element.
49544 *
49545 * @param x X location from upper left of listened HTML element.
49546 * @param y Y location from upper left of listened HTML element.
49547 * @param width Width of area to listen for events.
49548 * @param height Height of area to listen for events.
49549 */
49550 BodyTouchDelegate.prototype.resize = function (x, y, width, height) {
49551 var dimension = this.dim;
49552 dimension.x = x;
49553 dimension.y = y;
49554 dimension.width = width;
49555 dimension.height = height;
49556 };
49557 /**
49558 * @see: IPixelToItem.
49559 */
49560 BodyTouchDelegate.prototype.getPixelToItem = function (x, y, dx, dy, down) {
49561 return new controls.TouchUtils.TouchEvent(x * this.averageSizeX, y * this.averageSizeY, down, -dx * this.averageSizeX, -dy * this.averageSizeY);
49562 };
49563 /**
49564 * Fires event to Tablix Control to scroll with the event passed from the TouchManager.
49565 *
49566 * @param e Event recieved from touch manager.
49567 */
49568 BodyTouchDelegate.prototype.touchEvent = function (e) {
49569 var args = [this.tablixControl, e.dx, e.dy];
49570 if (this.handlers) {
49571 controls.fire([this.handlers], args);
49572 }
49573 };
49574 /**
49575 * Asigns handler for scrolling when scroll event is fired.
49576 *
49577 * @param tablixObj TablixControl that's handling the fired event.
49578 * @param handlerCall The call to be made (EXAMPLE: handlerCall = object.method;).
49579 */
49580 BodyTouchDelegate.prototype.setHandler = function (tablixObj, handlerCall) {
49581 this.handlers = handlerCall;
49582 this.tablixControl = tablixObj;
49583 };
49584 BodyTouchDelegate.DefaultAverageSizeX = 30;
49585 BodyTouchDelegate.DefaultAverageSizeY = 30;
49586 return BodyTouchDelegate;
49587 }());
49588 controls.BodyTouchDelegate = BodyTouchDelegate;
49589 })(controls = visuals.controls || (visuals.controls = {}));
49590 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
49591})(powerbi || (powerbi = {}));
49592/*
49593 * Power BI Visualizations
49594 *
49595 * Copyright (c) Microsoft Corporation
49596 * All rights reserved.
49597 * MIT License
49598 *
49599 * Permission is hereby granted, free of charge, to any person obtaining a copy
49600 * of this software and associated documentation files (the ""Software""), to deal
49601 * in the Software without restriction, including without limitation the rights
49602 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49603 * copies of the Software, and to permit persons to whom the Software is
49604 * furnished to do so, subject to the following conditions:
49605 *
49606 * The above copyright notice and this permission notice shall be included in
49607 * all copies or substantial portions of the Software.
49608 *
49609 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49610 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49611 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49612 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49613 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49614 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
49615 * THE SOFTWARE.
49616 */
49617var powerbi;
49618(function (powerbi) {
49619 var visuals;
49620 (function (visuals) {
49621 var controls;
49622 (function (controls) {
49623 var TouchUtils;
49624 (function (TouchUtils) {
49625 var Point = (function () {
49626 function Point(x, y) {
49627 this.x = x || 0;
49628 this.y = y || 0;
49629 }
49630 Point.prototype.offset = function (offsetX, offsetY) {
49631 this.x += offsetX;
49632 this.y += offsetY;
49633 };
49634 return Point;
49635 }());
49636 TouchUtils.Point = Point;
49637 var Rectangle = (function (_super) {
49638 __extends(Rectangle, _super);
49639 function Rectangle(x, y, width, height) {
49640 _super.call(this, x, y);
49641 this.width = width || 0;
49642 this.height = height || 0;
49643 }
49644 Object.defineProperty(Rectangle.prototype, "point", {
49645 get: function () {
49646 return new Point(this.x, this.y);
49647 },
49648 enumerable: true,
49649 configurable: true
49650 });
49651 Rectangle.prototype.contains = function (p) {
49652 return Rectangle.contains(this, p);
49653 };
49654 Rectangle.contains = function (rect, p) {
49655 if (p && !Rectangle.isEmpty(rect)) {
49656 return rect.x <= p.x && p.x < rect.x + rect.width && rect.y <= p.y && p.y < rect.y + rect.height;
49657 }
49658 return false;
49659 };
49660 Rectangle.isEmpty = function (rect) {
49661 return !(rect !== undefined && rect.width >= 0 && rect.height >= 0);
49662 };
49663 return Rectangle;
49664 }(Point));
49665 TouchUtils.Rectangle = Rectangle;
49666 (function (MouseButton) {
49667 MouseButton[MouseButton["NoClick"] = 0] = "NoClick";
49668 MouseButton[MouseButton["LeftClick"] = 1] = "LeftClick";
49669 MouseButton[MouseButton["RightClick"] = 2] = "RightClick";
49670 MouseButton[MouseButton["CenterClick"] = 3] = "CenterClick";
49671 })(TouchUtils.MouseButton || (TouchUtils.MouseButton = {}));
49672 var MouseButton = TouchUtils.MouseButton;
49673 /**
49674 * A simple touch event class that's abstracted away from any platform specific traits.
49675 */
49676 var TouchEvent = (function () {
49677 /**
49678 * @constructor
49679 * @param x X Location of mouse.
49680 * @param y Y Location of mouse.
49681 * @param isMouseDown Indicates if the mouse button is held down or a finger press on screen.
49682 * @param dx (optional) The change in x of the gesture.
49683 * @param dy (optional) The change in y of the gesture.
49684 */
49685 function TouchEvent(x, y, isMouseDown, dx, dy) {
49686 this._x = x;
49687 this._y = y;
49688 this.isMouseButtonDown = isMouseDown;
49689 this._dx = dx || 0;
49690 this._dy = dy || 0;
49691 }
49692 Object.defineProperty(TouchEvent.prototype, "x", {
49693 get: function () {
49694 return this._x;
49695 },
49696 enumerable: true,
49697 configurable: true
49698 });
49699 Object.defineProperty(TouchEvent.prototype, "y", {
49700 get: function () {
49701 return this._y;
49702 },
49703 enumerable: true,
49704 configurable: true
49705 });
49706 Object.defineProperty(TouchEvent.prototype, "dx", {
49707 get: function () {
49708 return this._dx;
49709 },
49710 enumerable: true,
49711 configurable: true
49712 });
49713 Object.defineProperty(TouchEvent.prototype, "dy", {
49714 get: function () {
49715 return this._dy;
49716 },
49717 enumerable: true,
49718 configurable: true
49719 });
49720 Object.defineProperty(TouchEvent.prototype, "isMouseDown", {
49721 /**
49722 * Returns a boolean indicating if the mouse button is held down.
49723 *
49724 * @return: True if the the mouse button is held down,
49725 * otherwise false.
49726 */
49727 get: function () {
49728 return this.isMouseButtonDown;
49729 },
49730 enumerable: true,
49731 configurable: true
49732 });
49733 return TouchEvent;
49734 }());
49735 TouchUtils.TouchEvent = TouchEvent;
49736 /**
49737 * This class "listens" to the TouchEventInterpreter to recieve touch events and sends it to all
49738 * "Touch Delegates" with TouchRegions that contain the mouse event. Prior to sending off the
49739 * event, its position is put in respect to the delegate's TouchRegion and converted to the appropriate
49740 * unit (see IPixelToItem).
49741 */
49742 var TouchManager = (function () {
49743 /**
49744 * Default constructor.
49745 *
49746 * The default behavior is to enable thresholds and lock to axis.
49747 */
49748 function TouchManager() {
49749 this.touchList = [];
49750 this.swipeDirection = 2 /* FreeForm */;
49751 this.matchingDirectionCount = 0;
49752 this.lockThreshold = true;
49753 this.scrollThreshold = true;
49754 this.lastTouchEvent = new TouchEvent(0, 0, false);
49755 }
49756 Object.defineProperty(TouchManager.prototype, "lastEvent", {
49757 get: function () {
49758 return this.lastTouchEvent;
49759 },
49760 enumerable: true,
49761 configurable: true
49762 });
49763 /**
49764 * @param region Rectangle indicating the locations of the touch region.
49765 * @param handler Handler for recieved touch events.
49766 * @param converter Converts from pixels to the wanted item of measure (rows, columns, etc).
49767 *
49768 * EXAMPLE: dx -> from # of pixels to the right to # of columns moved to the right.
49769 */
49770 TouchManager.prototype.addTouchRegion = function (region, handler, converter) {
49771 var item = {
49772 lastPoint: new TouchEvent(0, 0, false),
49773 handler: handler,
49774 region: region,
49775 converter: converter
49776 };
49777 this.touchList = this.touchList.concat([item]);
49778 };
49779 /**
49780 * Sends a mouse up event to all regions with their last event as a mouse down event.
49781 */
49782 TouchManager.prototype.upAllTouches = function () {
49783 var eventPoint;
49784 var length;
49785 length = this.touchList.length;
49786 for (var i = 0; i < length; i++) {
49787 if (this.touchList[i].lastPoint.isMouseDown) {
49788 eventPoint = this.touchList[i].converter.getPixelToItem(this.touchList[i].lastPoint.x, this.touchList[i].lastPoint.y, 0, 0, false);
49789 this.touchList[i].handler.touchEvent(eventPoint);
49790 }
49791 this.touchList[i].lastPoint = new TouchEvent(this.touchList[i].lastPoint.x, this.touchList[i].lastPoint.y, false);
49792 }
49793 this.lastTouchEvent = new TouchEvent(0, 0, false);
49794 };
49795 TouchManager.prototype.touchEvent = function (e) {
49796 var list;
49797 var length;
49798 var x = 0;
49799 var y = 0;
49800 var dx = 0;
49801 var dy = 0;
49802 var angle = 0;
49803 var eventPoint = null;
49804 //assume there are already regions in the middle of a drag event and get those regions
49805 list = this._getActive();
49806 //if this is the start of a mouse drag event, repopulate the list with touched regions
49807 if (!this.lastTouchEvent.isMouseDown && e.isMouseDown) {
49808 list = this._findRegions(e);
49809 }
49810 //determine the delta values and update last event (delta ignored on first mouse down event)
49811 dx = this.lastTouchEvent.x - e.x;
49812 dy = this.lastTouchEvent.y - e.y;
49813 this.lastTouchEvent = new TouchEvent(e.x, e.y, e.isMouseDown, dx, dy);
49814 //go through the list
49815 length = list.length;
49816 for (var i = 0; i < length; i++) {
49817 x = e.x - list[i].region.point.x;
49818 y = e.y - list[i].region.point.y;
49819 //is this in the middle of a drag?
49820 if (list[i].lastPoint.isMouseDown && e.isMouseDown) {
49821 dx = x - list[i].lastPoint.x;
49822 dy = y - list[i].lastPoint.y;
49823 //calculate the absolute angle from the horizontal axis
49824 angle = Math.abs(180 / Math.PI * Math.atan(dy / dx));
49825 if (this.scrollThreshold) {
49826 //is the gesture already locked? (6 prior events within the threshold)
49827 if (this.lockThreshold && (this.matchingDirectionCount > 5)) {
49828 if (this.swipeDirection === 1 /* Horizontal */) {
49829 dy = 0;
49830 }
49831 else if (this.swipeDirection === 0 /* Vertical */) {
49832 dx = 0;
49833 }
49834 }
49835 else {
49836 //is it within the horizontal threshold?
49837 if (angle < 20) {
49838 dy = 0;
49839 if (this.swipeDirection === 1 /* Horizontal */) {
49840 this.matchingDirectionCount++;
49841 }
49842 else {
49843 this.matchingDirectionCount = 1;
49844 this.swipeDirection = 1 /* Horizontal */;
49845 }
49846 }
49847 else {
49848 //calculate the absolute angle from the vertical axis
49849 angle = Math.abs(180 / Math.PI * Math.atan(dx / dy));
49850 //is it within the horizontal threshold?
49851 if (angle < 20) {
49852 dx = 0;
49853 if (this.swipeDirection === 0 /* Vertical */) {
49854 this.matchingDirectionCount++;
49855 }
49856 else {
49857 this.matchingDirectionCount = 1;
49858 this.swipeDirection = 0 /* Vertical */;
49859 }
49860 }
49861 else {
49862 if (this.swipeDirection === 2 /* FreeForm */) {
49863 this.matchingDirectionCount++;
49864 }
49865 else {
49866 this.swipeDirection = 2 /* FreeForm */;
49867 this.matchingDirectionCount = 1;
49868 }
49869 }
49870 }
49871 }
49872 }
49873 }
49874 else {
49875 dx = 0;
49876 dy = 0;
49877 this.swipeDirection = 2 /* FreeForm */;
49878 this.matchingDirectionCount = 0;
49879 }
49880 list[i].lastPoint = new TouchEvent(x, y, e.isMouseDown, dx, dy);
49881 eventPoint = list[i].converter.getPixelToItem(x, y, dx, dy, e.isMouseDown);
49882 list[i].handler.touchEvent(eventPoint);
49883 }
49884 };
49885 /**
49886 * @param e Position of event used to find touched regions
49887 * @return Array of regions that contain the event point.
49888 */
49889 TouchManager.prototype._findRegions = function (e) {
49890 var list = [];
49891 var length;
49892 length = this.touchList.length;
49893 for (var i = 0; i < length; i++) {
49894 if (this.touchList[i].region.contains(new Point(e.x, e.y))) {
49895 list = list.concat([this.touchList[i]]);
49896 }
49897 }
49898 return list;
49899 };
49900 /**
49901 * @return Array of regions that contain a mouse down event. (see ITouchHandlerSet.lastPoint).
49902 */
49903 TouchManager.prototype._getActive = function () {
49904 var list = [];
49905 var length;
49906 length = this.touchList.length;
49907 for (var i = 0; i < length; i++) {
49908 if (this.touchList[i].lastPoint.isMouseDown) {
49909 list = list.concat([this.touchList[i]]);
49910 }
49911 }
49912 return list;
49913 };
49914 return TouchManager;
49915 }());
49916 TouchUtils.TouchManager = TouchManager;
49917 var MinDistanceForSwipe = 80;
49918 var MaxTimeForSwipe = 600;
49919 /**
49920 * This class is responsible for establishing connections to handle touch events
49921 * and to interpret those events so they're compatible with the touch abstractions.
49922 *
49923 * Touch events with platform specific handles should be done here.
49924 */
49925 var TouchEventInterpreter = (function () {
49926 function TouchEventInterpreter(manager) {
49927 this.manager = manager;
49928 this.allowMouseDrag = true;
49929 this.touchPanel = null;
49930 this.scale = 1;
49931 this.documentMouseMoveWrapper = null;
49932 this.documentMouseUpWrapper = null;
49933 this.sliding = false;
49934 }
49935 TouchEventInterpreter.prototype.initTouch = function (panel, touchReferencePoint, allowMouseDrag) {
49936 var _this = this;
49937 panel.style.setProperty("-ms-touch-action", "pinch-zoom");
49938 this.touchReferencePoint = touchReferencePoint;
49939 this.touchPanel = panel;
49940 this.allowMouseDrag = allowMouseDrag === undefined ? true : allowMouseDrag;
49941 if ("ontouchmove" in panel) {
49942 panel.addEventListener("touchstart", function (e) { return _this.onTouchStart(e); });
49943 panel.addEventListener("touchend", function (e) { return _this.onTouchEnd(e); });
49944 }
49945 else {
49946 panel.addEventListener("mousedown", function (e) { return _this.onTouchMouseDown(e); });
49947 panel.addEventListener("mouseup", function (e) { return _this.onTouchMouseUp(e); });
49948 }
49949 };
49950 TouchEventInterpreter.prototype.getXYByClient = function (pageX, pageY, rect) {
49951 var x = rect.left;
49952 var y = rect.top;
49953 // Fix for Safari
49954 if (window["scrollX"] !== undefined) {
49955 x += window["scrollX"];
49956 y += window["scrollY"];
49957 }
49958 var point = new Point(0, 0);
49959 point.offset(pageX - x, pageY - y);
49960 return point;
49961 };
49962 TouchEventInterpreter.prototype.onTouchStart = function (e) {
49963 if (e.touches.length === 1) {
49964 e.cancelBubble = true;
49965 var mouchEvent = e.touches[0];
49966 this.touchStartTime = new Date().getTime();
49967 this.touchStartPageY = mouchEvent.pageY;
49968 this.onTouchMouseDown(mouchEvent);
49969 }
49970 };
49971 TouchEventInterpreter.prototype.onTouchMove = function (e) {
49972 if (e.touches.length === 1) {
49973 if (e.preventDefault) {
49974 e.preventDefault();
49975 }
49976 var mouchEvent = e.touches[0];
49977 this.touchLastPageY = mouchEvent.pageY;
49978 this.touchLastPageX = mouchEvent.pageX;
49979 // while sliding ignore the touch move event
49980 if (!this.sliding) {
49981 this.onTouchMouseMove(mouchEvent);
49982 }
49983 }
49984 };
49985 TouchEventInterpreter.prototype.onTouchEnd = function (e) {
49986 this.clearTouchEvents();
49987 var swipeInfo = this.getSwipeInfo();
49988 if (this.didUserSwipe(swipeInfo)) {
49989 this.startSlideAffect(swipeInfo);
49990 }
49991 else if (!this.sliding) {
49992 this.upAllTouches();
49993 }
49994 };
49995 TouchEventInterpreter.prototype.onTouchMouseDown = function (e) {
49996 var _this = this;
49997 this.scale = controls.HTMLElementUtils.getAccumulatedScale(this.touchPanel);
49998 //any prior touch scrolling that produced a selection outside Tablix will prevent the next touch scroll (1262519)
49999 document.getSelection().removeAllRanges();
50000 this.rect = (this.touchReferencePoint ? this.touchReferencePoint : this.touchPanel).getBoundingClientRect();
50001 if ("ontouchmove" in this.touchPanel) {
50002 this.documentMouseMoveWrapper = function (e) { return _this.onTouchMove(e); };
50003 document.addEventListener("touchmove", this.documentMouseMoveWrapper);
50004 this.documentMouseUpWrapper = function (e) { return _this.onTouchEnd(e); };
50005 document.addEventListener("touchend", this.documentMouseUpWrapper);
50006 }
50007 else {
50008 this.documentMouseMoveWrapper = function (e) { return _this.onTouchMouseMove(e); };
50009 document.addEventListener("mousemove", this.documentMouseMoveWrapper);
50010 this.documentMouseUpWrapper = function (e) { return _this.onTouchMouseUp(e); };
50011 document.addEventListener("mouseup", this.documentMouseUpWrapper);
50012 }
50013 if ("setCapture" in this.touchPanel) {
50014 this.touchPanel.setCapture();
50015 }
50016 };
50017 TouchEventInterpreter.prototype.onTouchMouseMove = function (e) {
50018 var event;
50019 var point;
50020 var rect = this.rect;
50021 var validMouseDragEvent = (rect !== null) && (e.which !== MouseButton.NoClick);
50022 // Ignore events that are not part of a drag event
50023 if (!validMouseDragEvent || this.sliding)
50024 return;
50025 point = this.getXYByClient(e.pageX, e.pageY, rect);
50026 event = new TouchEvent(point.x / this.scale, point.y / this.scale, validMouseDragEvent);
50027 this.manager.touchEvent(event);
50028 if (e.preventDefault)
50029 e.preventDefault();
50030 else if ("returnValue" in e)
50031 e["returnValue"] = false;
50032 };
50033 TouchEventInterpreter.prototype.onTouchMouseUp = function (e, bubble) {
50034 this.upAllTouches();
50035 this.clearTouchEvents();
50036 };
50037 TouchEventInterpreter.prototype.getSwipeInfo = function () {
50038 var touchEndTime = new Date().getTime();
50039 var touchTime = touchEndTime - this.touchStartTime;
50040 var touchDist = this.touchLastPageY - this.touchStartPageY;
50041 var touchDirection = touchDist < 0 ? -1 : 1;
50042 return {
50043 direction: touchDirection,
50044 distance: touchDist,
50045 endTime: touchEndTime,
50046 time: touchTime,
50047 };
50048 };
50049 TouchEventInterpreter.prototype.didUserSwipe = function (swipeInfo) {
50050 return swipeInfo.time < MaxTimeForSwipe && swipeInfo.distance * swipeInfo.direction > MinDistanceForSwipe;
50051 };
50052 /**
50053 * In case of swipe - auto advance to the swipe direction in 2 steps.
50054 */
50055 TouchEventInterpreter.prototype.startSlideAffect = function (swipeInfo) {
50056 var _this = this;
50057 if (this.sliding) {
50058 return;
50059 }
50060 this.sliding = true;
50061 var point = this.getXYByClient(this.touchLastPageX, this.touchLastPageY, this.rect);
50062 this.slide(point, 300, swipeInfo);
50063 // second step
50064 requestAnimationFrame(function () {
50065 // in case the user is now scrolling in the opposite direction stop the slide
50066 if (!_this.didUserChangeDirection(swipeInfo)) {
50067 _this.slide(point, 200, swipeInfo);
50068 }
50069 _this.clearSlide();
50070 });
50071 };
50072 TouchEventInterpreter.prototype.didUserChangeDirection = function (swipeInfo) {
50073 if (this.touchStartTime <= swipeInfo.endTime) {
50074 return false;
50075 }
50076 var updatedDist = this.touchLastPageY - this.touchStartPageY;
50077 var updatedDirection = updatedDist < 0 ? -1 : 1;
50078 return updatedDirection !== swipeInfo.direction;
50079 };
50080 TouchEventInterpreter.prototype.slide = function (point, slideDist, swipeInfo) {
50081 var updatedDist = this.touchStartTime > swipeInfo.endTime ? this.touchLastPageY - this.touchStartPageY : 0;
50082 point.y += slideDist * swipeInfo.direction + updatedDist;
50083 var event = new TouchEvent(point.x / this.scale, point.y / this.scale, true);
50084 this.manager.touchEvent(event);
50085 };
50086 TouchEventInterpreter.prototype.clearSlide = function () {
50087 this.sliding = false;
50088 this.upAllTouches();
50089 };
50090 TouchEventInterpreter.prototype.upAllTouches = function () {
50091 if (this.documentMouseMoveWrapper !== null)
50092 return;
50093 this.rect = null;
50094 this.manager.upAllTouches();
50095 };
50096 TouchEventInterpreter.prototype.clearTouchEvents = function () {
50097 if ("releaseCapture" in this.touchPanel) {
50098 this.touchPanel.releaseCapture();
50099 }
50100 if (this.documentMouseMoveWrapper === null)
50101 return;
50102 if ("ontouchmove" in this.touchPanel) {
50103 document.removeEventListener("touchmove", this.documentMouseMoveWrapper);
50104 document.removeEventListener("touchend", this.documentMouseUpWrapper);
50105 }
50106 else {
50107 document.removeEventListener("mousemove", this.documentMouseMoveWrapper);
50108 document.removeEventListener("mouseup", this.documentMouseUpWrapper);
50109 }
50110 this.documentMouseMoveWrapper = null;
50111 this.documentMouseUpWrapper = null;
50112 };
50113 return TouchEventInterpreter;
50114 }());
50115 TouchUtils.TouchEventInterpreter = TouchEventInterpreter;
50116 })(TouchUtils = controls.TouchUtils || (controls.TouchUtils = {}));
50117 })(controls = visuals.controls || (visuals.controls = {}));
50118 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
50119})(powerbi || (powerbi = {}));
50120/*
50121 * Power BI Visualizations
50122 *
50123 * Copyright (c) Microsoft Corporation
50124 * All rights reserved.
50125 * MIT License
50126 *
50127 * Permission is hereby granted, free of charge, to any person obtaining a copy
50128 * of this software and associated documentation files (the ""Software""), to deal
50129 * in the Software without restriction, including without limitation the rights
50130 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50131 * copies of the Software, and to permit persons to whom the Software is
50132 * furnished to do so, subject to the following conditions:
50133 *
50134 * The above copyright notice and this permission notice shall be included in
50135 * all copies or substantial portions of the Software.
50136 *
50137 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50138 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50139 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50140 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50141 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50142 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50143 * THE SOFTWARE.
50144 */
50145var powerbi;
50146(function (powerbi) {
50147 var visuals;
50148 (function (visuals) {
50149 var controls;
50150 (function (controls) {
50151 (function (TablixType) {
50152 TablixType[TablixType["Matrix"] = 0] = "Matrix";
50153 TablixType[TablixType["Table"] = 1] = "Table";
50154 })(controls.TablixType || (controls.TablixType = {}));
50155 var TablixType = controls.TablixType;
50156 })(controls = visuals.controls || (visuals.controls = {}));
50157 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
50158})(powerbi || (powerbi = {}));
50159/*
50160 * Power BI Visualizations
50161 *
50162 * Copyright (c) Microsoft Corporation
50163 * All rights reserved.
50164 * MIT License
50165 *
50166 * Permission is hereby granted, free of charge, to any person obtaining a copy
50167 * of this software and associated documentation files (the ""Software""), to deal
50168 * in the Software without restriction, including without limitation the rights
50169 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50170 * copies of the Software, and to permit persons to whom the Software is
50171 * furnished to do so, subject to the following conditions:
50172 *
50173 * The above copyright notice and this permission notice shall be included in
50174 * all copies or substantial portions of the Software.
50175 *
50176 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50177 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50178 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50179 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50180 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50181 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50182 * THE SOFTWARE.
50183 */
50184var powerbi;
50185(function (powerbi) {
50186 var visuals;
50187 (function (visuals) {
50188 var controls;
50189 (function (controls) {
50190 var PropAutoSizeWidth = controls.internal.TablixObjects.PropGeneralAutoSizeColumns;
50191 var getMetadataObjects = controls.internal.TablixObjects.getMetadadataObjects;
50192 var TablixColumnWidthManager = (function () {
50193 function TablixColumnWidthManager(dataView, isMatrix, hostPersistCallBack, matrixLeafNodes) {
50194 this.columnWidthObjects = [];
50195 this.isMatrix = isMatrix;
50196 this.updateDataView(dataView, matrixLeafNodes);
50197 this.hostPersistCallBack = hostPersistCallBack;
50198 }
50199 /**
50200 * Update the current DataView
50201 * @param {dataView} DataView new DataView
50202 * @param {MatrixVisualNode[]} matrixLeafNodes? (Optional)Matrix Leaf Nodes
50203 */
50204 TablixColumnWidthManager.prototype.updateDataView = function (dataView, matrixLeafNodes) {
50205 this.previousDataView = this.currentDataView;
50206 if (this.previousDataView)
50207 this.previousAutoColumnSizePropertyValue = PropAutoSizeWidth.getValue(getMetadataObjects(this.previousDataView));
50208 else
50209 this.previousAutoColumnSizePropertyValue = undefined;
50210 this.currentDataView = dataView;
50211 if (this.currentDataView)
50212 this.currentAutoColumnSizePropertyValue = PropAutoSizeWidth.getValue(getMetadataObjects(this.currentDataView));
50213 else
50214 this.currentAutoColumnSizePropertyValue = undefined;
50215 this.matrixLeafNodes = matrixLeafNodes;
50216 this.updateColumnWidthObjects();
50217 this.updateTablixColumnWidths();
50218 };
50219 /**
50220 * Destroy columnWidthObjects and construct it again from the currently displayed Columns
50221 */
50222 TablixColumnWidthManager.prototype.updateColumnWidthObjects = function () {
50223 this.columnWidthObjects.length = 0;
50224 if (this.isMatrix)
50225 this.updateMatrixColumnWidthObjects();
50226 else
50227 this.updateTableColumnWidthObjects();
50228 };
50229 TablixColumnWidthManager.prototype.updateTableColumnWidthObjects = function () {
50230 if (this.currentDataView && this.currentDataView.table) {
50231 var columnMetaData = this.currentDataView.table.columns;
50232 for (var i = 0, len = columnMetaData.length; i < len; i++) {
50233 var query = columnMetaData[i].queryName;
50234 this.columnWidthObjects.push({
50235 queryName: query,
50236 width: undefined
50237 });
50238 }
50239 }
50240 };
50241 TablixColumnWidthManager.prototype.updateMatrixColumnWidthObjects = function () {
50242 // Matrix visual columns are row headers and column hierarchy leaves
50243 if (this.currentDataView && this.currentDataView.matrix && this.currentDataView.matrix.rows) {
50244 // Get query names of row groups (row headers)
50245 for (var i = 0, len = this.currentDataView.matrix.rows.levels.length; i < len; i++) {
50246 var rowGroup = this.currentDataView.matrix.rows.levels[i]; // TODO: Investigate multi-source groups
50247 if (!_.isEmpty(rowGroup.sources))
50248 this.columnWidthObjects.push({
50249 queryName: rowGroup.sources[0].queryName,
50250 width: undefined
50251 });
50252 }
50253 }
50254 // Get query names of columns leaves or values
50255 if (this.matrixLeafNodes) {
50256 for (var i = 0, len = this.matrixLeafNodes.length; i < len; i++) {
50257 var query = this.matrixLeafNodes[i].queryName;
50258 this.columnWidthObjects.push({
50259 queryName: query,
50260 width: undefined
50261 });
50262 }
50263 }
50264 };
50265 /**
50266 * Update the column widths after a dataViewChange
50267 */
50268 TablixColumnWidthManager.prototype.updateTablixColumnWidths = function () {
50269 var columnMetaData = this.currentDataView && this.currentDataView.metadata && this.currentDataView.metadata.columns;
50270 if (columnMetaData) {
50271 // Auto-Size false to true.
50272 // Blow away any saved widths and revert back to default of calculating column sizes
50273 if (this.shouldClearAllColumnWidths()) {
50274 this.autoSizeAllColumns();
50275 }
50276 else {
50277 this.deserializeColumnWidths(columnMetaData);
50278 }
50279 }
50280 };
50281 /**
50282 * Read the Column Widths from the Columns metadata
50283 * @param {DataViewMetadataColumn[]} columnMetaData Columns metadata
50284 */
50285 TablixColumnWidthManager.prototype.deserializeColumnWidths = function (columnMetaData) {
50286 // Clear existing widths
50287 this.columnWidthObjects.forEach(function (obj) {
50288 obj.width = undefined;
50289 });
50290 for (var _i = 0, columnMetaData_1 = columnMetaData; _i < columnMetaData_1.length; _i++) {
50291 var column = columnMetaData_1[_i];
50292 var columnWidthPropValue = powerbi.DataViewObjects.getValue(column.objects, TablixColumnWidthManager.columnWidthProp);
50293 if (!_.isNumber(columnWidthPropValue)) {
50294 continue;
50295 }
50296 for (var _a = 0, _b = this.columnWidthObjects; _a < _b.length; _a++) {
50297 var obj = _b[_a];
50298 if (obj.queryName === column.queryName) {
50299 obj.width = columnWidthPropValue;
50300 }
50301 }
50302 }
50303 };
50304 /**
50305 * Returns a value indicating that autoSizeColumns was flipped from true to false
50306 */
50307 TablixColumnWidthManager.prototype.shouldPersistAllColumnWidths = function () {
50308 // We don't have a previous DataView -> Don't persist
50309 if (!this.previousDataView)
50310 // TODO: 6928446
50311 // Once 6927388 gets fixed, we need to persist the DataView is first loaded with AutoSize off to count for missing set widths
50312 return false;
50313 else
50314 return !this.currentAutoColumnSizePropertyValue && this.previousAutoColumnSizePropertyValue;
50315 };
50316 /**
50317 * Returns a value indicating that autoSizeColumns was flipped from false to true
50318 */
50319 TablixColumnWidthManager.prototype.shouldClearAllColumnWidths = function () {
50320 return this.previousDataView != null && this.previousAutoColumnSizePropertyValue === false
50321 && this.currentDataView != null && this.currentAutoColumnSizePropertyValue === true;
50322 };
50323 /**
50324 * Returns the current columnWidthObjects
50325 * @returns current columnWidthObjects including undefined widths for autosized columns
50326 */
50327 TablixColumnWidthManager.prototype.getColumnWidthObjects = function () {
50328 return this.columnWidthObjects;
50329 };
50330 /**
50331 * Returns the current columnWidthObjects for only the fixed-size columns
50332 * @returns Returns the current columnWidthObjects excluding auto-sized columns
50333 */
50334 TablixColumnWidthManager.prototype.getFixedColumnWidthObjects = function () {
50335 return this.columnWidthObjects.filter(function (obj) {
50336 return obj.width != null;
50337 });
50338 };
50339 /**
50340 * Get the persisted width of a certain column in px, or undefined if the columns is set to autosize or index is out of range
50341 * @param {number} index index of the Column
50342 * @returns Column persisted width in pixel
50343 */
50344 TablixColumnWidthManager.prototype.getPersistedColumnWidth = function (index) {
50345 var colIndex = this.isMatrix ? index : index - 1;
50346 var item = this.columnWidthObjects[colIndex];
50347 if (item)
50348 return item.width;
50349 else
50350 return undefined;
50351 };
50352 /**
50353 * Call the host to persist the data
50354 * @param {boolean} generateInstances
50355 */
50356 TablixColumnWidthManager.prototype.callHostToPersist = function (generateInstances) {
50357 if (generateInstances)
50358 this.generateVisualObjectInstancesToPersist();
50359 if (this.hostPersistCallBack) {
50360 this.hostPersistCallBack(this.visualObjectInstancesToPersist);
50361 }
50362 };
50363 /**
50364 * Remove all persisted columns widths and Update visualObjectInstancesToPersist
50365 */
50366 TablixColumnWidthManager.prototype.autoSizeAllColumns = function () {
50367 this.visualObjectInstancesToPersist = {
50368 merge: [this.getAutoSizeColumnWidthObject()],
50369 remove: [],
50370 };
50371 for (var _i = 0, _a = this.columnWidthObjects; _i < _a.length; _i++) {
50372 var columnWidthObject = _a[_i];
50373 this.visualObjectInstancesToPersist.remove.push({
50374 selector: { metadata: columnWidthObject.queryName },
50375 objectName: 'general',
50376 properties: {
50377 columnWidth: undefined
50378 }
50379 });
50380 }
50381 this.callHostToPersist(false);
50382 };
50383 /**
50384 * Remove persisted column width for a specific column and Update visualObjectInstancesToPersist
50385 */
50386 TablixColumnWidthManager.prototype.onColumnAutosized = function (queryName) {
50387 // If AutoSize option is ON, remove the persisted value
50388 // Else, update the persisted value
50389 var width = this.currentAutoColumnSizePropertyValue ? undefined : -1;
50390 for (var _i = 0, _a = this.columnWidthObjects; _i < _a.length; _i++) {
50391 var obj = _a[_i];
50392 if (obj.queryName === queryName) {
50393 obj.width = width;
50394 }
50395 }
50396 ;
50397 // If AutoSize option is ON, remove the persisted value
50398 if (this.currentAutoColumnSizePropertyValue) {
50399 this.visualObjectInstancesToPersist = {
50400 remove: [{
50401 selector: { metadata: queryName },
50402 objectName: 'general',
50403 properties: { columnWidth: undefined }
50404 }],
50405 };
50406 this.callHostToPersist(false);
50407 }
50408 // Else, do nothing. A Column Resize will be triggered soon
50409 };
50410 /**
50411 * Handler for a column width change by the user
50412 * @param {number} index zero-based index of the column, including hidden row header for table
50413 * @param {number} width new width
50414 */
50415 TablixColumnWidthManager.prototype.onColumnWidthChanged = function (index, width) {
50416 // Table has a hidden row headers column
50417 var colIndex = this.isMatrix ? index : index - 1;
50418 if (_.isEmpty(this.columnWidthObjects) || colIndex < 0 || colIndex >= this.columnWidthObjects.length)
50419 return;
50420 var queryName = this.columnWidthObjects[colIndex].queryName;
50421 // Column Autosize
50422 if (width === -1) {
50423 this.onColumnAutosized(queryName);
50424 }
50425 else {
50426 for (var _i = 0, _a = this.columnWidthObjects; _i < _a.length; _i++) {
50427 var obj = _a[_i];
50428 if (obj.queryName === queryName) {
50429 obj.width = width;
50430 }
50431 }
50432 ;
50433 this.callHostToPersist(true);
50434 }
50435 };
50436 /**
50437 * Persist all column widths, called when autoSizeColumns flipped to false
50438 * @param {number[]} widthsToPersist Widths to persist, including an empty row header for table
50439 */
50440 TablixColumnWidthManager.prototype.persistAllColumnWidths = function (widthsToPersist) {
50441 var _this = this;
50442 // Table indices are offset with an empty header.
50443 var widths = this.isMatrix ? widthsToPersist : widthsToPersist.slice(1, widthsToPersist.length);
50444 // ToDo: Handle this properly
50445 // This happens when autosizing turns OFF before knowing all widths (lots of columns outside of ViewPort)
50446 if (this.columnWidthObjects.length !== widths.length) {
50447 return;
50448 }
50449 // Pick the maximum for each queryName
50450 // This will ensure going from autoSize ON to OFF will not show any ellipsis
50451 var dictionary = new Array();
50452 widths.forEach(function (w, i) {
50453 var query = _this.columnWidthObjects[i].queryName;
50454 if (dictionary[query] == null)
50455 dictionary[query] = w;
50456 else
50457 dictionary[query] = Math.max(w, dictionary[query]);
50458 });
50459 for (var _i = 0, _a = this.columnWidthObjects; _i < _a.length; _i++) {
50460 var obj = _a[_i];
50461 var width = dictionary[obj.queryName];
50462 if (width != null)
50463 obj.width = width;
50464 }
50465 this.callHostToPersist(true);
50466 };
50467 /**
50468 * Construct a ColumnAutoSize object
50469 * @returns ColumnAutoSize object
50470 */
50471 TablixColumnWidthManager.prototype.getAutoSizeColumnWidthObject = function () {
50472 return {
50473 selector: null,
50474 objectName: 'general',
50475 properties: {
50476 autoSizeColumnWidth: this.currentAutoColumnSizePropertyValue
50477 }
50478 };
50479 };
50480 /**
50481 * Generate visualObjectInstances with autoSizeColumns and Column Widths
50482 */
50483 TablixColumnWidthManager.prototype.generateVisualObjectInstancesToPersist = function () {
50484 // ToDo: Ensure lists need to be reset after call to persist
50485 // AutoSize Property
50486 this.visualObjectInstancesToPersist = {
50487 merge: [this.getAutoSizeColumnWidthObject()]
50488 };
50489 // Column Widths
50490 var added = new Array();
50491 for (var _i = 0, _a = this.columnWidthObjects; _i < _a.length; _i++) {
50492 var obj = _a[_i];
50493 // Only persist width if we have a valid queryName to use as selector
50494 // ToDo: Not sure how we can have an item without a queryName
50495 if (obj.queryName && _.isNumber(obj.width) && !added[obj.queryName]) {
50496 this.visualObjectInstancesToPersist.merge.push({
50497 selector: { metadata: obj.queryName },
50498 objectName: 'general',
50499 properties: {
50500 columnWidth: obj.width
50501 }
50502 });
50503 added[obj.queryName] = true;
50504 }
50505 }
50506 };
50507 /**
50508 * PropertyID for Column Widths (General > columnWidth)
50509 */
50510 TablixColumnWidthManager.columnWidthProp = { objectName: 'general', propertyName: 'columnWidth' };
50511 return TablixColumnWidthManager;
50512 }());
50513 controls.TablixColumnWidthManager = TablixColumnWidthManager;
50514 })(controls = visuals.controls || (visuals.controls = {}));
50515 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
50516})(powerbi || (powerbi = {}));
50517/*
50518 * Power BI Visualizations
50519 *
50520 * Copyright (c) Microsoft Corporation
50521 * All rights reserved.
50522 * MIT License
50523 *
50524 * Permission is hereby granted, free of charge, to any person obtaining a copy
50525 * of this software and associated documentation files (the ""Software""), to deal
50526 * in the Software without restriction, including without limitation the rights
50527 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50528 * copies of the Software, and to permit persons to whom the Software is
50529 * furnished to do so, subject to the following conditions:
50530 *
50531 * The above copyright notice and this permission notice shall be included in
50532 * all copies or substantial portions of the Software.
50533 *
50534 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50535 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50536 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50537 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50538 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50539 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50540 * THE SOFTWARE.
50541 */
50542var powerbi;
50543(function (powerbi) {
50544 var visuals;
50545 (function (visuals) {
50546 /**
50547 * Base class for values that are animated when resized.
50548 */
50549 var AnimatedText = (function () {
50550 function AnimatedText(name) {
50551 this.mainText = jsCommon.CssConstants.createClassAndSelector('mainText');
50552 this.name = name;
50553 this.visualConfiguration = { maxFontSize: 60 };
50554 }
50555 AnimatedText.prototype.getMetaDataColumn = function (dataView) {
50556 if (dataView && dataView.metadata && dataView.metadata.columns) {
50557 for (var i = 0, ilen = dataView.metadata.columns.length; i < ilen; i++) {
50558 var column = dataView.metadata.columns[i];
50559 if (column.isMeasure) {
50560 this.metaDataColumn = column;
50561 break;
50562 }
50563 }
50564 }
50565 };
50566 AnimatedText.prototype.getAdjustedFontHeight = function (availableWidth, textToMeasure, seedFontHeight) {
50567 var textProperties = {
50568 fontFamily: null,
50569 fontSize: null,
50570 text: textToMeasure
50571 };
50572 var fontHeight = this.getAdjustedFontHeightCore(textProperties, availableWidth, seedFontHeight, 0);
50573 return fontHeight;
50574 };
50575 AnimatedText.prototype.getAdjustedFontHeightCore = function (textProperties, availableWidth, seedFontHeight, iteration) {
50576 // Too many attempts - just return what we have so we don't sacrifice perf
50577 if (iteration > 10) {
50578 return seedFontHeight;
50579 }
50580 textProperties.fontSize = jsCommon.PixelConverter.toString(seedFontHeight);
50581 var candidateLength = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
50582 if (candidateLength < availableWidth)
50583 return seedFontHeight;
50584 return this.getAdjustedFontHeightCore(textProperties, availableWidth, seedFontHeight * 0.9, iteration + 1);
50585 };
50586 AnimatedText.prototype.clear = function () {
50587 this.svg.select(this.mainText.selector).text('');
50588 };
50589 AnimatedText.prototype.doValueTransition = function (startValue, endValue, displayUnitSystemType, animationOptions, duration, forceUpdate, formatter) {
50590 if (!forceUpdate && startValue === endValue && endValue != null)
50591 return;
50592 if (!startValue)
50593 startValue = 0;
50594 var svg = this.svg, viewport = this.currentViewport, height = viewport.height, width = viewport.width, endValueArr = [endValue], seedFontHeight = this.getSeedFontHeight(width, height), translateX = this.getTranslateX(width), translateY = this.getTranslateY(seedFontHeight), metaDataColumn = this.metaDataColumn;
50595 // Respect the formatter default value
50596 if (!formatter) {
50597 formatter = visuals.valueFormatter.create({
50598 format: this.getFormatString(metaDataColumn),
50599 value: endValue,
50600 displayUnitSystemType: displayUnitSystemType,
50601 formatSingleValues: true,
50602 allowFormatBeautification: true,
50603 columnType: metaDataColumn ? metaDataColumn.type : undefined
50604 });
50605 }
50606 var startText = formatter.format(startValue), endText = formatter.format(endValue);
50607 svg.attr('class', this.name);
50608 var textElement = svg
50609 .selectAll('text')
50610 .data(endValueArr);
50611 textElement
50612 .enter()
50613 .append('text')
50614 .attr('class', this.mainText.class);
50615 var fontHeight = this.getAdjustedFontHeight(width, endText, seedFontHeight);
50616 translateY = this.getTranslateY(fontHeight + (height - fontHeight) / 2);
50617 var textElementUpdate = textElement
50618 .text(startText)
50619 .attr({
50620 'text-anchor': this.getTextAnchor(),
50621 'font-size': fontHeight,
50622 'transform': visuals.SVGUtil.translate(translateX, translateY),
50623 })
50624 .style({
50625 'fill': this.style.titleText.color.value,
50626 })
50627 .call(visuals.tooltipUtils.tooltipUpdate, [startText]);
50628 if (endValue == null) {
50629 textElementUpdate.text(endText).call(visuals.tooltipUtils.tooltipUpdate, [endText]);
50630 }
50631 else if (metaDataColumn && visuals.AxisHelper.isDateTime(metaDataColumn.type)) {
50632 textElementUpdate.text(endText).call(visuals.tooltipUtils.tooltipUpdate, [endText]);
50633 }
50634 else {
50635 var interpolatedValue_1 = startValue;
50636 textElementUpdate
50637 .transition()
50638 .duration(duration)
50639 .tween('text', function (d) {
50640 var i = d3.interpolate(interpolatedValue_1, d);
50641 return function (t) {
50642 var num = i(t);
50643 this.textContent = formatter.format(num);
50644 };
50645 });
50646 }
50647 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(animationOptions);
50648 };
50649 AnimatedText.prototype.setTextColor = function (color) {
50650 this.style.titleText.color.value = color;
50651 };
50652 AnimatedText.prototype.getSeedFontHeight = function (boundingWidth, boundingHeight) {
50653 // Simply an estimate - it should eventually be modified based on the actual text length
50654 var estimatedSize = Math.floor(Math.min(boundingWidth, boundingHeight) * 0.75);
50655 var maxFontSize = this.visualConfiguration.maxFontSize;
50656 if (maxFontSize)
50657 return Math.min(maxFontSize, estimatedSize);
50658 return estimatedSize;
50659 };
50660 AnimatedText.prototype.getTranslateX = function (width) {
50661 if (this.visualConfiguration) {
50662 switch (this.visualConfiguration.align) {
50663 case 'left':
50664 return 0;
50665 case 'right':
50666 return width;
50667 }
50668 }
50669 return width / 2;
50670 };
50671 AnimatedText.prototype.getTranslateY = function (height) {
50672 return height;
50673 };
50674 AnimatedText.prototype.getTextAnchor = function () {
50675 if (this.visualConfiguration) {
50676 switch (this.visualConfiguration.align) {
50677 case 'left':
50678 return 'start';
50679 case 'right':
50680 return 'end';
50681 }
50682 }
50683 return 'middle';
50684 };
50685 AnimatedText.prototype.getFormatString = function (column) {
50686 debug.assertAnyValue(column, 'column');
50687 return visuals.valueFormatter.getFormatString(column, AnimatedText.formatStringProp);
50688 };
50689 /** Note: Public for testability */
50690 AnimatedText.formatStringProp = {
50691 objectName: 'general',
50692 propertyName: 'formatString',
50693 };
50694 return AnimatedText;
50695 }());
50696 visuals.AnimatedText = AnimatedText;
50697 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
50698})(powerbi || (powerbi = {}));
50699/*
50700 * Power BI Visualizations
50701 *
50702 * Copyright (c) Microsoft Corporation
50703 * All rights reserved.
50704 * MIT License
50705 *
50706 * Permission is hereby granted, free of charge, to any person obtaining a copy
50707 * of this software and associated documentation files (the ""Software""), to deal
50708 * in the Software without restriction, including without limitation the rights
50709 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50710 * copies of the Software, and to permit persons to whom the Software is
50711 * furnished to do so, subject to the following conditions:
50712 *
50713 * The above copyright notice and this permission notice shall be included in
50714 * all copies or substantial portions of the Software.
50715 *
50716 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50717 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50718 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50719 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50720 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50721 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50722 * THE SOFTWARE.
50723 */
50724var powerbi;
50725(function (powerbi) {
50726 var visuals;
50727 (function (visuals) {
50728 /**
50729 * Renders a number that can be animate change in value.
50730 */
50731 var AnimatedNumber = (function (_super) {
50732 __extends(AnimatedNumber, _super);
50733 function AnimatedNumber(svg, animator) {
50734 _super.call(this, 'animatedNumber');
50735 if (svg)
50736 this.svg = svg;
50737 if (animator)
50738 this.animator = animator;
50739 }
50740 AnimatedNumber.prototype.init = function (options) {
50741 this.options = options;
50742 var element = options.element;
50743 if (!this.svg)
50744 this.svg = d3.select(element.get(0)).append('svg');
50745 this.currentViewport = options.viewport;
50746 this.hostServices = options.host;
50747 this.style = options.style;
50748 this.updateViewportDependantProperties();
50749 };
50750 AnimatedNumber.prototype.updateViewportDependantProperties = function () {
50751 var viewport = this.currentViewport;
50752 this.svg.attr('width', viewport.width)
50753 .attr('height', viewport.height);
50754 };
50755 AnimatedNumber.prototype.update = function (options) {
50756 debug.assertValue(options, 'options');
50757 this.currentViewport = options.viewport;
50758 var dataViews = this.dataViews = options.dataViews;
50759 if (!dataViews || !dataViews[0]) {
50760 return;
50761 }
50762 var dataView = dataViews[0];
50763 this.updateViewportDependantProperties();
50764 this.getMetaDataColumn(dataView);
50765 var newValue = dataView && dataView.single ? dataView.single.value : 0;
50766 if (newValue != null) {
50767 this.updateInternal(newValue, options.suppressAnimations, true, this.formatter);
50768 }
50769 };
50770 AnimatedNumber.prototype.setFormatter = function (formatter) {
50771 this.formatter = formatter;
50772 };
50773 AnimatedNumber.prototype.onDataChanged = function (options) {
50774 // TODO: Remove onDataChanged & onResizing once all visuals have implemented update.
50775 this.update({
50776 dataViews: options.dataViews,
50777 suppressAnimations: options.suppressAnimations,
50778 viewport: this.currentViewport
50779 });
50780 };
50781 AnimatedNumber.prototype.onResizing = function (viewport) {
50782 // TODO: Remove onDataChanged & onResizing once all visuals have implemented update.
50783 this.update({
50784 dataViews: this.dataViews,
50785 suppressAnimations: true,
50786 viewport: viewport
50787 });
50788 };
50789 AnimatedNumber.prototype.canResizeTo = function (viewport) {
50790 // Temporarily disabling resize restriction.
50791 return true;
50792 };
50793 AnimatedNumber.prototype.updateInternal = function (target, suppressAnimations, forceUpdate, formatter) {
50794 if (forceUpdate === void 0) { forceUpdate = false; }
50795 var start = this.value || 0;
50796 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
50797 this.doValueTransition(start, target,
50798 /*displayUnitSystemType*/ null, this.options.animation, duration, forceUpdate, formatter);
50799 this.value = target;
50800 };
50801 return AnimatedNumber;
50802 }(visuals.AnimatedText));
50803 visuals.AnimatedNumber = AnimatedNumber;
50804 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
50805})(powerbi || (powerbi = {}));
50806/*
50807 * Power BI Visualizations
50808 *
50809 * Copyright (c) Microsoft Corporation
50810 * All rights reserved.
50811 * MIT License
50812 *
50813 * Permission is hereby granted, free of charge, to any person obtaining a copy
50814 * of this software and associated documentation files (the ""Software""), to deal
50815 * in the Software without restriction, including without limitation the rights
50816 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50817 * copies of the Software, and to permit persons to whom the Software is
50818 * furnished to do so, subject to the following conditions:
50819 *
50820 * The above copyright notice and this permission notice shall be included in
50821 * all copies or substantial portions of the Software.
50822 *
50823 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50824 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50825 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50826 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50827 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50828 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50829 * THE SOFTWARE.
50830 */
50831var powerbi;
50832(function (powerbi) {
50833 var visuals;
50834 (function (visuals) {
50835 var BasicShapeVisual = (function () {
50836 function BasicShapeVisual(options) {
50837 }
50838 Object.defineProperty(BasicShapeVisual.prototype, "shapeType", {
50839 /**property for the shape line color */
50840 get: function () {
50841 return this.data ? this.data.shapeType : BasicShapeVisual.DefaultShape;
50842 },
50843 set: function (shapeType) {
50844 this.data.shapeType = shapeType;
50845 },
50846 enumerable: true,
50847 configurable: true
50848 });
50849 Object.defineProperty(BasicShapeVisual.prototype, "lineColor", {
50850 /**property for the shape line color */
50851 get: function () {
50852 return this.data ? this.data.lineColor : BasicShapeVisual.DefaultStrokeColor;
50853 },
50854 set: function (color) {
50855 this.data.lineColor = color;
50856 },
50857 enumerable: true,
50858 configurable: true
50859 });
50860 Object.defineProperty(BasicShapeVisual.prototype, "lineTransparency", {
50861 /**property for the shape line transparency */
50862 get: function () {
50863 return this.data ? this.data.lineTransparency : BasicShapeVisual.DefaultLineTransValue;
50864 },
50865 set: function (trans) {
50866 this.data.lineTransparency = trans;
50867 },
50868 enumerable: true,
50869 configurable: true
50870 });
50871 Object.defineProperty(BasicShapeVisual.prototype, "lineWeight", {
50872 /**property for the shape line weight */
50873 get: function () {
50874 return this.data ? this.data.lineWeight : BasicShapeVisual.DefaultWeightValue;
50875 },
50876 set: function (weight) {
50877 this.data.lineWeight = weight;
50878 },
50879 enumerable: true,
50880 configurable: true
50881 });
50882 Object.defineProperty(BasicShapeVisual.prototype, "roundEdge", {
50883 /**property for the shape round edge */
50884 get: function () {
50885 return this.data ? this.data.roundEdge : BasicShapeVisual.DefaultRoundEdgeValue;
50886 },
50887 set: function (roundEdge) {
50888 this.data.roundEdge = roundEdge;
50889 },
50890 enumerable: true,
50891 configurable: true
50892 });
50893 Object.defineProperty(BasicShapeVisual.prototype, "showFill", {
50894 /**property for showing the fill properties */
50895 get: function () {
50896 return this.data ? this.data.showFill : BasicShapeVisual.DefaultFillShowValue;
50897 },
50898 set: function (show) {
50899 this.data.showFill = show;
50900 },
50901 enumerable: true,
50902 configurable: true
50903 });
50904 Object.defineProperty(BasicShapeVisual.prototype, "fillColor", {
50905 /**property for the shape line color */
50906 get: function () {
50907 return this.data ? this.data.fillColor : BasicShapeVisual.DefaultFillColor;
50908 },
50909 set: function (color) {
50910 this.data.fillColor = color;
50911 },
50912 enumerable: true,
50913 configurable: true
50914 });
50915 Object.defineProperty(BasicShapeVisual.prototype, "shapeTransparency", {
50916 /**property for the shape fill transparency */
50917 get: function () {
50918 return this.data ? this.data.shapeTransparency : BasicShapeVisual.DefaultFillTransValue;
50919 },
50920 set: function (trans) {
50921 this.data.shapeTransparency = trans;
50922 },
50923 enumerable: true,
50924 configurable: true
50925 });
50926 Object.defineProperty(BasicShapeVisual.prototype, "angle", {
50927 /**property for the shape angle */
50928 get: function () {
50929 return this.data ? this.data.angle : BasicShapeVisual.DefaultAngle;
50930 },
50931 set: function (angle) {
50932 this.data.angle = this.scaleTo360Deg(angle);
50933 },
50934 enumerable: true,
50935 configurable: true
50936 });
50937 BasicShapeVisual.prototype.init = function (options) {
50938 this.element = options.element;
50939 this.selection = d3.select(this.element.context);
50940 this.currentViewport = options.viewport;
50941 };
50942 BasicShapeVisual.prototype.update = function (options) {
50943 debug.assertValue(options, 'options');
50944 this.currentViewport = options.viewport;
50945 var dataViews = options.dataViews;
50946 if (!_.isEmpty(dataViews)) {
50947 var dataView = options.dataViews[0];
50948 if (dataView.metadata && dataView.metadata.objects) {
50949 var dataViewObject = options.dataViews[0].metadata.objects;
50950 this.data = this.getDataFromDataView(dataViewObject);
50951 }
50952 }
50953 this.render();
50954 };
50955 BasicShapeVisual.prototype.getDataFromDataView = function (dataViewObject) {
50956 if (dataViewObject) {
50957 return {
50958 shapeType: powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.general.shapeType, BasicShapeVisual.DefaultShape),
50959 lineColor: this.getValueFromColor(powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.line.lineColor, BasicShapeVisual.DefaultStrokeColor)),
50960 lineTransparency: powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.line.transparency, BasicShapeVisual.DefaultLineTransValue),
50961 lineWeight: powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.line.weight, BasicShapeVisual.DefaultWeightValue),
50962 roundEdge: powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.line.roundEdge, BasicShapeVisual.DefaultRoundEdgeValue),
50963 shapeTransparency: powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.fill.transparency, BasicShapeVisual.DefaultFillTransValue),
50964 fillColor: this.getValueFromColor(powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.fill.fillColor, BasicShapeVisual.DefaultFillColor)),
50965 showFill: powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.fill.show, BasicShapeVisual.DefaultFillShowValue),
50966 angle: this.scaleTo360Deg(powerbi.DataViewObjects.getValue(dataViewObject, visuals.basicShapeProps.rotation.angle, BasicShapeVisual.DefaultAngle))
50967 };
50968 }
50969 return null;
50970 };
50971 BasicShapeVisual.prototype.scaleTo360Deg = function (angle) {
50972 if (angle !== 0 && (Math.abs(angle) % 360) === 0)
50973 return angle;
50974 angle = angle % 360;
50975 angle = (angle + 360) % 360;
50976 return angle;
50977 };
50978 BasicShapeVisual.prototype.getValueFromColor = function (color) {
50979 return color.solid ? color.solid.color : color;
50980 };
50981 BasicShapeVisual.prototype.enumerateObjectInstances = function (options) {
50982 var objectInstances = [];
50983 switch (options.objectName) {
50984 case 'line':
50985 var instance = {
50986 selector: null,
50987 properties: {
50988 lineColor: this.lineColor,
50989 transparency: this.lineTransparency,
50990 weight: this.lineWeight
50991 },
50992 objectName: options.objectName
50993 };
50994 if (this.data.shapeType === visuals.basicShapeType.rectangle) {
50995 instance.properties['roundEdge'] = this.roundEdge;
50996 }
50997 objectInstances.push(instance);
50998 return objectInstances;
50999 case 'fill':
51000 if (this.shapeType !== visuals.basicShapeType.line) {
51001 objectInstances.push({
51002 selector: null,
51003 properties: {
51004 show: this.showFill,
51005 fillColor: this.fillColor,
51006 transparency: this.shapeTransparency
51007 },
51008 objectName: options.objectName
51009 });
51010 }
51011 return objectInstances;
51012 case 'rotation':
51013 objectInstances.push({
51014 selector: null,
51015 properties: {
51016 angle: this.angle
51017 },
51018 objectName: options.objectName
51019 });
51020 return objectInstances;
51021 }
51022 return null;
51023 };
51024 BasicShapeVisual.prototype.render = function () {
51025 this.selection.html('');
51026 switch (this.shapeType) {
51027 case visuals.basicShapeType.rectangle:
51028 visuals.ShapeFactory.createRectangle(this.data, this.currentViewport.height, this.currentViewport.width, this.selection, this.angle);
51029 break;
51030 case visuals.basicShapeType.oval:
51031 visuals.ShapeFactory.createOval(this.data, this.currentViewport.height, this.currentViewport.width, this.selection, this.angle);
51032 break;
51033 case visuals.basicShapeType.line:
51034 visuals.ShapeFactory.createLine(this.data, this.currentViewport.height, this.currentViewport.width, this.selection, this.angle);
51035 break;
51036 case visuals.basicShapeType.arrow:
51037 visuals.ShapeFactory.createUpArrow(this.data, this.currentViewport.height, this.currentViewport.width, this.selection, this.angle);
51038 break;
51039 case visuals.basicShapeType.triangle:
51040 visuals.ShapeFactory.createTriangle(this.data, this.currentViewport.height, this.currentViewport.width, this.selection, this.angle);
51041 break;
51042 default:
51043 break;
51044 }
51045 };
51046 BasicShapeVisual.DefaultShape = visuals.basicShapeType.rectangle;
51047 BasicShapeVisual.DefaultStrokeColor = '#00B8AA';
51048 BasicShapeVisual.DefaultFillColor = '#E6E6E6';
51049 BasicShapeVisual.DefaultFillShowValue = true;
51050 BasicShapeVisual.DefaultFillTransValue = 0;
51051 BasicShapeVisual.DefaultWeightValue = 3;
51052 BasicShapeVisual.DefaultLineTransValue = 0;
51053 BasicShapeVisual.DefaultRoundEdgeValue = 0;
51054 BasicShapeVisual.DefaultAngle = 0;
51055 return BasicShapeVisual;
51056 }());
51057 visuals.BasicShapeVisual = BasicShapeVisual;
51058 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
51059})(powerbi || (powerbi = {}));
51060/*
51061 * Power BI Visualizations
51062 *
51063 * Copyright (c) Microsoft Corporation
51064 * All rights reserved.
51065 * MIT License
51066 *
51067 * Permission is hereby granted, free of charge, to any person obtaining a copy
51068 * of this software and associated documentation files (the ""Software""), to deal
51069 * in the Software without restriction, including without limitation the rights
51070 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51071 * copies of the Software, and to permit persons to whom the Software is
51072 * furnished to do so, subject to the following conditions:
51073 *
51074 * The above copyright notice and this permission notice shall be included in
51075 * all copies or substantial portions of the Software.
51076 *
51077 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51078 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51079 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51080 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51081 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51082 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51083 * THE SOFTWARE.
51084 */
51085var powerbi;
51086(function (powerbi) {
51087 var visuals;
51088 (function (visuals) {
51089 var EnumExtensions = jsCommon.EnumExtensions;
51090 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
51091 var DEFAULT_AXIS_SCALE_TYPE = visuals.axisScale.linear;
51092 var COMBOCHART_DOMAIN_OVERLAP_TRESHOLD_PERCENTAGE = 0.1;
51093 // the interactive right margin is set to be the circle selection radius of the hover line
51094 var INTERACTIVITY_RIGHT_MARGIN = 6;
51095 visuals.DEFAULT_AXIS_COLOR = '#777';
51096 /**
51097 * Renders a data series as a cartestian visual.
51098 */
51099 var CartesianChart = (function () {
51100 function CartesianChart(options) {
51101 this.xRefLine = createClassAndSelector('x-ref-line');
51102 this.y1RefLine = createClassAndSelector('y1-ref-line');
51103 var isScrollable = false;
51104 this.trimOrdinalDataOnOverflow = true;
51105 if (options) {
51106 this.tooltipsEnabled = options.tooltipsEnabled;
51107 this.type = options.chartType;
51108 this.isLabelInteractivityEnabled = options.isLabelInteractivityEnabled;
51109 this.lineChartLabelDensityEnabled = options.lineChartLabelDensityEnabled;
51110 if (options.trimOrdinalDataOnOverflow !== undefined)
51111 this.trimOrdinalDataOnOverflow = options.trimOrdinalDataOnOverflow;
51112 if (options.isScrollable)
51113 isScrollable = options.isScrollable;
51114 this.animator = options.animator;
51115 if (options.cartesianSmallViewPortProperties) {
51116 this.cartesianSmallViewPortProperties = options.cartesianSmallViewPortProperties;
51117 }
51118 if (options.behavior) {
51119 this.behavior = options.behavior;
51120 }
51121 }
51122 this.axes = new CartesianAxes(isScrollable, ScrollableAxes.ScrollbarWidth, this.trimOrdinalDataOnOverflow);
51123 this.svgAxes = new SvgCartesianAxes(this.axes);
51124 this.svgBrush = new SvgBrush(ScrollableAxes.ScrollbarWidth);
51125 this.scrollableAxes = new ScrollableAxes(this.axes, this.svgBrush);
51126 }
51127 CartesianChart.getAxisVisibility = function (type) {
51128 switch (type) {
51129 case 6 /* StackedBar */:
51130 case 5 /* ClusteredBar */:
51131 case 7 /* HundredPercentStackedBar */:
51132 return 1 /* ShowLinesOnXAxis */;
51133 case 9 /* Scatter */:
51134 return 3 /* ShowLinesOnBothAxis */;
51135 default:
51136 return 2 /* ShowLinesOnYAxis */;
51137 }
51138 };
51139 CartesianChart.prototype.init = function (options) {
51140 this.visualInitOptions = options;
51141 this.layers = [];
51142 var element = this.element = options.element;
51143 this.currentViewport = options.viewport;
51144 this.hostServices = options.host;
51145 var chartAreaSvg = this.chartAreaSvg = d3.select(element.get(0)).append('svg');
51146 chartAreaSvg.classed(CartesianChart.ClassName, true);
51147 chartAreaSvg.style('position', 'absolute');
51148 if (this.behavior) {
51149 this.clearCatcher = visuals.appendClearCatcher(chartAreaSvg);
51150 this.interactivityService = visuals.createInteractivityService(this.hostServices);
51151 }
51152 if (options.style.maxMarginFactor != null)
51153 this.axes.setMaxMarginFactor(options.style.maxMarginFactor);
51154 var axisLinesVisibility = CartesianChart.getAxisVisibility(this.type);
51155 this.axes.setAxisLinesVisibility(axisLinesVisibility);
51156 this.svgAxes.init(chartAreaSvg);
51157 this.svgBrush.init(chartAreaSvg);
51158 this.sharedColorPalette = new SharedColorPalette(options.style.colorPalette.dataColors);
51159 this.legend = visuals.createLegend(element, options.interactivity && options.interactivity.isInteractiveLegend, this.type !== 12 /* Waterfall */ ? this.interactivityService : undefined, this.axes.isScrollable);
51160 this.isMobileChart = options.interactivity && options.interactivity.isInteractiveLegend;
51161 };
51162 CartesianChart.prototype.isPlayAxis = function () {
51163 if (!this.dataViews || !this.dataViews[0])
51164 return false;
51165 var dataView = this.dataViews[0];
51166 var categoryRoleIsPlay = dataView.categorical
51167 && dataView.categorical.categories
51168 && dataView.categorical.categories[0]
51169 && dataView.categorical.categories[0].source
51170 && dataView.categorical.categories[0].source.roles
51171 && dataView.categorical.categories[0].source.roles['Play'];
51172 return this.type === 9 /* Scatter */
51173 && (this.animator || this.isMobileChart)
51174 && dataView.matrix != null
51175 && (!dataView.categorical || categoryRoleIsPlay);
51176 };
51177 CartesianChart.getIsScalar = function (objects, propertyId, type) {
51178 var axisTypeValue = powerbi.DataViewObjects.getValue(objects, propertyId);
51179 if (!objects || axisTypeValue === undefined) {
51180 // If we don't have anything set (Auto), show charts as Scalar if the category type is numeric or time.
51181 // If we have the property, it will override the type.
51182 return !visuals.AxisHelper.isOrdinal(type);
51183 }
51184 // also checking type here to be in sync with AxisHelper, which ignores scalar if the type is non-numeric.
51185 return (axisTypeValue === visuals.axisType.scalar) && !visuals.AxisHelper.isOrdinal(type);
51186 };
51187 CartesianChart.getAdditionalTelemetry = function (dataView) {
51188 var telemetry = {};
51189 var categoryColumn = dataView && dataView.categorical && _.first(dataView.categorical.categories);
51190 if (categoryColumn) {
51191 telemetry.axisType = visuals.CartesianChart.getIsScalar(dataView.metadata.objects, visuals.columnChartProps.categoryAxis.axisType, categoryColumn.source.type)
51192 ? 'scalar'
51193 : 'categorical';
51194 }
51195 return telemetry;
51196 };
51197 CartesianChart.detectScalarMapping = function (dataViewMapping) {
51198 if (!dataViewMapping || !dataViewMapping.categorical || !dataViewMapping.categorical.categories)
51199 return false;
51200 var dataViewCategories = dataViewMapping.categorical.categories;
51201 var categoryItems = dataViewCategories.for.in.items;
51202 if (_.isEmpty(categoryItems))
51203 return false;
51204 var categoryType = categoryItems[0].type;
51205 if (!dataViewMapping.metadata)
51206 return false;
51207 var objects = dataViewMapping.metadata.objects;
51208 return CartesianChart.getIsScalar(objects, visuals.columnChartProps.categoryAxis.axisType, categoryType);
51209 };
51210 CartesianChart.prototype.populateObjectProperties = function (dataViews) {
51211 if (dataViews && dataViews.length > 0) {
51212 var dataViewMetadata = dataViews[0].metadata;
51213 if (dataViewMetadata) {
51214 this.legendObjectProperties = powerbi.DataViewObjects.getObject(dataViewMetadata.objects, 'legend', {});
51215 this.xAxisReferenceLines = powerbi.DataViewObjects.getUserDefinedObjects(dataViewMetadata.objects, 'xAxisReferenceLine');
51216 this.y1AxisReferenceLines = powerbi.DataViewObjects.getUserDefinedObjects(dataViewMetadata.objects, 'y1AxisReferenceLine');
51217 }
51218 else {
51219 this.legendObjectProperties = {};
51220 }
51221 this.categoryAxisProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataViewMetadata);
51222 this.valueAxisProperties = visuals.CartesianHelper.getValueAxisProperties(dataViewMetadata);
51223 }
51224 };
51225 CartesianChart.prototype.updateInternal = function (options, dataChanged) {
51226 var dataViews = this.dataViews = options.dataViews;
51227 this.currentViewport = options.viewport;
51228 if (!dataViews)
51229 return;
51230 if (this.layers.length === 0) {
51231 // Lazily instantiate the chart layers on the first data load.
51232 var objects = this.extractMetadataObjects(dataViews);
51233 this.layers = this.createAndInitLayers(objects);
51234 debug.assert(this.layers.length > 0, 'createAndInitLayers should update the layers.');
51235 }
51236 var layers = this.layers;
51237 if (dataChanged) {
51238 if (!_.isEmpty(dataViews)) {
51239 this.populateObjectProperties(dataViews);
51240 this.axes.update(dataViews);
51241 this.svgAxes.update(this.categoryAxisProperties, this.valueAxisProperties);
51242 var dataView = dataViews[0];
51243 if (dataView.metadata) {
51244 // flatten background data
51245 this.background = {
51246 image: powerbi.DataViewObjects.getValue(dataView.metadata.objects, visuals.scatterChartProps.plotArea.image),
51247 transparency: powerbi.DataViewObjects.getValue(dataView.metadata.objects, visuals.scatterChartProps.plotArea.transparency, visuals.visualBackgroundHelper.getDefaultTransparency()),
51248 };
51249 }
51250 }
51251 this.sharedColorPalette.clearPreferredScale();
51252 var layerDataViews = getLayerDataViews(dataViews);
51253 var trendLineDataViews = _.filter(dataViews, function (dataView) { return visuals.TrendLineHelper.isDataViewForRegression(dataView); });
51254 this.trendLines = [];
51255 for (var i = 0, layerCount = layers.length; i < layerCount; i++) {
51256 var layerDataView = layerDataViews[i];
51257 layers[i].setData(layerDataView ? [layerDataView] : []);
51258 if (this.supportsTrendLines(i)) {
51259 var trendLineDataView = trendLineDataViews[i];
51260 if (trendLineDataView) {
51261 var y2 = (i > 0);
51262 var trendLines = visuals.TrendLineHelper.readDataView(trendLineDataView, layerDataView, y2, this.sharedColorPalette);
51263 (_a = this.trendLines).push.apply(_a, trendLines);
51264 }
51265 }
51266 if (layerCount > 1)
51267 this.sharedColorPalette.rotateScale();
51268 }
51269 }
51270 this.render(!this.hasSetData || options.suppressAnimations, options.resizeMode);
51271 this.hasSetData = this.hasSetData || (dataViews && dataViews.length > 0);
51272 if (dataViews && dataViews.length > 0) {
51273 var warnings = visuals.getInvalidValueWarnings(dataViews, false /*supportsNaN*/, false /*supportsNegativeInfinity*/, false /*supportsPositiveInfinity*/);
51274 this.axes.addWarnings(warnings);
51275 if (warnings && warnings.length > 0)
51276 this.hostServices.setWarnings(warnings);
51277 }
51278 var _a;
51279 };
51280 // TODO: Remove onDataChanged & onResizing once we have a flag to distinguish between resize and data changed events.
51281 CartesianChart.prototype.onDataChanged = function (options) {
51282 this.updateInternal({
51283 dataViews: options.dataViews,
51284 suppressAnimations: options.suppressAnimations,
51285 viewport: this.currentViewport
51286 }, true);
51287 };
51288 // TODO: Remove onDataChanged & onResizing once we have a flag to distinguish between resize and data changed events.
51289 CartesianChart.prototype.onResizing = function (viewport, resizeMode) {
51290 this.updateInternal({
51291 dataViews: this.dataViews,
51292 suppressAnimations: true,
51293 viewport: viewport,
51294 resizeMode: resizeMode,
51295 }, false);
51296 };
51297 CartesianChart.prototype.scrollTo = function (position) {
51298 this.scrollableAxes.scrollTo(position);
51299 };
51300 CartesianChart.prototype.enumerateObjectInstances = function (options) {
51301 var enumeration = new visuals.ObjectEnumerationBuilder();
51302 var layersLength = this.layers ? this.layers.length : 0;
51303 if (options.objectName === 'legend') {
51304 if (!this.shouldShowLegendCard())
51305 return;
51306 var show = powerbi.DataViewObject.getValue(this.legendObjectProperties, visuals.legendProps.show, this.legend.isVisible());
51307 var showTitle = powerbi.DataViewObject.getValue(this.legendObjectProperties, visuals.legendProps.showTitle, true);
51308 var titleText = powerbi.DataViewObject.getValue(this.legendObjectProperties, visuals.legendProps.titleText, this.layerLegendData ? this.layerLegendData.title : '');
51309 var labelColor = powerbi.DataViewObject.getValue(this.legendObjectProperties, visuals.legendProps.labelColor, visuals.LegendData.DefaultLegendLabelFillColor);
51310 var fontSize = powerbi.DataViewObject.getValue(this.legendObjectProperties, visuals.legendProps.fontSize, this.layerLegendData && this.layerLegendData.fontSize ? this.layerLegendData.fontSize : visuals.SVGLegend.DefaultFontSizeInPt);
51311 enumeration.pushInstance({
51312 selector: null,
51313 properties: {
51314 show: show,
51315 position: visuals.LegendPosition[this.legend.getOrientation()],
51316 showTitle: showTitle,
51317 titleText: titleText,
51318 labelColor: labelColor,
51319 fontSize: fontSize,
51320 },
51321 objectName: options.objectName
51322 });
51323 }
51324 else if (options.objectName === 'categoryAxis' && this.axes.hasCategoryAxis()) {
51325 this.getCategoryAxisValues(enumeration);
51326 }
51327 else if (options.objectName === 'valueAxis') {
51328 this.getValueAxisValues(enumeration);
51329 }
51330 else if (options.objectName === 'y1AxisReferenceLine') {
51331 var refLinedefaultColor = this.sharedColorPalette.getColorByIndex(0).value;
51332 visuals.ReferenceLineHelper.enumerateObjectInstances(enumeration, this.y1AxisReferenceLines, refLinedefaultColor, options.objectName);
51333 }
51334 else if (options.objectName === 'xAxisReferenceLine') {
51335 var refLinedefaultColor = this.sharedColorPalette.getColorByIndex(0).value;
51336 visuals.ReferenceLineHelper.enumerateObjectInstances(enumeration, this.xAxisReferenceLines, refLinedefaultColor, options.objectName);
51337 }
51338 else if (options.objectName === 'trend') {
51339 if (this.supportsTrendLines()) {
51340 visuals.TrendLineHelper.enumerateObjectInstances(enumeration, this.trendLines);
51341 }
51342 }
51343 else if (options.objectName === 'plotArea') {
51344 visuals.visualBackgroundHelper.enumeratePlot(enumeration, this.background);
51345 }
51346 if (options.objectName === 'dataPoint' &&
51347 visuals.ComboChart.isComboChart(this.type)) {
51348 visuals.ComboChart.enumerateDataPoints(enumeration, options, this.layers);
51349 }
51350 else {
51351 for (var i = 0, len = layersLength; i < len; i++) {
51352 var layer = this.layers[i];
51353 if (layer.enumerateObjectInstances) {
51354 layer.enumerateObjectInstances(enumeration, options);
51355 }
51356 }
51357 }
51358 return enumeration.complete();
51359 };
51360 CartesianChart.prototype.supportsTrendLines = function (layerIndex) {
51361 var layerDataViews = getLayerDataViews(this.dataViews);
51362 if (_.isEmpty(this.layers))
51363 return false;
51364 // If layerIndex was not given then check all layers.
51365 var layers = layerIndex == null ? this.layers : [this.layers[layerIndex]];
51366 return _.all(layers, function (layer, index) {
51367 if (!layerDataViews[index])
51368 return true;
51369 return layer.supportsTrendLine && layer.supportsTrendLine();
51370 });
51371 };
51372 CartesianChart.prototype.shouldShowLegendCard = function () {
51373 var layers = this.layers;
51374 var dataViews = this.dataViews;
51375 if (layers && dataViews) {
51376 var layersLength = layers.length;
51377 var layersWithValuesCtr = 0;
51378 for (var i = 0; i < layersLength; i++) {
51379 if (layers[i].hasLegend()) {
51380 return true;
51381 }
51382 // if there are at least two layers with values legend card should be shown (even if each of the individual layers don't have legend)
51383 var dataView = dataViews[i];
51384 if (dataView && dataView.categorical && dataView.categorical.values && dataView.categorical.values.length > 0) {
51385 layersWithValuesCtr++;
51386 if (layersWithValuesCtr > 1) {
51387 return true;
51388 }
51389 }
51390 }
51391 }
51392 return false;
51393 };
51394 CartesianChart.prototype.getAxisScaleOptions = function (axisType) {
51395 var scaleOptions = [DEFAULT_AXIS_SCALE_TYPE];
51396 if (this.axes.isLogScaleAllowed(axisType))
51397 scaleOptions.push(visuals.axisScale.log);
51398 return scaleOptions;
51399 };
51400 CartesianChart.prototype.getCategoryAxisValues = function (enumeration) {
51401 if (!this.categoryAxisProperties) {
51402 return;
51403 }
51404 var supportedType = visuals.axisType.both;
51405 var isScalar = false;
51406 var scaleOptions = this.getAxisScaleOptions(0 /* X */);
51407 if (this.layers && this.layers[0].getSupportedCategoryAxisType) {
51408 supportedType = this.layers[0].getSupportedCategoryAxisType();
51409 if (supportedType === visuals.axisType.scalar) {
51410 isScalar = true;
51411 }
51412 else {
51413 isScalar = visuals.CartesianHelper.isScalar(supportedType === visuals.axisType.both, this.categoryAxisProperties);
51414 }
51415 }
51416 if (!isScalar) {
51417 this.categoryAxisProperties['start'] = null;
51418 this.categoryAxisProperties['end'] = null;
51419 }
51420 var instance = {
51421 selector: null,
51422 properties: {},
51423 objectName: 'categoryAxis',
51424 validValues: {
51425 axisScale: scaleOptions,
51426 axisStyle: this.axes.categoryAxisHasUnitType ? [visuals.axisStyle.showTitleOnly, visuals.axisStyle.showUnitOnly, visuals.axisStyle.showBoth] : [visuals.axisStyle.showTitleOnly]
51427 }
51428 };
51429 instance.properties['show'] = this.categoryAxisProperties['show'] != null ? this.categoryAxisProperties['show'] : true;
51430 if (this.axes.isYAxisCategorical())
51431 instance.properties['position'] = this.valueAxisProperties && this.valueAxisProperties['position'] != null ? this.valueAxisProperties['position'] : visuals.yAxisPosition.left;
51432 if (supportedType === visuals.axisType.both) {
51433 instance.properties['axisType'] = isScalar ? visuals.axisType.scalar : visuals.axisType.categorical;
51434 }
51435 if (isScalar) {
51436 instance.properties['axisScale'] = this.categoryAxisProperties['axisScale'] || DEFAULT_AXIS_SCALE_TYPE;
51437 instance.properties['start'] = this.categoryAxisProperties['start'];
51438 instance.properties['end'] = this.categoryAxisProperties['end'];
51439 }
51440 instance.properties['showAxisTitle'] = this.categoryAxisProperties['showAxisTitle'] != null ? this.categoryAxisProperties['showAxisTitle'] : false;
51441 instance.properties['axisStyle'] = this.categoryAxisProperties['axisStyle'] ? this.categoryAxisProperties['axisStyle'] : visuals.axisStyle.showTitleOnly;
51442 instance.properties['labelColor'] = this.categoryAxisProperties['labelColor'] || visuals.DEFAULT_AXIS_COLOR;
51443 if (isScalar) {
51444 instance.properties['labelDisplayUnits'] = this.categoryAxisProperties['labelDisplayUnits'] ? this.categoryAxisProperties['labelDisplayUnits'] : 0;
51445 var labelPrecision = this.categoryAxisProperties['labelPrecision'];
51446 instance.properties['labelPrecision'] = (labelPrecision === undefined || labelPrecision < 0)
51447 ? visuals.dataLabelUtils.defaultLabelPrecision
51448 : labelPrecision;
51449 }
51450 enumeration.pushInstance(instance);
51451 };
51452 //todo: wrap all these object getters and other related stuff into an interface
51453 CartesianChart.prototype.getValueAxisValues = function (enumeration) {
51454 if (!this.valueAxisProperties) {
51455 return;
51456 }
51457 var scaleOptions = this.getAxisScaleOptions(1 /* Y1 */);
51458 var secScaleOption = this.getAxisScaleOptions(2 /* Y2 */);
51459 var instance = {
51460 selector: null,
51461 properties: {},
51462 objectName: 'valueAxis',
51463 validValues: {
51464 axisScale: scaleOptions,
51465 secAxisScale: secScaleOption,
51466 axisStyle: this.axes.valueAxisHasUnitType ? [visuals.axisStyle.showTitleOnly, visuals.axisStyle.showUnitOnly, visuals.axisStyle.showBoth] : [visuals.axisStyle.showTitleOnly]
51467 }
51468 };
51469 instance.properties['show'] = this.valueAxisProperties['show'] != null ? this.valueAxisProperties['show'] : true;
51470 if (!this.axes.isYAxisCategorical()) {
51471 instance.properties['position'] = this.valueAxisProperties['position'] != null ? this.valueAxisProperties['position'] : visuals.yAxisPosition.left;
51472 }
51473 instance.properties['axisScale'] = this.valueAxisProperties['axisScale'] || DEFAULT_AXIS_SCALE_TYPE;
51474 instance.properties['start'] = this.valueAxisProperties['start'];
51475 instance.properties['end'] = this.valueAxisProperties['end'];
51476 instance.properties['showAxisTitle'] = this.valueAxisProperties['showAxisTitle'] != null ? this.valueAxisProperties['showAxisTitle'] : false;
51477 instance.properties['axisStyle'] = this.valueAxisProperties['axisStyle'] != null ? this.valueAxisProperties['axisStyle'] : visuals.axisStyle.showTitleOnly;
51478 instance.properties['labelColor'] = this.valueAxisProperties['labelColor'] || visuals.DEFAULT_AXIS_COLOR;
51479 if (this.type !== 7 /* HundredPercentStackedBar */ && this.type !== 8 /* HundredPercentStackedColumn */) {
51480 instance.properties['labelDisplayUnits'] = this.valueAxisProperties['labelDisplayUnits'] ? this.valueAxisProperties['labelDisplayUnits'] : 0;
51481 var labelPrecision = this.valueAxisProperties['labelPrecision'];
51482 instance.properties['labelPrecision'] = (labelPrecision === undefined || labelPrecision < 0)
51483 ? visuals.dataLabelUtils.defaultLabelPrecision
51484 : labelPrecision;
51485 }
51486 enumeration.pushInstance(instance);
51487 if (this.layers.length === 2) {
51488 instance.properties['secShow'] = this.valueAxisProperties['secShow'] != null ? this.valueAxisProperties['secShow'] : this.axes.hasY2Axis();
51489 if (instance.properties['secShow']) {
51490 instance.properties['axisLabel'] = '';
51491 }
51492 }
51493 if (this.axes.hasY2Axis() && instance.properties['secShow']) {
51494 enumeration.pushContainer({
51495 displayName: powerbi.data.createDisplayNameGetter('Visual_YAxis_ShowSecondary'),
51496 });
51497 var secInstance = {
51498 selector: null,
51499 properties: {},
51500 objectName: 'valueAxis'
51501 };
51502 secInstance.properties['secAxisLabel'] = '';
51503 secInstance.properties['secPosition'] = this.valueAxisProperties['secPosition'] != null ? this.valueAxisProperties['secPosition'] : visuals.yAxisPosition.right;
51504 secInstance.properties['secAxisScale'] = this.valueAxisProperties['secAxisScale'] || DEFAULT_AXIS_SCALE_TYPE;
51505 secInstance.properties['secStart'] = this.valueAxisProperties['secStart'];
51506 secInstance.properties['secEnd'] = this.valueAxisProperties['secEnd'];
51507 secInstance.properties['secShowAxisTitle'] = this.valueAxisProperties['secShowAxisTitle'] != null ? this.valueAxisProperties['secShowAxisTitle'] : false;
51508 enumeration
51509 .pushInstance(secInstance)
51510 .pushInstance({
51511 selector: null,
51512 properties: {
51513 secAxisStyle: this.valueAxisProperties['secAxisStyle'] ? this.valueAxisProperties['secAxisStyle'] : visuals.axisStyle.showTitleOnly,
51514 labelColor: this.valueAxisProperties['secLabelColor'],
51515 secLabelDisplayUnits: this.valueAxisProperties['secLabelDisplayUnits'] ? this.valueAxisProperties['secLabelDisplayUnits'] : 0,
51516 secLabelPrecision: this.valueAxisProperties['secLabelPrecision'] < 0 ? 0 : this.valueAxisProperties['secLabelPrecision']
51517 },
51518 objectName: 'valueAxis',
51519 validValues: {
51520 secAxisStyle: this.axes.secondaryValueAxisHasUnitType ? [visuals.axisStyle.showTitleOnly, visuals.axisStyle.showUnitOnly, visuals.axisStyle.showBoth] : [visuals.axisStyle.showTitleOnly],
51521 axisScale: scaleOptions
51522 },
51523 });
51524 enumeration.popContainer();
51525 }
51526 };
51527 CartesianChart.prototype.onClearSelection = function () {
51528 if (this.hasSetData) {
51529 for (var i = 0, len = this.layers.length; i < len; i++) {
51530 var layer = this.layers[i];
51531 layer.onClearSelection();
51532 layer.render(true /* suppressAnimations */);
51533 }
51534 }
51535 };
51536 CartesianChart.prototype.extractMetadataObjects = function (dataViews) {
51537 var objects;
51538 if (dataViews && dataViews.length > 0) {
51539 var dataViewMetadata = dataViews[0].metadata;
51540 if (dataViewMetadata)
51541 objects = dataViewMetadata.objects;
51542 }
51543 return objects;
51544 };
51545 CartesianChart.prototype.createAndInitLayers = function (objects) {
51546 var _this = this;
51547 // Create the layers
51548 var layers = CartesianLayerFactory.createLayers(this.type, objects, this.interactivityService, this.animator, this.axes.isScrollable, this.tooltipsEnabled, this.lineChartLabelDensityEnabled);
51549 // Initialize the layers
51550 var cartesianOptions = powerbi.Prototype.inherit(this.visualInitOptions);
51551 cartesianOptions.svg = this.svgAxes.getScrollableRegion();
51552 cartesianOptions.labelsContext = this.svgAxes.getLabelsRegion();
51553 cartesianOptions.cartesianHost = {
51554 updateLegend: function (data) { return _this.legend.drawLegend(data, _this.currentViewport); },
51555 getSharedColors: function () { return _this.sharedColorPalette; },
51556 triggerRender: function (suppressAnimations) { return _this.render(suppressAnimations); },
51557 };
51558 cartesianOptions.chartType = this.type;
51559 for (var i = 0, len = layers.length; i < len; i++)
51560 layers[i].init(cartesianOptions);
51561 return layers;
51562 };
51563 CartesianChart.prototype.renderLegend = function () {
51564 var layers = this.layers;
51565 var legendData = { title: "", dataPoints: [] };
51566 var _loop_1 = function(i, len) {
51567 this_1.layerLegendData = layers[i].calculateLegend();
51568 if (this_1.layerLegendData) {
51569 legendData.title = i === 0 ? this_1.layerLegendData.title || ""
51570 : legendData.title;
51571 legendData.labelColor = this_1.layerLegendData.labelColor;
51572 // Data points have have duplicate identities (ex. Combo Chart uses a measure in both line and column).
51573 // Add the layer number (if it's set) so the D3 keys are different.
51574 if (!_.isEmpty(this_1.layerLegendData.dataPoints)) {
51575 this_1.layerLegendData.dataPoints.forEach(function (dataPoint) { return dataPoint.layerNumber = i; });
51576 }
51577 legendData.dataPoints = legendData.dataPoints.concat(this_1.layerLegendData.dataPoints || []);
51578 legendData.fontSize = this_1.layerLegendData.fontSize || visuals.SVGLegend.DefaultFontSizeInPt;
51579 if (this_1.layerLegendData.grouped) {
51580 legendData.grouped = true;
51581 }
51582 }
51583 };
51584 var this_1 = this;
51585 for (var i = 0, len = layers.length; i < len; i++) {
51586 _loop_1(i, len);
51587 }
51588 var legendProperties = this.legendObjectProperties;
51589 if (legendProperties) {
51590 visuals.LegendData.update(legendData, legendProperties);
51591 var position = legendProperties[visuals.legendProps.position];
51592 if (position)
51593 this.legend.changeOrientation(visuals.LegendPosition[position]);
51594 }
51595 else {
51596 this.legend.changeOrientation(visuals.LegendPosition.Top);
51597 }
51598 if ((legendData.dataPoints.length === 1 && !legendData.grouped) || this.hideLegends()) {
51599 legendData.dataPoints = [];
51600 }
51601 this.legend.drawLegend(legendData, this.currentViewport);
51602 };
51603 CartesianChart.prototype.hideLegends = function () {
51604 if (this.cartesianSmallViewPortProperties) {
51605 if (this.cartesianSmallViewPortProperties.hideLegendOnSmallViewPort && (this.currentViewport.height < this.cartesianSmallViewPortProperties.MinHeightLegendVisible)) {
51606 return true;
51607 }
51608 }
51609 return false;
51610 };
51611 CartesianChart.prototype.render = function (suppressAnimations, resizeMode) {
51612 var _this = this;
51613 // Note: interactive legend shouldn't be rendered explicitly here
51614 // The interactive legend is being rendered in the render method of ICartesianVisual
51615 if (!(this.visualInitOptions.interactivity && this.visualInitOptions.interactivity.isInteractiveLegend)) {
51616 this.renderLegend();
51617 }
51618 var legendMargins = this.legendMargins = this.legend.getMargins();
51619 var legendOrientation = this.legend.getOrientation();
51620 var hideAxisLabels = this.hideAxisLabels(legendMargins);
51621 var plotAreaViewport = {
51622 height: this.currentViewport.height - legendMargins.height,
51623 width: this.currentViewport.width - legendMargins.width
51624 };
51625 var padding = powerbi.Prototype.inherit(SvgCartesianAxes.AxisPadding);
51626 var playAxisControlLayout;
51627 if (this.isPlayAxis()) {
51628 plotAreaViewport.height -= CartesianChart.PlayAxisBottomMargin;
51629 playAxisControlLayout = {
51630 left: visuals.Legend.isLeft(legendOrientation) ? legendMargins.width : 0,
51631 top: visuals.Legend.isTop(legendOrientation) ? legendMargins.height + plotAreaViewport.height : plotAreaViewport.height,
51632 height: CartesianChart.PlayAxisBottomMargin,
51633 width: plotAreaViewport.width
51634 };
51635 }
51636 this.chartAreaSvg.attr({
51637 'width': plotAreaViewport.width,
51638 'height': plotAreaViewport.height,
51639 });
51640 visuals.Legend.positionChartArea(this.chartAreaSvg, this.legend);
51641 var interactivityRightMargin = this.calculateInteractivityRightMargin();
51642 var _a = this.getMinimumDomainExtents(), ensureXDomain = _a[0], ensureYDomain = _a[1];
51643 var axesLayout = this.axes.negotiateAxes(this.layers, plotAreaViewport, padding, playAxisControlLayout, hideAxisLabels, CartesianChart.AxisTextProperties, interactivityRightMargin, ensureXDomain, ensureYDomain);
51644 // Even if the caller thinks animations are ok, now that we've laid out the axes and legend we should disable animations
51645 // if the plot area changed. Animations for property changes like legend on/off are not desired.
51646 var plotAreaHasChanged = !this.renderedPlotArea
51647 || (this.renderedPlotArea.height !== axesLayout.plotArea.height ||
51648 this.renderedPlotArea.width !== axesLayout.plotArea.width);
51649 suppressAnimations = suppressAnimations || plotAreaHasChanged;
51650 this.scrollableAxes.render(axesLayout, this.layers, suppressAnimations, function (layers, axesLayout, suppressAnimations) { return _this.renderPlotArea(layers, axesLayout, suppressAnimations, legendMargins, resizeMode); });
51651 // attach scroll event
51652 this.chartAreaSvg.on('wheel', function () {
51653 if (!(_this.axes.isXScrollBarVisible || _this.axes.isYScrollBarVisible))
51654 return;
51655 visuals.TooltipManager.ToolTipInstance.hide();
51656 var wheelEvent = d3.event;
51657 var dy = wheelEvent.deltaY;
51658 _this.scrollableAxes.scrollDelta(dy);
51659 });
51660 this.renderedPlotArea = axesLayout.plotArea;
51661 };
51662 /**
51663 * Gets any minimum domain extents.
51664 * Reference lines and trend lines may enforce minimum extents on X and/or Y domains.
51665 */
51666 CartesianChart.prototype.getMinimumDomainExtents = function () {
51667 var xs = [];
51668 var ys = [];
51669 if (!_.isEmpty(this.xAxisReferenceLines)) {
51670 var xAxisReferenceLineProperties = this.xAxisReferenceLines[0].object;
51671 var value = visuals.ReferenceLineHelper.extractReferenceLineValue(xAxisReferenceLineProperties);
51672 xs.push(value);
51673 }
51674 if (!_.isEmpty(this.y1AxisReferenceLines)) {
51675 var y1AxisReferenceLineProperties = this.y1AxisReferenceLines[0].object;
51676 var value = visuals.ReferenceLineHelper.extractReferenceLineValue(y1AxisReferenceLineProperties);
51677 ys.push(value);
51678 }
51679 var ensureXDomain = {
51680 min: d3.min(xs),
51681 max: d3.max(xs)
51682 };
51683 var ensureYDomain = {
51684 min: d3.min(ys),
51685 max: d3.max(ys)
51686 };
51687 return [ensureXDomain, ensureYDomain];
51688 };
51689 CartesianChart.prototype.getPlotAreaRect = function (axesLayout, legendMargins) {
51690 var rect = {
51691 left: axesLayout.margin.left,
51692 top: axesLayout.margin.top,
51693 width: axesLayout.plotArea.width,
51694 height: axesLayout.plotArea.height,
51695 };
51696 // Adjust the margins to the legend position
51697 if (this.legend) {
51698 var legendPosition_1 = this.legend.getOrientation();
51699 if (visuals.Legend.isTop(legendPosition_1)) {
51700 rect.top += legendMargins.height;
51701 }
51702 else if (visuals.Legend.isLeft(legendPosition_1)) {
51703 rect.left += legendMargins.width;
51704 }
51705 }
51706 return rect;
51707 };
51708 CartesianChart.prototype.renderBackgroundImage = function (layout) {
51709 visuals.visualBackgroundHelper.renderBackgroundImage(this.background, this.element, layout);
51710 };
51711 CartesianChart.prototype.hideAxisLabels = function (legendMargins) {
51712 if (this.cartesianSmallViewPortProperties) {
51713 if (this.cartesianSmallViewPortProperties.hideAxesOnSmallViewPort && (this.currentViewport.height < this.cartesianSmallViewPortProperties.MinHeightAxesVisible) && !this.visualInitOptions.interactivity.isInteractiveLegend) {
51714 return true;
51715 }
51716 }
51717 return false;
51718 };
51719 CartesianChart.prototype.calculateInteractivityRightMargin = function () {
51720 // add right margin in order not to cut the circle selection of the hover line
51721 if (this.visualInitOptions.interactivity && this.visualInitOptions.interactivity.isInteractiveLegend && !this.trimOrdinalDataOnOverflow) {
51722 return INTERACTIVITY_RIGHT_MARGIN;
51723 }
51724 else {
51725 return 0;
51726 }
51727 };
51728 CartesianChart.prototype.renderPlotArea = function (layers, axesLayout, suppressAnimations, legendMargins, resizeMode) {
51729 debug.assertValue(layers, 'layers');
51730 var axes = axesLayout.axes;
51731 var plotArea = axesLayout.plotArea;
51732 var plotAreaRect = this.getPlotAreaRect(axesLayout, legendMargins);
51733 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
51734 var easing = this.animator && this.animator.getEasing();
51735 this.renderBackgroundImage(plotAreaRect);
51736 if (!_.isEmpty(easing))
51737 this.svgAxes.renderAxes(axesLayout, duration, easing);
51738 else
51739 this.svgAxes.renderAxes(axesLayout, duration);
51740 this.renderReferenceLines(axesLayout);
51741 this.renderLayers(layers, plotArea, axes, suppressAnimations, resizeMode);
51742 this.renderTrendLines(axesLayout);
51743 };
51744 CartesianChart.prototype.renderTrendLines = function (axesLayout) {
51745 var scrollableRegion = this.svgAxes.getScrollableRegion();
51746 visuals.TrendLineHelper.render(this.trendLines, scrollableRegion, axesLayout.axes, axesLayout.plotArea);
51747 };
51748 CartesianChart.prototype.renderReferenceLines = function (axesLayout) {
51749 var axes = axesLayout.axes;
51750 var plotArea = axesLayout.plotArea;
51751 var scrollableRegion = this.svgAxes.getScrollableRegion();
51752 var refLineDefaultColor = this.sharedColorPalette.getColorByIndex(0).value;
51753 var showY1ReferenceLines = false;
51754 if (this.y1AxisReferenceLines) {
51755 for (var _i = 0, _a = this.y1AxisReferenceLines; _i < _a.length; _i++) {
51756 var referenceLineProperties = _a[_i];
51757 var object = referenceLineProperties.object;
51758 if (object[visuals.ReferenceLineHelper.referenceLineProps.show]) {
51759 var isHorizontal = !axes.y1.isCategoryAxis;
51760 var y1RefLineOptions = {
51761 graphicContext: scrollableRegion,
51762 referenceLineProperties: object,
51763 axes: axes,
51764 viewport: plotArea,
51765 classAndSelector: this.y1RefLine,
51766 defaultColor: refLineDefaultColor,
51767 isHorizontal: isHorizontal
51768 };
51769 visuals.ReferenceLineHelper.render(y1RefLineOptions);
51770 showY1ReferenceLines = true;
51771 }
51772 }
51773 }
51774 if (!showY1ReferenceLines) {
51775 scrollableRegion.selectAll(this.y1RefLine.selector).remove();
51776 }
51777 var showXReferenceLines = false;
51778 if (this.xAxisReferenceLines) {
51779 for (var _b = 0, _c = this.xAxisReferenceLines; _b < _c.length; _b++) {
51780 var referenceLineProperties = _c[_b];
51781 var object = referenceLineProperties.object;
51782 if (object[visuals.ReferenceLineHelper.referenceLineProps.show]) {
51783 var isHorizontal = false;
51784 var xRefLineOptions = {
51785 graphicContext: scrollableRegion,
51786 referenceLineProperties: object,
51787 axes: axes,
51788 viewport: plotArea,
51789 classAndSelector: this.xRefLine,
51790 defaultColor: refLineDefaultColor,
51791 isHorizontal: isHorizontal
51792 };
51793 visuals.ReferenceLineHelper.render(xRefLineOptions);
51794 showXReferenceLines = true;
51795 }
51796 }
51797 }
51798 if (!showXReferenceLines) {
51799 scrollableRegion.selectAll(this.xRefLine.selector).remove();
51800 }
51801 };
51802 CartesianChart.prototype.getReferenceLineLabels = function (axes, plotArea) {
51803 var refLineDefaultColor = this.sharedColorPalette.getColorByIndex(0).value;
51804 var referenceLineLabels = [];
51805 if (this.y1AxisReferenceLines) {
51806 for (var _i = 0, _a = this.y1AxisReferenceLines; _i < _a.length; _i++) {
51807 var referenceLineProperties = _a[_i];
51808 var object = referenceLineProperties.object;
51809 if (object[visuals.ReferenceLineHelper.referenceLineProps.show] && object[visuals.ReferenceLineHelper.referenceLineProps.dataLabelShow]) {
51810 var isHorizontal = !axes.y1.isCategoryAxis;
51811 var y1RefLineLabelOptions = {
51812 referenceLineProperties: object,
51813 axes: axes,
51814 viewport: plotArea,
51815 defaultColor: refLineDefaultColor,
51816 isHorizontal: isHorizontal,
51817 key: JSON.stringify({
51818 type: 'y1AxisReferenceLine',
51819 id: referenceLineProperties.id,
51820 }),
51821 };
51822 referenceLineLabels.push(visuals.ReferenceLineHelper.createLabelDataPoint(y1RefLineLabelOptions));
51823 }
51824 }
51825 }
51826 if (this.xAxisReferenceLines) {
51827 for (var _b = 0, _c = this.xAxisReferenceLines; _b < _c.length; _b++) {
51828 var referenceLineProperties = _c[_b];
51829 var object = referenceLineProperties.object;
51830 if (object[visuals.ReferenceLineHelper.referenceLineProps.show] && object[visuals.ReferenceLineHelper.referenceLineProps.dataLabelShow]) {
51831 var isHorizontal = false;
51832 var xRefLineLabelOptions = {
51833 referenceLineProperties: object,
51834 axes: axes,
51835 viewport: plotArea,
51836 defaultColor: refLineDefaultColor,
51837 isHorizontal: isHorizontal,
51838 key: JSON.stringify({
51839 type: 'xAxisReferenceLine',
51840 id: referenceLineProperties.id,
51841 }),
51842 };
51843 referenceLineLabels.push(visuals.ReferenceLineHelper.createLabelDataPoint(xRefLineLabelOptions));
51844 }
51845 }
51846 }
51847 return referenceLineLabels;
51848 };
51849 CartesianChart.prototype.renderDataLabels = function (labelDataPointGroups, labelsAreNumeric, plotArea, suppressAnimations, isCombo) {
51850 var labelBackgroundRegion = this.svgAxes.getLabelBackground();
51851 var labelRegion = this.svgAxes.getLabelsRegion();
51852 if (this.behavior) {
51853 var labelLayoutOptions = visuals.NewDataLabelUtils.getDataLabelLayoutOptions(this.type);
51854 var labelLayout = new powerbi.LabelLayout(labelLayoutOptions);
51855 var dataLabels = labelLayout.layout(labelDataPointGroups, plotArea);
51856 if (isCombo) {
51857 visuals.NewDataLabelUtils.drawLabelBackground(labelBackgroundRegion, dataLabels, "#FFFFFF", 0.7);
51858 }
51859 var svgLabels = void 0;
51860 var animator = this.animator;
51861 if (animator && !suppressAnimations) {
51862 var isPlayAxis = this.isPlayAxis();
51863 var duration = isPlayAxis ? visuals.PlayChart.FrameAnimationDuration : animator.getDuration();
51864 svgLabels = visuals.NewDataLabelUtils.animateDefaultLabels(labelRegion, dataLabels, duration, labelsAreNumeric, isPlayAxis ? 'linear' : animator.getEasing());
51865 }
51866 else {
51867 svgLabels = visuals.NewDataLabelUtils.drawDefaultLabels(labelRegion, dataLabels, labelsAreNumeric);
51868 }
51869 if (labelLayoutOptions.allowLeaderLines) {
51870 var filteredLabels = _.filter(dataLabels, function (d) { return d.leaderLinePoints != null && !_.isEmpty(d.leaderLinePoints) && d.identity != null; });
51871 visuals.NewDataLabelUtils.drawLabelLeaderLines(labelRegion, filteredLabels, function (d) { return d.identity.getKey(); });
51872 }
51873 if (this.interactivityService && this.isLabelInteractivityEnabled) {
51874 var labelsBehaviorOptions = {
51875 labelItems: svgLabels,
51876 };
51877 this.interactivityService.bind(dataLabels, new visuals.LabelsBehavior(), labelsBehaviorOptions, { isLabels: true });
51878 }
51879 }
51880 else {
51881 var labelLayout = new powerbi.LabelLayout({
51882 maximumOffset: visuals.NewDataLabelUtils.maxLabelOffset,
51883 startingOffset: visuals.NewDataLabelUtils.startingLabelOffset,
51884 attemptToMoveLabelsIntoViewport: true,
51885 });
51886 var dataLabels = labelLayout.layout(labelDataPointGroups, plotArea);
51887 if (isCombo) {
51888 visuals.NewDataLabelUtils.drawLabelBackground(labelBackgroundRegion, dataLabels, "#FFFFFF", 0.7);
51889 }
51890 visuals.NewDataLabelUtils.drawDefaultLabels(labelRegion, dataLabels, labelsAreNumeric);
51891 }
51892 };
51893 CartesianChart.prototype.renderLayers = function (layers, plotArea, axes, suppressAnimations, resizeMode) {
51894 var labelDataPointGroups = [];
51895 var dataPoints = [];
51896 var layerBehaviorOptions = [];
51897 var labelsAreNumeric = true;
51898 for (var i = 0, len = layers.length; i < len; i++) {
51899 var result = layers[i].render(suppressAnimations, resizeMode);
51900 if (result) {
51901 if (this.behavior) {
51902 // NOTE: these are not needed if we don't have interactivity
51903 dataPoints = dataPoints.concat(result.dataPoints);
51904 layerBehaviorOptions.push(result.behaviorOptions);
51905 }
51906 if (result.labelDataPointGroups) {
51907 var resultLabelDataPointsGroups = result.labelDataPointGroups;
51908 for (var _i = 0, resultLabelDataPointsGroups_1 = resultLabelDataPointsGroups; _i < resultLabelDataPointsGroups_1.length; _i++) {
51909 var resultLabelDataPointsGroup = resultLabelDataPointsGroups_1[_i];
51910 if (!resultLabelDataPointsGroup)
51911 continue;
51912 labelDataPointGroups.push({
51913 labelDataPoints: visuals.NewDataLabelUtils.removeDuplicates(resultLabelDataPointsGroup.labelDataPoints || []),
51914 maxNumberOfLabels: resultLabelDataPointsGroup.maxNumberOfLabels,
51915 });
51916 }
51917 }
51918 else {
51919 var resultsLabelDataPoints = result.labelDataPoints || [];
51920 labelDataPointGroups.push({
51921 labelDataPoints: visuals.NewDataLabelUtils.removeDuplicates(resultsLabelDataPoints),
51922 maxNumberOfLabels: resultsLabelDataPoints.length,
51923 });
51924 }
51925 labelsAreNumeric = labelsAreNumeric && result.labelsAreNumeric;
51926 }
51927 }
51928 var referenceLineLabels = this.getReferenceLineLabels(axes, plotArea);
51929 if (!_.isEmpty(referenceLineLabels)) {
51930 labelDataPointGroups.unshift({
51931 labelDataPoints: referenceLineLabels,
51932 maxNumberOfLabels: referenceLineLabels.length,
51933 });
51934 }
51935 this.renderDataLabels(labelDataPointGroups, labelsAreNumeric, plotArea, suppressAnimations, visuals.ComboChart.isComboChart(this.type));
51936 if (this.interactivityService) {
51937 var behaviorOptions = {
51938 layerOptions: layerBehaviorOptions,
51939 clearCatcher: this.clearCatcher,
51940 };
51941 this.interactivityService.bind(dataPoints, this.behavior, behaviorOptions);
51942 }
51943 };
51944 /**
51945 * Returns the actual viewportWidth if visual is not scrollable.
51946 * @return If visual is scrollable, returns the plot area needed to draw all the datapoints.
51947 */
51948 CartesianChart.getPreferredPlotArea = function (categoryCount, categoryThickness, viewport, isScrollable, isScalar, margin, noOuterPadding) {
51949 if (!margin)
51950 margin = { top: 0, right: 0, bottom: 0, left: 0 };
51951 var plotArea = {
51952 height: viewport.height - margin.top - margin.bottom,
51953 width: viewport.width - margin.left - margin.right
51954 };
51955 if (!isScalar && isScrollable) {
51956 var preferredCategorySpan = CartesianChart.getPreferredCategorySpan(categoryCount, categoryThickness, noOuterPadding);
51957 plotArea.width = Math.max(preferredCategorySpan, plotArea.width);
51958 }
51959 return plotArea;
51960 };
51961 /**
51962 * Returns preferred Category span if the visual is scrollable.
51963 */
51964 CartesianChart.getPreferredCategorySpan = function (categoryCount, categoryThickness, noOuterPadding) {
51965 var span = (categoryThickness * categoryCount);
51966 if (noOuterPadding)
51967 return span;
51968 return span + (categoryThickness * CartesianChart.OuterPaddingRatio * 2);
51969 };
51970 /**
51971 * Note: Public for testing access.
51972 */
51973 CartesianChart.getLayout = function (data, options) {
51974 var categoryCount = options.categoryCount, availableWidth = options.availableWidth, domain = options.domain, trimOrdinalDataOnOverflow = options.trimOrdinalDataOnOverflow, isScalar = !!options.isScalar, isScrollable = !!options.isScrollable;
51975 var categoryThickness = CartesianChart.getCategoryThickness(data ? data.series : null, categoryCount, availableWidth, domain, isScalar, trimOrdinalDataOnOverflow);
51976 // Total width of the outer padding, the padding that exist on the far right and far left of the chart.
51977 var totalOuterPadding = categoryThickness * CartesianChart.OuterPaddingRatio * 2;
51978 // visibleCategoryCount will be used to discard data that overflows on ordinal-axis charts.
51979 // Needed for dashboard visuals
51980 var calculatedBarCount = powerbi.Double.floorWithPrecision((availableWidth - totalOuterPadding) / categoryThickness);
51981 var visibleCategoryCount = Math.min(calculatedBarCount, categoryCount);
51982 var willScroll = visibleCategoryCount < categoryCount && isScrollable;
51983 var outerPaddingRatio = CartesianChart.OuterPaddingRatio;
51984 if (!isScalar && !willScroll) {
51985 // use dynamic outer padding to improve spacing when we have few categories
51986 var oneOuterPadding = (availableWidth - (categoryThickness * visibleCategoryCount)) / 2;
51987 outerPaddingRatio = oneOuterPadding / categoryThickness;
51988 }
51989 // If scrollable, visibleCategoryCount will be total categories
51990 if (!isScalar && isScrollable)
51991 visibleCategoryCount = categoryCount;
51992 return {
51993 categoryCount: visibleCategoryCount,
51994 categoryThickness: categoryThickness,
51995 outerPaddingRatio: outerPaddingRatio,
51996 isScalar: isScalar
51997 };
51998 };
51999 /**
52000 * Returns the thickness for each category.
52001 * For clustered charts, you still need to divide by
52002 * the number of series to get column width after calling this method.
52003 * For linear or time scales, category thickness accomodates for
52004 * the minimum interval between consequtive points.
52005 * For all types, return value has accounted for outer padding,
52006 * but not inner padding.
52007 */
52008 CartesianChart.getCategoryThickness = function (seriesList, numCategories, plotLength, domain, isScalar, trimOrdinalDataOnOverflow) {
52009 var thickness;
52010 if (numCategories < 2)
52011 thickness = plotLength * (1 - CartesianChart.OuterPaddingRatio);
52012 else if (isScalar && domain && domain.length > 1) {
52013 // the smallest interval defines the column width.
52014 var minInterval = CartesianChart.getMinInterval(seriesList);
52015 var domainSpan = domain[domain.length - 1] - domain[0];
52016 // account for outside padding
52017 var ratio = minInterval / (domainSpan + (minInterval * CartesianChart.OuterPaddingRatio * 2));
52018 thickness = plotLength * ratio;
52019 thickness = Math.max(thickness, CartesianChart.MinScalarRectThickness);
52020 }
52021 else {
52022 // Divide the available width up including outer padding (in terms of category thickness) on
52023 // both sides of the chart, and categoryCount categories. Reverse math:
52024 // availableWidth = (categoryThickness * categoryCount) + (categoryThickness * (outerPadding * 2)),
52025 // availableWidth = categoryThickness * (categoryCount + (outerPadding * 2)),
52026 // categoryThickness = availableWidth / (categoryCount + (outerpadding * 2))
52027 thickness = plotLength / (numCategories + (CartesianChart.OuterPaddingRatio * 2));
52028 if (trimOrdinalDataOnOverflow) {
52029 thickness = Math.max(thickness, CartesianChart.MinOrdinalRectThickness);
52030 }
52031 }
52032 // spec calls for using the whole plot area, but the max rectangle thickness is "as if there were three categories"
52033 // (outerPaddingRatio has the same units as '# of categories' so they can be added)
52034 var maxRectThickness = plotLength / (3 + (CartesianChart.OuterPaddingRatio * 2));
52035 thickness = Math.min(thickness, maxRectThickness);
52036 if (!isScalar && numCategories >= 3 && trimOrdinalDataOnOverflow) {
52037 return Math.max(thickness, CartesianChart.MinOrdinalRectThickness);
52038 }
52039 return thickness;
52040 };
52041 CartesianChart.getMinInterval = function (seriesList) {
52042 var minInterval = Number.MAX_VALUE;
52043 if (seriesList.length > 0) {
52044 var series0data = seriesList[0].data.filter(function (d) { return !d.highlight; });
52045 for (var i = 0, ilen = series0data.length - 1; i < ilen; i++) {
52046 minInterval = Math.min(minInterval, Math.abs(series0data[i + 1].categoryValue - series0data[i].categoryValue));
52047 }
52048 }
52049 return minInterval;
52050 };
52051 CartesianChart.MinOrdinalRectThickness = 20;
52052 CartesianChart.MinScalarRectThickness = 2;
52053 CartesianChart.OuterPaddingRatio = 0.4;
52054 CartesianChart.InnerPaddingRatio = 0.2;
52055 CartesianChart.TickLabelPadding = 2; // between text labels, used by AxisHelper
52056 CartesianChart.ClassName = 'cartesianChart';
52057 CartesianChart.PlayAxisBottomMargin = 80; //do not change unless we add dynamic label measurements for play slider
52058 CartesianChart.FontSize = 11;
52059 CartesianChart.FontSizeString = jsCommon.PixelConverter.toString(CartesianChart.FontSize);
52060 CartesianChart.AxisTextProperties = {
52061 fontFamily: 'wf_segoe-ui_normal',
52062 fontSize: CartesianChart.FontSizeString,
52063 };
52064 return CartesianChart;
52065 }());
52066 visuals.CartesianChart = CartesianChart;
52067 function getLayerDataViews(dataViews) {
52068 if (_.isEmpty(dataViews))
52069 return [];
52070 // TODO: figure out a more general way to correlate between layers and input data views.
52071 return _.filter(dataViews, function (dataView) { return !visuals.TrendLineHelper.isDataViewForRegression(dataView); });
52072 }
52073 function hasMultipleYAxes(layers) {
52074 debug.assertValue(layers, 'layers');
52075 return layers.length > 1;
52076 }
52077 /**
52078 * Returns a boolean, that indicates if y axis title should be displayed.
52079 * @return True if y axis title should be displayed,
52080 * otherwise false.
52081 */
52082 function shouldShowYAxisLabel(layerNumber, valueAxisProperties, yAxisWillMerge) {
52083 return ((layerNumber === 0 && !!valueAxisProperties && !!valueAxisProperties['showAxisTitle']) ||
52084 (layerNumber === 1 && !yAxisWillMerge && !!valueAxisProperties && !!valueAxisProperties['secShowAxisTitle']));
52085 }
52086 function tryMergeYDomains(layers, visualOptions) {
52087 debug.assert(layers.length < 3, 'merging of more than 2 layers is not supported');
52088 var noMerge = {
52089 domain: undefined,
52090 merged: false,
52091 tickCount: undefined
52092 };
52093 if (layers.length < 2)
52094 return noMerge;
52095 var min;
52096 var max;
52097 var minOfMax;
52098 var maxOfMin;
52099 // TODO: replace full calculateAxesProperties with just a data domain calc
52100 // we need to be aware of which chart require zero (column/bar) and which don't (line)
52101 var y1props = layers[0].calculateAxesProperties(visualOptions)[1];
52102 var y2props = layers[1].calculateAxesProperties(visualOptions)[1];
52103 var firstYDomain = y1props.scale.domain();
52104 var secondYDomain = y2props.scale.domain();
52105 if (y1props.values && y1props.values.length > 0 && y2props.values && y2props.values.length > 0) {
52106 noMerge.tickCount = Math.max(y1props.values.length, y2props.values.length);
52107 }
52108 min = Math.min(firstYDomain[0], secondYDomain[0]);
52109 max = Math.max(firstYDomain[1], secondYDomain[1]);
52110 if (visualOptions.forceMerge) {
52111 return {
52112 domain: [min, max],
52113 merged: true,
52114 tickCount: noMerge.tickCount
52115 };
52116 }
52117 // If domains don't intersect don't merge axis.
52118 if (firstYDomain[0] > secondYDomain[1] || firstYDomain[1] < secondYDomain[0])
52119 return noMerge;
52120 maxOfMin = Math.max(firstYDomain[0], secondYDomain[0]);
52121 minOfMax = Math.min(firstYDomain[1], secondYDomain[1]);
52122 var range = (max - min);
52123 if (range === 0) {
52124 return noMerge;
52125 }
52126 var intersection = Math.abs((minOfMax - maxOfMin) / range);
52127 // Only merge if intersection of domains greater than 10% of total range.
52128 if (intersection < COMBOCHART_DOMAIN_OVERLAP_TRESHOLD_PERCENTAGE)
52129 return noMerge;
52130 else
52131 return {
52132 domain: [min, max],
52133 merged: true,
52134 tickCount: noMerge.tickCount
52135 };
52136 }
52137 var SvgBrush = (function () {
52138 function SvgBrush(brushWidth) {
52139 this.brush = d3.svg.brush();
52140 this.brushWidth = brushWidth;
52141 }
52142 SvgBrush.prototype.init = function (element) {
52143 this.element = element;
52144 };
52145 SvgBrush.prototype.remove = function () {
52146 this.element.selectAll(SvgBrush.Brush.selector).remove();
52147 this.brushGraphicsContext = undefined;
52148 };
52149 SvgBrush.prototype.getExtent = function () {
52150 return this.brush.extent();
52151 };
52152 SvgBrush.prototype.setExtent = function (extent) {
52153 this.brush.extent(extent);
52154 };
52155 SvgBrush.prototype.setScale = function (scale) {
52156 if (this.isHorizontal)
52157 this.brush.x(scale);
52158 else
52159 this.brush.y(scale);
52160 };
52161 SvgBrush.prototype.setOrientation = function (isHorizontal) {
52162 this.isHorizontal = isHorizontal;
52163 };
52164 SvgBrush.prototype.renderBrush = function (extentLength, brushX, brushY, scrollCallback) {
52165 var _this = this;
52166 // create graphics context if it doesn't exist
52167 if (!this.brushGraphicsContext) {
52168 this.brushGraphicsContext = this.element.append("g")
52169 .classed(SvgBrush.Brush.class, true);
52170 }
52171 this.scrollCallback = scrollCallback;
52172 // events
52173 this.brush
52174 .on("brushstart", function () { return _this.brushStartExtent = _this.brush.extent(); })
52175 .on("brush", function () {
52176 window.requestAnimationFrame(scrollCallback);
52177 })
52178 .on("brushend", function () {
52179 _this.resizeExtent(extentLength);
52180 _this.updateExtentPosition(extentLength);
52181 _this.brushStartExtent = null;
52182 });
52183 // position the graphics context
52184 var brushContext = this.brushGraphicsContext
52185 .attr({
52186 "transform": visuals.SVGUtil.translate(brushX, brushY),
52187 "drag-resize-disabled": "true" /* Disables resizing of the visual when dragging the scrollbar in edit mode */
52188 })
52189 .call(this.brush);
52190 // Disable the zooming feature by removing the resize elements
52191 brushContext.selectAll(".resize")
52192 .remove();
52193 if (this.isHorizontal)
52194 brushContext.selectAll("rect").attr("height", this.brushWidth);
52195 else
52196 brushContext.selectAll("rect").attr("width", this.brushWidth);
52197 };
52198 SvgBrush.prototype.scroll = function (scrollBarLength) {
52199 this.updateExtentPosition(scrollBarLength);
52200 this.scrollCallback();
52201 };
52202 SvgBrush.prototype.updateExtentPosition = function (scrollBarLength) {
52203 var extent = this.brush.extent();
52204 debug.assertNonEmpty(extent, 'updateExtentPosition, extent');
52205 var newStartPos = extent[0];
52206 var halfScrollBarLen = scrollBarLength / 2;
52207 if (extent[0] === extent[1]) {
52208 // user clicked on the brush background, width will be zero, offset x by half width
52209 newStartPos = newStartPos - halfScrollBarLen;
52210 }
52211 if (extent[1] - extent[0] > scrollBarLength) {
52212 // user is dragging one edge after mousedown in the background, figure out which side is moving
52213 // also, center up on the new extent center
52214 var halfDragLength = (extent[1] - extent[0]) / 2;
52215 if (extent[0] < this.brushStartExtent[0])
52216 newStartPos = extent[0] + halfDragLength - halfScrollBarLen;
52217 else
52218 newStartPos = extent[1] - halfDragLength - halfScrollBarLen;
52219 }
52220 if (this.isHorizontal)
52221 this.brushGraphicsContext.select(".extent").attr('x', newStartPos);
52222 else
52223 this.brushGraphicsContext.select(".extent").attr('y', newStartPos);
52224 };
52225 SvgBrush.prototype.resizeExtent = function (extentLength) {
52226 if (this.isHorizontal)
52227 this.brushGraphicsContext.select(".extent").attr("width", extentLength);
52228 else
52229 this.brushGraphicsContext.select(".extent").attr("height", extentLength);
52230 };
52231 SvgBrush.Brush = createClassAndSelector('brush');
52232 return SvgBrush;
52233 }());
52234 var ScrollableAxes = (function () {
52235 function ScrollableAxes(axes, svgBrush) {
52236 this.axes = axes;
52237 this.brush = svgBrush;
52238 }
52239 ScrollableAxes.prototype.filterDataToViewport = function (mainAxisScale, layers, axes, scrollScale, extent, visibleCategoryCount) {
52240 if (scrollScale) {
52241 var selected = void 0;
52242 var data_1 = [];
52243 // NOTE: using start + numVisibleCategories to make sure we don't have issues with exactness related to extent start/end
52244 // (don't use extent[1])
52245 /*
52246 When extent[0] and extent[1] are very close to the boundary of a new index, due to floating point err,
52247 the "start" might move to the next index but the "end" might not change until you slide one more pixel.
52248 It makes things really jittery during scrolling, sometimes you see N columns and sometimes you briefly see N+1.
52249 */
52250 var startIndex = visuals.AxisHelper.lookupOrdinalIndex(scrollScale, extent[0]);
52251 var endIndex = startIndex + visibleCategoryCount; // NOTE: intentionally 1 past end index
52252 var domain = scrollScale.domain();
52253 selected = domain.slice(startIndex, endIndex); // NOTE: Up to but not including 'end'
52254 if (selected && selected.length > 0) {
52255 for (var i = 0; i < layers.length; i++) {
52256 data_1[i] = layers[i].setFilteredData(selected[0], selected[selected.length - 1] + 1);
52257 }
52258 mainAxisScale.domain(selected);
52259 var axisPropsToUpdate = void 0;
52260 if (this.axes.isXScrollBarVisible) {
52261 axisPropsToUpdate = axes.x;
52262 }
52263 else {
52264 axisPropsToUpdate = axes.y1;
52265 }
52266 axisPropsToUpdate.axis.scale(mainAxisScale);
52267 axisPropsToUpdate.scale(mainAxisScale);
52268 // tick values are indices for ordinal axes
52269 axisPropsToUpdate.axis.ticks(selected.length);
52270 axisPropsToUpdate.axis.tickValues(selected);
52271 // use the original tick format to format the tick values
52272 var tickFormat_1 = axisPropsToUpdate.axis.tickFormat();
52273 axisPropsToUpdate.values = _.map(selected, function (d) { return tickFormat_1(d); });
52274 }
52275 }
52276 };
52277 ScrollableAxes.prototype.render = function (axesLayout, layers, suppressAnimations, renderDelegate) {
52278 var _this = this;
52279 var plotArea = axesLayout.plotArea;
52280 if (plotArea.width < 1 || plotArea.height < 1)
52281 return; //do nothing - too small
52282 this.axisScale = null;
52283 var brushX;
52284 var brushY;
52285 var scrollbarLength;
52286 var numVisibleCategories;
52287 var categoryThickness;
52288 var newAxisLength;
52289 if (this.axes.isXScrollBarVisible) {
52290 this.axisScale = axesLayout.axes.x.scale;
52291 brushX = axesLayout.margin.left;
52292 brushY = axesLayout.viewport.height;
52293 categoryThickness = axesLayout.axes.x.categoryThickness;
52294 var outerPadding = axesLayout.axes.x.outerPadding;
52295 numVisibleCategories = powerbi.Double.floorWithPrecision((plotArea.width - outerPadding * 2) / categoryThickness);
52296 scrollbarLength = (numVisibleCategories + 1) * categoryThickness;
52297 newAxisLength = plotArea.width;
52298 }
52299 else if (this.axes.isYScrollBarVisible) {
52300 this.axisScale = axesLayout.axes.y1.scale;
52301 brushX = axesLayout.viewport.width;
52302 brushY = axesLayout.margin.top;
52303 categoryThickness = axesLayout.axes.y1.categoryThickness;
52304 var outerPadding = axesLayout.axes.y1.outerPadding;
52305 numVisibleCategories = powerbi.Double.floorWithPrecision((plotArea.height - outerPadding * 2) / categoryThickness);
52306 scrollbarLength = (numVisibleCategories + 1) * categoryThickness;
52307 newAxisLength = plotArea.height;
52308 }
52309 else {
52310 // No scrollbars, render the chart normally.
52311 this.brush.remove();
52312 renderDelegate(layers, axesLayout, suppressAnimations);
52313 return;
52314 }
52315 // viewport is REALLY small
52316 if (numVisibleCategories < 1)
52317 return; // don't do anything
52318 this.scrollScale = this.axisScale.copy();
52319 this.scrollScale.rangeBands([0, scrollbarLength]); //no inner/outer padding, keep the math simple
52320 this.brushMinExtent = this.scrollScale(numVisibleCategories - 1);
52321 // Options: use newAxisLength to squeeze-pop and keep the chart balanced,
52322 // or use scrollbarLength to keep rects still - but it leaves unbalanced right edge
52323 // 1. newAxisLength ex: As you resize smaller we constantly adjust the inner/outer padding to keep things balanced with the same # of rects,
52324 // when we need to drop a rect we pop out the rectangle and the padding seems to jump (to keep things cenetered and balanced).
52325 // 2. scrollbarLenghth ex: As you resize smaller we can leave all rectangles in the exact same place, no squeezing inner/outer padding,
52326 // when we need to drop a rect we just remove it - but this leaves the right side with lots of empty room (bad for dashboard tiles)
52327 // we are using option 1 to squeeze pop and show balanced layout at all sizes, but this is the less ideal experience during resize.
52328 // we should consider using option 2 during resize, then switch to option 1 when resize ends.
52329 this.axisScale.rangeBands([0, newAxisLength], CartesianChart.InnerPaddingRatio, CartesianChart.OuterPaddingRatio);
52330 this.brush.setOrientation(this.axes.isXScrollBarVisible);
52331 this.brush.setScale(this.scrollScale);
52332 this.brush.setExtent([0, this.brushMinExtent]);
52333 // This function will be called whenever we scroll.
52334 var renderOnScroll = function (extent, suppressAnimations) {
52335 _this.filterDataToViewport(_this.axisScale, layers, axesLayout.axes, _this.scrollScale, extent, numVisibleCategories);
52336 renderDelegate(layers, axesLayout, suppressAnimations);
52337 };
52338 var scrollCallback = function () { return _this.onBrushed(scrollbarLength, renderOnScroll); };
52339 this.brush.renderBrush(this.brushMinExtent, brushX, brushY, scrollCallback);
52340 renderOnScroll(this.brush.getExtent(), suppressAnimations);
52341 };
52342 ScrollableAxes.prototype.scrollDelta = function (delta) {
52343 if (this.axisScale && !_.isEmpty(this.axisScale.domain())) {
52344 var currentStartIndex = this.axisScale.domain()[0];
52345 var newStartIndex = currentStartIndex + Math.round(delta / CartesianChart.MinOrdinalRectThickness);
52346 this.scrollTo(newStartIndex);
52347 }
52348 };
52349 // PUBLIC FOR UNIT TESTING ONLY
52350 ScrollableAxes.prototype.scrollTo = function (startIndex) {
52351 debug.assert(this.axes.isXScrollBarVisible || this.axes.isYScrollBarVisible, 'scrolling is not available');
52352 debug.assertValue(this.scrollScale, 'scrollScale');
52353 var lastIndex = _.last(this.scrollScale.domain());
52354 startIndex = Math.max(0, Math.min(startIndex, lastIndex));
52355 var extent = this.brush.getExtent();
52356 var extentLength = extent[1] - extent[0];
52357 var halfCategoryThickness = (this.scrollScale(1) - this.scrollScale(0)) / 2;
52358 extent[0] = this.scrollScale(startIndex) + halfCategoryThickness;
52359 extent[1] = extent[0] + extentLength + halfCategoryThickness;
52360 this.brush.setExtent(extent);
52361 var scrollbarLength = this.scrollScale.rangeExtent()[1];
52362 ScrollableAxes.clampBrushExtent(this.brush, scrollbarLength, this.brushMinExtent);
52363 this.brush.scroll(scrollbarLength);
52364 };
52365 ScrollableAxes.prototype.onBrushed = function (scrollbarLength, render) {
52366 var brush = this.brush;
52367 ScrollableAxes.clampBrushExtent(this.brush, scrollbarLength, this.brushMinExtent);
52368 var extent = brush.getExtent();
52369 render(extent, /*suppressAnimations*/ true);
52370 };
52371 ScrollableAxes.clampBrushExtent = function (brush, scrollbarLength, minExtent) {
52372 var extent = brush.getExtent();
52373 var width = extent[1] - extent[0];
52374 if (width === minExtent && extent[1] <= scrollbarLength && extent[0] >= 0)
52375 return;
52376 if (width > minExtent) {
52377 var padding = (width - minExtent) / 2;
52378 extent[0] += padding;
52379 extent[1] -= padding;
52380 }
52381 else if (width < minExtent) {
52382 var padding = (minExtent - width) / 2;
52383 extent[0] -= padding;
52384 extent[1] += padding;
52385 }
52386 if (extent[0] < 0) {
52387 extent[0] = 0;
52388 extent[1] = minExtent;
52389 }
52390 else if (extent[0] > scrollbarLength - minExtent) {
52391 extent[0] = scrollbarLength - minExtent;
52392 extent[1] = scrollbarLength;
52393 }
52394 brush.setExtent(extent);
52395 };
52396 ScrollableAxes.ScrollbarWidth = 10;
52397 return ScrollableAxes;
52398 }());
52399 var SvgCartesianAxes = (function () {
52400 function SvgCartesianAxes(axes) {
52401 this.axes = axes;
52402 }
52403 SvgCartesianAxes.prototype.getScrollableRegion = function () {
52404 return this.axisGraphicsContextScrollable;
52405 };
52406 SvgCartesianAxes.prototype.getLabelsRegion = function () {
52407 return this.labelRegion;
52408 };
52409 SvgCartesianAxes.prototype.getLabelBackground = function () {
52410 return this.labelBackgroundRegion;
52411 };
52412 SvgCartesianAxes.prototype.getXAxis = function () {
52413 return this.xAxisGraphicsContext;
52414 };
52415 SvgCartesianAxes.prototype.getY1Axis = function () {
52416 return this.y1AxisGraphicsContext;
52417 };
52418 SvgCartesianAxes.prototype.getY2Axis = function () {
52419 return this.y2AxisGraphicsContext;
52420 };
52421 SvgCartesianAxes.prototype.update = function (categoryAxisProperties, valueAxisProperties) {
52422 this.categoryAxisProperties = categoryAxisProperties;
52423 this.valueAxisProperties = valueAxisProperties;
52424 };
52425 SvgCartesianAxes.prototype.init = function (svg) {
52426 /*
52427 The layout of the visual will look like:
52428 <svg>
52429 <g>
52430 <nonscrollable axis/>
52431 </g>
52432 <svgScrollable>
52433 <g>
52434 <scrollable axis/>
52435 </g>
52436 </svgScrollable>
52437 <g xbrush/>
52438 </svg>
52439
52440 */
52441 var axisGraphicsContext = this.axisGraphicsContext = svg.append('g')
52442 .classed(SvgCartesianAxes.AxisGraphicsContext.class, true);
52443 this.svgScrollable = svg.append('svg')
52444 .classed('svgScrollable', true)
52445 .style('overflow', 'hidden');
52446 var axisGraphicsContextScrollable = this.axisGraphicsContextScrollable = this.svgScrollable.append('g')
52447 .classed(SvgCartesianAxes.AxisGraphicsContext.class, true);
52448 this.labelBackgroundRegion = this.svgScrollable.append('g')
52449 .classed(visuals.NewDataLabelUtils.labelBackgroundGraphicsContextClass.class, true);
52450 this.labelRegion = this.svgScrollable.append('g')
52451 .classed(visuals.NewDataLabelUtils.labelGraphicsContextClass.class, true);
52452 var showLinesOnX = this.axes.showLinesOnX;
52453 var showLinesOnY = this.axes.showLinesOnY;
52454 // NOTE: We infer the axis which should scroll based on whether or not we draw grid lines for the other axis, and
52455 // only allow one axis to scroll.
52456 var scrollX = showLinesOnY;
52457 var scrollY = !scrollX;
52458 if (scrollY) {
52459 this.y1AxisGraphicsContext = axisGraphicsContextScrollable.append('g').attr('class', 'y axis');
52460 this.y2AxisGraphicsContext = axisGraphicsContextScrollable.append('g').attr('class', 'y axis');
52461 }
52462 else {
52463 this.y1AxisGraphicsContext = axisGraphicsContext.append('g').attr('class', 'y axis');
52464 this.y2AxisGraphicsContext = axisGraphicsContext.append('g').attr('class', 'y axis');
52465 }
52466 if (scrollX) {
52467 this.xAxisGraphicsContext = axisGraphicsContextScrollable.append('g').attr('class', 'x axis');
52468 }
52469 else {
52470 this.xAxisGraphicsContext = axisGraphicsContext.append('g').attr('class', 'x axis');
52471 }
52472 this.xAxisGraphicsContext.classed('showLinesOnAxis', showLinesOnX);
52473 this.y1AxisGraphicsContext.classed('showLinesOnAxis', showLinesOnY);
52474 this.y2AxisGraphicsContext.classed('showLinesOnAxis', showLinesOnY);
52475 this.xAxisGraphicsContext.classed('hideLinesOnAxis', !showLinesOnX);
52476 this.y1AxisGraphicsContext.classed('hideLinesOnAxis', !showLinesOnY);
52477 this.y2AxisGraphicsContext.classed('hideLinesOnAxis', !showLinesOnY);
52478 };
52479 SvgCartesianAxes.updateAnimatedTickTooltips = function (axisSelection, values) {
52480 axisSelection.each('end', function () {
52481 d3.select(this)
52482 .selectAll('text')
52483 .append('title')
52484 .text(function (d, i) { return values[i]; });
52485 });
52486 };
52487 SvgCartesianAxes.updateTickTooltips = function (axisSelection, values) {
52488 axisSelection.selectAll('text').append('title').text(function (d, i) { return values[i]; });
52489 };
52490 SvgCartesianAxes.prototype.renderAxes = function (axesLayout, duration, easing) {
52491 if (easing === void 0) { easing = 'cubic-in-out'; }
52492 var marginLimits = axesLayout.marginLimits;
52493 var plotArea = axesLayout.plotArea;
52494 var viewport = axesLayout.viewport;
52495 var margin = axesLayout.margin;
52496 var axes = axesLayout.axes;
52497 var tickLabelMargins = axesLayout.tickLabelMargins;
52498 var bottomMarginLimit = marginLimits.bottom;
52499 var leftRightMarginLimit = marginLimits.left;
52500 var xLabelColor;
52501 var yLabelColor;
52502 var y2LabelColor;
52503 if (this.axes.shouldRenderAxis(axes.x)) {
52504 if (axes.x.isCategoryAxis) {
52505 xLabelColor = this.categoryAxisProperties && this.categoryAxisProperties['labelColor'] ? this.categoryAxisProperties['labelColor'] : null;
52506 }
52507 else {
52508 xLabelColor = this.valueAxisProperties && this.valueAxisProperties['labelColor'] ? this.valueAxisProperties['labelColor'] : null;
52509 }
52510 axes.x.axis.orient("bottom");
52511 // we only rotate ordinal tick labels
52512 if (!axes.x.willLabelsFit && visuals.AxisHelper.isOrdinalScale(axes.x.scale))
52513 axes.x.axis.tickPadding(SvgCartesianAxes.TickPaddingRotatedX);
52514 var xAxisGraphicsElement = this.xAxisGraphicsContext;
52515 if (duration) {
52516 xAxisGraphicsElement
52517 .transition()
52518 .duration(duration)
52519 .ease(easing)
52520 .call(axes.x.axis)
52521 .call(SvgCartesianAxes.updateAnimatedTickTooltips, axes.x.values);
52522 }
52523 else {
52524 xAxisGraphicsElement
52525 .call(axes.x.axis);
52526 }
52527 xAxisGraphicsElement
52528 .call(SvgCartesianAxes.darkenZeroLine)
52529 .call(SvgCartesianAxes.setAxisLabelColor, xLabelColor);
52530 var xAxisTextNodes = xAxisGraphicsElement.selectAll('text');
52531 if (axes.x.willLabelsWordBreak) {
52532 xAxisTextNodes
52533 .call(visuals.AxisHelper.LabelLayoutStrategy.wordBreak, axes.x, bottomMarginLimit);
52534 }
52535 else {
52536 xAxisTextNodes
52537 .call(visuals.AxisHelper.LabelLayoutStrategy.rotate, bottomMarginLimit, powerbi.TextMeasurementService.getTailoredTextOrDefault, CartesianChart.AxisTextProperties, !axes.x.willLabelsFit && visuals.AxisHelper.isOrdinalScale(axes.x.scale), bottomMarginLimit === tickLabelMargins.xMax, axes.x, margin, this.axes.isXScrollBarVisible || this.axes.isYScrollBarVisible);
52538 }
52539 if (!duration) {
52540 SvgCartesianAxes.updateTickTooltips(xAxisGraphicsElement, axes.x.values);
52541 }
52542 }
52543 else {
52544 this.xAxisGraphicsContext.selectAll('*').remove();
52545 }
52546 if (this.axes.shouldRenderAxis(axes.y1)) {
52547 if (axes.y1.isCategoryAxis) {
52548 yLabelColor = this.categoryAxisProperties && this.categoryAxisProperties['labelColor'] ? this.categoryAxisProperties['labelColor'] : null;
52549 }
52550 else {
52551 yLabelColor = this.valueAxisProperties && this.valueAxisProperties['labelColor'] ? this.valueAxisProperties['labelColor'] : null;
52552 }
52553 var showY1OnRight = this.axes.shouldShowY1OnRight();
52554 var y1TickPadding = showY1OnRight ? axesLayout.tickPadding.right : axesLayout.tickPadding.left;
52555 axes.y1.axis
52556 .tickSize(-plotArea.width)
52557 .tickPadding(y1TickPadding)
52558 .orient(this.axes.getYAxisOrientation().toLowerCase());
52559 var y1AxisGraphicsElement = this.y1AxisGraphicsContext;
52560 if (duration) {
52561 y1AxisGraphicsElement
52562 .transition()
52563 .duration(duration)
52564 .ease(easing)
52565 .call(axes.y1.axis)
52566 .call(SvgCartesianAxes.updateAnimatedTickTooltips, axes.y1.values);
52567 }
52568 else {
52569 y1AxisGraphicsElement
52570 .call(axes.y1.axis);
52571 }
52572 y1AxisGraphicsElement
52573 .call(SvgCartesianAxes.darkenZeroLine)
52574 .call(SvgCartesianAxes.setAxisLabelColor, yLabelColor);
52575 if (tickLabelMargins.yLeft >= leftRightMarginLimit) {
52576 y1AxisGraphicsElement.selectAll('text')
52577 .call(visuals.AxisHelper.LabelLayoutStrategy.clip,
52578 // Can't use padding space to render text, so subtract that from available space for ellipses calculations
52579 leftRightMarginLimit - y1TickPadding, powerbi.TextMeasurementService.svgEllipsis);
52580 }
52581 if (!duration) {
52582 SvgCartesianAxes.updateTickTooltips(y1AxisGraphicsElement, axes.y1.values);
52583 }
52584 if (axes.y2 && (!this.valueAxisProperties || this.valueAxisProperties['secShow'] == null || this.valueAxisProperties['secShow'])) {
52585 y2LabelColor = this.valueAxisProperties && this.valueAxisProperties['secLabelColor'] ? this.valueAxisProperties['secLabelColor'] : null;
52586 var y2TickPadding = showY1OnRight ? axesLayout.tickPadding.left : axesLayout.tickPadding.right;
52587 axes.y2.axis
52588 .tickSize(SvgCartesianAxes.Y2TickSize)
52589 .tickPadding(y2TickPadding)
52590 .orient(showY1OnRight ? visuals.yAxisPosition.left.toLowerCase() : visuals.yAxisPosition.right.toLowerCase());
52591 var y2AxisGraphicsElement = this.y2AxisGraphicsContext;
52592 if (duration) {
52593 y2AxisGraphicsElement
52594 .transition()
52595 .duration(duration)
52596 .ease(easing)
52597 .call(axes.y2.axis)
52598 .call(SvgCartesianAxes.updateAnimatedTickTooltips, axes.y2.values);
52599 }
52600 else {
52601 y2AxisGraphicsElement
52602 .call(axes.y2.axis);
52603 }
52604 y2AxisGraphicsElement
52605 .call(SvgCartesianAxes.darkenZeroLine)
52606 .call(SvgCartesianAxes.setAxisLabelColor, y2LabelColor);
52607 if (tickLabelMargins.yRight >= leftRightMarginLimit) {
52608 y2AxisGraphicsElement.selectAll('text')
52609 .call(visuals.AxisHelper.LabelLayoutStrategy.clip,
52610 // Can't use padding space to render text, so subtract that from available space for ellipses calculations
52611 leftRightMarginLimit - y2TickPadding, powerbi.TextMeasurementService.svgEllipsis);
52612 }
52613 if (!duration) {
52614 SvgCartesianAxes.updateTickTooltips(y2AxisGraphicsElement, axes.y2.values);
52615 }
52616 }
52617 else {
52618 this.y2AxisGraphicsContext.selectAll('*').remove();
52619 }
52620 }
52621 else {
52622 this.y1AxisGraphicsContext.selectAll('*').remove();
52623 this.y2AxisGraphicsContext.selectAll('*').remove();
52624 }
52625 // Axis labels
52626 //TODO: Add label for second Y axis for combo chart
52627 var axisLabels = axesLayout.axisLabels;
52628 var chartHasAxisLabels = (axisLabels.x != null) || (axisLabels.y != null || axisLabels.y2 != null);
52629 if (chartHasAxisLabels) {
52630 var hideXAxisTitle = !this.axes.shouldRenderAxisTitle(axes.x, /* defaultValue */ true, /* secondary */ false);
52631 var hideYAxisTitle = !this.axes.shouldRenderAxisTitle(axes.y1, /* defaultValue */ true, /* secondary */ false);
52632 var hideY2AxisTitle = !this.axes.shouldRenderAxisTitle(axes.y2, /* defaultValue */ false, /* secondary */ true);
52633 var renderAxisOptions = {
52634 axisLabels: axisLabels,
52635 viewport: viewport,
52636 margin: margin,
52637 hideXAxisTitle: hideXAxisTitle,
52638 hideYAxisTitle: hideYAxisTitle,
52639 hideY2AxisTitle: hideY2AxisTitle,
52640 xLabelColor: xLabelColor,
52641 yLabelColor: yLabelColor,
52642 y2LabelColor: y2LabelColor,
52643 fontSize: SvgCartesianAxes.AxisLabelFontSize,
52644 };
52645 this.renderAxesLabels(renderAxisOptions);
52646 }
52647 else {
52648 this.axisGraphicsContext.selectAll('.xAxisLabel').remove();
52649 this.axisGraphicsContext.selectAll('.yAxisLabel').remove();
52650 }
52651 this.translateAxes(viewport, margin);
52652 };
52653 SvgCartesianAxes.prototype.renderAxesLabels = function (options) {
52654 debug.assertValue(options, 'options');
52655 debug.assertValue(options.viewport, 'options.viewport');
52656 debug.assertValue(options.axisLabels, 'options.axisLabels');
52657 this.axisGraphicsContext.selectAll('.xAxisLabel').remove();
52658 this.axisGraphicsContext.selectAll('.yAxisLabel').remove();
52659 var margin = options.margin;
52660 var width = options.viewport.width - (margin.left + margin.right);
52661 var height = options.viewport.height;
52662 var fontSize = options.fontSize;
52663 var heightOffset = fontSize;
52664 var showOnRight = this.axes.shouldShowY1OnRight();
52665 if (!options.hideXAxisTitle) {
52666 var xAxisLabel = this.axisGraphicsContext.append("text")
52667 .style("text-anchor", "middle")
52668 .text(options.axisLabels.x)
52669 .call(function (text) {
52670 text.each(function () {
52671 var text = d3.select(this);
52672 text.attr({
52673 "class": "xAxisLabel",
52674 "transform": visuals.SVGUtil.translate(width / 2, height - heightOffset)
52675 });
52676 });
52677 });
52678 xAxisLabel.style("fill", options.xLabelColor ? options.xLabelColor.solid.color : null);
52679 xAxisLabel.call(visuals.AxisHelper.LabelLayoutStrategy.clip, width, powerbi.TextMeasurementService.svgEllipsis)
52680 .call(visuals.tooltipUtils.tooltipUpdate, [options.axisLabels.x]);
52681 }
52682 if (!options.hideYAxisTitle) {
52683 var yAxisLabel = this.axisGraphicsContext.append("text")
52684 .style("text-anchor", "middle")
52685 .text(options.axisLabels.y)
52686 .call(function (text) {
52687 text.each(function () {
52688 var text = d3.select(this);
52689 text.attr({
52690 "class": "yAxisLabel",
52691 "transform": "rotate(-90)",
52692 "y": showOnRight ? width + margin.right - fontSize : -margin.left,
52693 "x": -((height - margin.top - margin.bottom) / 2),
52694 "dy": "1em",
52695 });
52696 });
52697 });
52698 yAxisLabel.style("fill", options.yLabelColor ? options.yLabelColor.solid.color : null);
52699 yAxisLabel.call(visuals.AxisHelper.LabelLayoutStrategy.clip, height - (margin.bottom + margin.top), powerbi.TextMeasurementService.svgEllipsis)
52700 .call(visuals.tooltipUtils.tooltipUpdate, [options.axisLabels.y]);
52701 }
52702 if (!options.hideY2AxisTitle && options.axisLabels.y2) {
52703 var y2AxisLabel = this.axisGraphicsContext.append("text")
52704 .style("text-anchor", "middle")
52705 .text(options.axisLabels.y2)
52706 .call(function (text) {
52707 text.each(function () {
52708 var text = d3.select(this);
52709 text.attr({
52710 "class": "yAxisLabel",
52711 "transform": "rotate(-90)",
52712 "y": showOnRight ? -margin.left : width + margin.right - fontSize,
52713 "x": -((height - margin.top - margin.bottom) / 2),
52714 "dy": "1em",
52715 });
52716 });
52717 });
52718 y2AxisLabel.style("fill", options.y2LabelColor ? options.y2LabelColor.solid.color : null);
52719 y2AxisLabel.call(visuals.AxisHelper.LabelLayoutStrategy.clip, height - (margin.bottom + margin.top), powerbi.TextMeasurementService.svgEllipsis)
52720 .call(visuals.tooltipUtils.tooltipUpdate, [options.axisLabels.y2]);
52721 }
52722 };
52723 // Margin convention: http://bl.ocks.org/mbostock/3019563
52724 SvgCartesianAxes.prototype.translateAxes = function (viewport, margin) {
52725 var width = viewport.width - (margin.left + margin.right);
52726 var height = viewport.height - (margin.top + margin.bottom);
52727 var showY1OnRight = this.axes.shouldShowY1OnRight();
52728 this.xAxisGraphicsContext
52729 .attr('transform', visuals.SVGUtil.translate(0, height));
52730 this.y1AxisGraphicsContext
52731 .attr('transform', visuals.SVGUtil.translate(showY1OnRight ? width : 0, 0));
52732 this.y2AxisGraphicsContext
52733 .attr('transform', visuals.SVGUtil.translate(showY1OnRight ? 0 : width, 0));
52734 this.svgScrollable.attr({
52735 'x': 0,
52736 'width': viewport.width,
52737 'height': viewport.height
52738 });
52739 this.axisGraphicsContext.attr('transform', visuals.SVGUtil.translate(margin.left, margin.top));
52740 this.axisGraphicsContextScrollable.attr('transform', visuals.SVGUtil.translate(margin.left, margin.top));
52741 this.labelRegion.attr('transform', visuals.SVGUtil.translate(margin.left, margin.top));
52742 this.labelBackgroundRegion.attr('transform', visuals.SVGUtil.translate(margin.left, margin.top));
52743 if (this.axes.isXScrollBarVisible) {
52744 this.svgScrollable.attr({
52745 'x': margin.left
52746 });
52747 this.axisGraphicsContextScrollable.attr('transform', visuals.SVGUtil.translate(0, margin.top));
52748 this.labelRegion.attr('transform', visuals.SVGUtil.translate(0, margin.top));
52749 this.labelBackgroundRegion.attr('transform', visuals.SVGUtil.translate(0, margin.top));
52750 this.svgScrollable.attr('width', width);
52751 }
52752 else if (this.axes.isYScrollBarVisible) {
52753 this.svgScrollable.attr('height', height + margin.top);
52754 }
52755 };
52756 /**
52757 * Within the context of the given selection (g), find the offset of
52758 * the zero tick using the d3 attached datum of g.tick elements.
52759 * 'Classed' is undefined for transition selections
52760 */
52761 SvgCartesianAxes.darkenZeroLine = function (g) {
52762 // remove zero-line class from all first, filtering can cause lines that are no longer zero to still be dark (since the key is index based)
52763 g.selectAll('g.tick line').classed('zero-line', false);
52764 var zeroTick = g.selectAll('g.tick').filter(function (data) { return data === 0; }).node();
52765 if (zeroTick) {
52766 d3.select(zeroTick).select('line').classed('zero-line', true);
52767 }
52768 };
52769 SvgCartesianAxes.setAxisLabelColor = function (g, fill) {
52770 g.selectAll('g.tick text').style('fill', fill ? fill.solid.color : null);
52771 };
52772 // These match D3's internal axis padding values
52773 SvgCartesianAxes.AxisPadding = {
52774 left: 10,
52775 right: 10,
52776 top: 0,
52777 bottom: 13,
52778 };
52779 SvgCartesianAxes.AxisGraphicsContext = createClassAndSelector('axisGraphicsContext');
52780 SvgCartesianAxes.TickPaddingRotatedX = 5;
52781 SvgCartesianAxes.AxisLabelFontSize = 11;
52782 SvgCartesianAxes.Y2TickSize = -6;
52783 return SvgCartesianAxes;
52784 }());
52785 visuals.SvgCartesianAxes = SvgCartesianAxes;
52786 var CartesianAxes = (function () {
52787 function CartesianAxes(isScrollable, scrollbarWidth, trimOrdinalDataOnOverflow) {
52788 this.scrollbarWidth = scrollbarWidth;
52789 this.isScrollable = isScrollable;
52790 this.maxMarginFactor = CartesianAxes.MaxMarginFactor;
52791 this.yAxisOrientation = visuals.yAxisPosition.left;
52792 this.trimOrdinalDataOnOverflow = trimOrdinalDataOnOverflow;
52793 }
52794 CartesianAxes.prototype.shouldShowY1OnRight = function () {
52795 return this.yAxisOrientation === visuals.yAxisPosition.right;
52796 };
52797 CartesianAxes.prototype.isYAxisCategorical = function () {
52798 return this.layout && this.layout.axes.y1.isCategoryAxis;
52799 };
52800 CartesianAxes.prototype.hasCategoryAxis = function () {
52801 var axes = this.layout && this.layout.axes;
52802 if (!axes)
52803 return false;
52804 return this.isYAxisCategorical()
52805 ? axes.y1 && axes.y1.axis != null
52806 : axes.x && axes.x.axis != null;
52807 };
52808 CartesianAxes.prototype.hasY2Axis = function () {
52809 return this.layout && this.layout.axes.y2 != null;
52810 };
52811 CartesianAxes.prototype.getYAxisOrientation = function () {
52812 return this.yAxisOrientation;
52813 };
52814 CartesianAxes.prototype.setAxisLinesVisibility = function (axisLinesVisibility) {
52815 this.showLinesOnX = EnumExtensions.hasFlag(axisLinesVisibility, 3 /* ShowLinesOnBothAxis */) ||
52816 EnumExtensions.hasFlag(axisLinesVisibility, 1 /* ShowLinesOnXAxis */);
52817 this.showLinesOnY = EnumExtensions.hasFlag(axisLinesVisibility, 3 /* ShowLinesOnBothAxis */) ||
52818 EnumExtensions.hasFlag(axisLinesVisibility, 2 /* ShowLinesOnYAxis */);
52819 };
52820 CartesianAxes.prototype.setMaxMarginFactor = function (factor) {
52821 this.maxMarginFactor = factor;
52822 };
52823 CartesianAxes.prototype.update = function (dataViews) {
52824 if (dataViews && dataViews.length > 0) {
52825 var dataViewMetadata = dataViews[0].metadata;
52826 this.categoryAxisProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataViewMetadata);
52827 this.valueAxisProperties = visuals.CartesianHelper.getValueAxisProperties(dataViewMetadata);
52828 }
52829 var axisPosition = this.valueAxisProperties['position'];
52830 this.yAxisOrientation = axisPosition ? axisPosition.toString() : visuals.yAxisPosition.left;
52831 };
52832 CartesianAxes.prototype.addWarnings = function (warnings) {
52833 var axes = this.layout && this.layout.axes;
52834 if (axes && axes.x && axes.x.hasDisallowedZeroInDomain
52835 || axes.y1 && axes.y1.hasDisallowedZeroInDomain
52836 || axes.y2 && axes.y2.hasDisallowedZeroInDomain) {
52837 warnings.unshift(new visuals.ZeroValueWarning());
52838 }
52839 };
52840 /**
52841 * Computes the Cartesian Chart axes from the set of layers.
52842 */
52843 CartesianAxes.prototype.calculateAxes = function (layers, viewport, margin, playAxisControlLayout, textProperties, scrollbarVisible, existingAxisProperties, hideAxisTitles, ensureXDomain, ensureYDomain) {
52844 debug.assertValue(layers, 'layers');
52845 var visualOptions = {
52846 viewport: viewport,
52847 margin: margin,
52848 forcedXDomain: [this.categoryAxisProperties ? this.categoryAxisProperties['start'] : null, this.categoryAxisProperties ? this.categoryAxisProperties['end'] : null],
52849 forceMerge: this.valueAxisProperties && this.valueAxisProperties['secShow'] === false,
52850 showCategoryAxisLabel: false,
52851 showValueAxisLabel: false,
52852 trimOrdinalDataOnOverflow: this.trimOrdinalDataOnOverflow,
52853 categoryAxisScaleType: this.categoryAxisProperties && this.categoryAxisProperties['axisScale'] != null ? this.categoryAxisProperties['axisScale'] : DEFAULT_AXIS_SCALE_TYPE,
52854 valueAxisScaleType: this.valueAxisProperties && this.valueAxisProperties['axisScale'] != null ? this.valueAxisProperties['axisScale'] : DEFAULT_AXIS_SCALE_TYPE,
52855 categoryAxisDisplayUnits: this.categoryAxisProperties && this.categoryAxisProperties['labelDisplayUnits'] != null ? this.categoryAxisProperties['labelDisplayUnits'] : 0,
52856 valueAxisDisplayUnits: this.valueAxisProperties && this.valueAxisProperties['labelDisplayUnits'] != null ? this.valueAxisProperties['labelDisplayUnits'] : 0,
52857 categoryAxisPrecision: this.categoryAxisProperties ? visuals.CartesianHelper.getPrecision(this.categoryAxisProperties['labelPrecision']) : null,
52858 valueAxisPrecision: this.valueAxisProperties ? visuals.CartesianHelper.getPrecision(this.valueAxisProperties['labelPrecision']) : null,
52859 playAxisControlLayout: playAxisControlLayout,
52860 ensureXDomain: ensureXDomain,
52861 ensureYDomain: ensureYDomain,
52862 };
52863 var skipMerge = this.valueAxisProperties && this.valueAxisProperties['secShow'] === true;
52864 var yAxisWillMerge = false;
52865 var mergeResult;
52866 if (hasMultipleYAxes(layers) && !skipMerge) {
52867 mergeResult = tryMergeYDomains(layers, visualOptions);
52868 yAxisWillMerge = mergeResult.merged;
52869 if (yAxisWillMerge) {
52870 visualOptions.forcedYDomain = mergeResult.domain;
52871 }
52872 else {
52873 visualOptions.forcedTickCount = mergeResult.tickCount;
52874 }
52875 }
52876 if (this.valueAxisProperties) {
52877 visualOptions.forcedYDomain = visuals.AxisHelper.applyCustomizedDomain([this.valueAxisProperties['start'], this.valueAxisProperties['end']], visualOptions.forcedYDomain);
52878 }
52879 var result;
52880 for (var layerNumber = 0, len = layers.length; layerNumber < len; layerNumber++) {
52881 var currentlayer = layers[layerNumber];
52882 if (layerNumber === 1 && !yAxisWillMerge) {
52883 visualOptions.forcedYDomain = this.valueAxisProperties ? [this.valueAxisProperties['secStart'], this.valueAxisProperties['secEnd']] : null;
52884 visualOptions.valueAxisScaleType = this.valueAxisProperties && this.valueAxisProperties['secAxisScale'] != null ? this.valueAxisProperties['secAxisScale'] : DEFAULT_AXIS_SCALE_TYPE;
52885 visualOptions.valueAxisDisplayUnits = this.valueAxisProperties && this.valueAxisProperties['secLabelDisplayUnits'] != null ? this.valueAxisProperties['secLabelDisplayUnits'] : 0;
52886 visualOptions.valueAxisPrecision = this.valueAxisProperties ? visuals.CartesianHelper.getPrecision(this.valueAxisProperties['secLabelPrecision']) : null;
52887 }
52888 visualOptions.showCategoryAxisLabel = (!!this.categoryAxisProperties && !!this.categoryAxisProperties['showAxisTitle']); //here
52889 visualOptions.showValueAxisLabel = shouldShowYAxisLabel(layerNumber, this.valueAxisProperties, yAxisWillMerge);
52890 var axes = currentlayer.calculateAxesProperties(visualOptions);
52891 if (layerNumber === 0) {
52892 result = {
52893 x: axes[0],
52894 y1: axes[1]
52895 };
52896 }
52897 else if (axes && !result.y2) {
52898 if (result.x.usingDefaultDomain || _.isEmpty(result.x.dataDomain)) {
52899 visualOptions.showValueAxisLabel = (!!this.valueAxisProperties && !!this.valueAxisProperties['showAxisTitle']);
52900 var axes_1 = currentlayer.calculateAxesProperties(visualOptions);
52901 // no categories returned for the first layer, use second layer x-axis properties
52902 result.x = axes_1[0];
52903 // and 2nd value axis to be the primary
52904 result.y1 = axes_1[1];
52905 }
52906 else {
52907 // make sure all layers use the same x-axis/scale for drawing
52908 currentlayer.overrideXScale(result.x);
52909 if (!yAxisWillMerge && !axes[1].usingDefaultDomain)
52910 result.y2 = axes[1];
52911 }
52912 }
52913 if (existingAxisProperties && existingAxisProperties.x) {
52914 result.x.willLabelsFit = existingAxisProperties.x.willLabelsFit;
52915 result.x.willLabelsWordBreak = existingAxisProperties.x.willLabelsWordBreak;
52916 }
52917 else {
52918 var width = viewport.width - (margin.left + margin.right);
52919 result.x.willLabelsFit = visuals.AxisHelper.LabelLayoutStrategy.willLabelsFit(result.x, width, powerbi.TextMeasurementService.measureSvgTextWidth, textProperties);
52920 // If labels do not fit and we are not scrolling, try word breaking
52921 result.x.willLabelsWordBreak = (!result.x.willLabelsFit && !scrollbarVisible) && visuals.AxisHelper.LabelLayoutStrategy.willLabelsWordBreak(result.x, margin, width, powerbi.TextMeasurementService.measureSvgTextWidth, powerbi.TextMeasurementService.estimateSvgTextHeight, powerbi.TextMeasurementService.getTailoredTextOrDefault, textProperties);
52922 }
52923 }
52924 // Adjust for axis titles
52925 if (hideAxisTitles) {
52926 result.x.axisLabel = null;
52927 result.y1.axisLabel = null;
52928 if (result.y2) {
52929 result.y2.axisLabel = null;
52930 }
52931 }
52932 this.addUnitTypeToAxisLabels(result);
52933 return result;
52934 };
52935 /**
52936 * Negotiate the axes regions, the plot area, and determine if we need a scrollbar for ordinal categories.
52937 * @param layers an array of Cartesian layout layers (column, line, etc.)
52938 * @param parentViewport the full viewport for the visual
52939 * @param padding the D3 axis padding values
52940 * @param playAxisControlLayout if this is a playable Cartesian chart, includes the layout for the play controls (start/stop, time slider)
52941 * @param hideAxisLabels forces axis titles to be hidden
52942 * @param textProperties text properties to be used by text measurement
52943 * @param interactivityRightMargin extra right margin for the interactivity
52944 * @param ensureXDomain if non null, includes values that must be part of the axis domain
52945 * @param ensureYDomain if non null, includes values that must be part of the axis domain
52946 */
52947 CartesianAxes.prototype.negotiateAxes = function (layers, parentViewport, padding, playAxisControlLayout, hideAxisLabels, textProperties, interactivityRightMargin, ensureXDomain, ensureYDomain) {
52948 // 1> MinMargins -> some initial axis properties / text
52949 // 2> Get axis margins for the initial text, no rotateXTickLabels90. margins grown? -> axis properties / text again (possibly more tick labels now)
52950 // ?> do we have more labels? do we need rotate? are we done?
52951 // 3> margins again (rotate? margins grow?) -> text again (less tick labls now?)
52952 // FREEZE PROPERTIES THAT CAN CHANGE
52953 // 4> margins (final), axes (final)
52954 // 1.a) initialize margins
52955 var margin = powerbi.Prototype.inherit(CartesianAxes.MinimumMargin);
52956 var viewport = powerbi.Prototype.inherit(parentViewport);
52957 var leftRightMarginLimit = viewport.width * this.maxMarginFactor;
52958 var bottomMarginLimit = Math.max(CartesianAxes.MinimumMargin.bottom, Math.ceil(viewport.height * this.maxMarginFactor));
52959 var marginLimits = {
52960 left: leftRightMarginLimit,
52961 right: leftRightMarginLimit,
52962 top: 0,
52963 bottom: bottomMarginLimit,
52964 };
52965 // 1.b) Calculate axis properties using initial margins
52966 var axes = this.calculateAxes(layers, viewport, margin, playAxisControlLayout, textProperties,
52967 /*scrollbarVisible*/ false,
52968 /*previousAxisProperties*/ null, hideAxisLabels, ensureXDomain, ensureYDomain);
52969 // these are used by getTickLabelMargins
52970 var renderXAxis = this.shouldRenderAxis(axes.x);
52971 var renderY1Axis = this.shouldRenderAxis(axes.y1);
52972 var renderY2Axis = this.shouldRenderAxis(axes.y2, true);
52973 var showY1OnRight = this.shouldShowY1OnRight();
52974 var plotArea = {
52975 width: viewport.width - (margin.left + margin.right),
52976 height: viewport.height - (margin.top + margin.bottom)
52977 };
52978 var isScalar = false;
52979 if (!_.isEmpty(layers)) {
52980 if (layers[0].getVisualCategoryAxisIsScalar)
52981 isScalar = layers[0].getVisualCategoryAxisIsScalar();
52982 }
52983 // 2.a) calculate axis tick margins
52984 var tickLabelMargins = undefined;
52985 tickLabelMargins = visuals.AxisHelper.getTickLabelMargins(plotArea, marginLimits.left, powerbi.TextMeasurementService.measureSvgTextWidth, powerbi.TextMeasurementService.estimateSvgTextHeight, axes, marginLimits.bottom, textProperties,
52986 /*scrolling*/ false, showY1OnRight, renderXAxis, renderY1Axis, renderY2Axis);
52987 margin = this.updateAxisMargins(axes, tickLabelMargins, padding, showY1OnRight, renderY1Axis, renderY2Axis, isScalar ? 0 : interactivityRightMargin);
52988 // if any of these change, we need to calculate margins again
52989 var previousTickCountY1 = axes.y1 && axes.y1.values.length;
52990 var previousTickCountY2 = axes.y2 && axes.y2.values.length;
52991 var previousWillFitX = axes.x && axes.x.willLabelsFit;
52992 var previousWillBreakX = axes.x && axes.x.willLabelsWordBreak;
52993 // 2.b) Re-calculate the axes with the new margins.
52994 axes = this.calculateAxes(layers, viewport, margin, playAxisControlLayout, textProperties,
52995 /*scrollbarVisible*/ false,
52996 /*previousAxes*/ null, hideAxisLabels, ensureXDomain, ensureYDomain);
52997 plotArea.width = viewport.width - (margin.left + margin.right);
52998 plotArea.height = viewport.height - (margin.top + margin.bottom);
52999 // check properties that affect getTickLabelMargin - if these are the same, we don't need to calculate axis margins again
53000 var preferredPlotArea = this.getPreferredPlotArea(axes, layers, isScalar);
53001 var rotateXTickLabels90 = !this.willAllCategoriesFitInPlotArea(plotArea, preferredPlotArea);
53002 var allDone = ((!axes.y1 || axes.y1.values.length === previousTickCountY1)
53003 && (!axes.y2 || axes.y2.values.length === previousTickCountY2)
53004 && (!axes.x || axes.x.willLabelsFit === previousWillFitX)
53005 && (!axes.x || axes.x.willLabelsWordBreak === previousWillBreakX)
53006 && !rotateXTickLabels90);
53007 this.isXScrollBarVisible = false;
53008 this.isYScrollBarVisible = false;
53009 if (!allDone) {
53010 // 3.a) calculate axis tick margins
53011 tickLabelMargins = visuals.AxisHelper.getTickLabelMargins(plotArea, marginLimits.left, powerbi.TextMeasurementService.measureSvgTextWidth, powerbi.TextMeasurementService.estimateSvgTextHeight, axes, marginLimits.bottom, textProperties, rotateXTickLabels90, showY1OnRight, renderXAxis, renderY1Axis, renderY2Axis);
53012 margin = this.updateAxisMargins(axes, tickLabelMargins, padding, showY1OnRight, renderY1Axis, renderY2Axis, isScalar ? 0 : interactivityRightMargin);
53013 // 3.b) Re-calculate the axes with the new final margins
53014 axes = this.calculateAxes(layers, viewport, margin, playAxisControlLayout, textProperties,
53015 /*scrollbarVisible*/ rotateXTickLabels90, axes, hideAxisLabels, ensureXDomain, ensureYDomain);
53016 // now we can determine if we need actual scrolling
53017 // rotateXTickLabels90 will give more plotArea to categories since the left-overflow of a rotated category label doesn't exist anymore
53018 plotArea.width = viewport.width - (margin.left + margin.right);
53019 plotArea.height = viewport.height - (margin.top + margin.bottom);
53020 preferredPlotArea = this.getPreferredPlotArea(axes, layers, isScalar);
53021 var willScroll = !this.willAllCategoriesFitInPlotArea(plotArea, preferredPlotArea);
53022 if (willScroll) {
53023 if (this.showLinesOnY) {
53024 this.isXScrollBarVisible = true;
53025 plotArea.height -= this.scrollbarWidth;
53026 viewport.height -= this.scrollbarWidth;
53027 }
53028 if (this.showLinesOnX) {
53029 this.isYScrollBarVisible = true;
53030 plotArea.width -= this.scrollbarWidth;
53031 viewport.width -= this.scrollbarWidth;
53032 }
53033 // 3.c) Re-calculate the axes with the final margins (and the updated viewport - scrollbarWidth)
53034 axes = this.calculateAxes(layers, viewport, margin, playAxisControlLayout, textProperties,
53035 /*scrollbarVisible*/ true, axes, hideAxisLabels, ensureXDomain, ensureYDomain);
53036 }
53037 }
53038 ///////DONE
53039 var axisLabels = hideAxisLabels ?
53040 { x: null, y: null, y2: null } :
53041 { x: axes.x.axisLabel, y: axes.y1.axisLabel, y2: axes.y2 ? axes.y2.axisLabel : null };
53042 this.layout = {
53043 axes: axes,
53044 axisLabels: axisLabels,
53045 margin: margin,
53046 marginLimits: marginLimits,
53047 viewport: viewport,
53048 plotArea: plotArea,
53049 preferredPlotArea: preferredPlotArea,
53050 tickLabelMargins: tickLabelMargins,
53051 tickPadding: padding,
53052 rotateXTickLabels90: rotateXTickLabels90,
53053 };
53054 return this.layout;
53055 };
53056 CartesianAxes.prototype.getPreferredPlotArea = function (axes, layers, isScalar) {
53057 var preferredPlotArea;
53058 if (!isScalar && this.isScrollable && !_.isEmpty(layers) && layers[0].getPreferredPlotArea) {
53059 var categoryThickness = this.showLinesOnY ? axes.x.categoryThickness : axes.y1.categoryThickness;
53060 var categoryCount = this.showLinesOnY ? axes.x.dataDomain.length : axes.y1.dataDomain.length;
53061 preferredPlotArea = layers[0].getPreferredPlotArea(isScalar, categoryCount, categoryThickness);
53062 }
53063 return preferredPlotArea;
53064 };
53065 CartesianAxes.prototype.willAllCategoriesFitInPlotArea = function (plotArea, preferredPlotArea) {
53066 if (this.showLinesOnY && preferredPlotArea && powerbi.Double.greaterWithPrecision(preferredPlotArea.width, plotArea.width)) {
53067 return false;
53068 }
53069 if (this.showLinesOnX && preferredPlotArea && powerbi.Double.greaterWithPrecision(preferredPlotArea.height, plotArea.height)) {
53070 return false;
53071 }
53072 return true;
53073 };
53074 CartesianAxes.prototype.updateAxisMargins = function (axes, tickLabelMargins, padding, showY1OnRight, renderY1Axis, renderY2Axis, interactivityRightMargin) {
53075 // We look at the y axes as main and second sides, if the y axis orientation is right then the main side represents the right side.
53076 var maxY1Padding = showY1OnRight ? tickLabelMargins.yRight : tickLabelMargins.yLeft, maxY2Padding = showY1OnRight ? tickLabelMargins.yLeft : tickLabelMargins.yRight, maxXAxisBottom = tickLabelMargins.xMax;
53077 maxY1Padding += padding.left;
53078 if ((renderY2Axis && !showY1OnRight) || (showY1OnRight && renderY1Axis))
53079 maxY2Padding += padding.right;
53080 maxXAxisBottom += padding.bottom;
53081 var axisLabels = { x: axes.x.axisLabel, y: axes.y1.axisLabel, y2: axes.y2 ? axes.y2.axisLabel : null };
53082 if (axisLabels.x != null)
53083 maxXAxisBottom += CartesianAxes.XAxisLabelPadding;
53084 if (axisLabels.y != null)
53085 maxY1Padding += CartesianAxes.YAxisLabelPadding;
53086 if (axisLabels.y2 != null)
53087 maxY2Padding += CartesianAxes.YAxisLabelPadding;
53088 var margin = powerbi.Prototype.inherit(CartesianAxes.MinimumMargin);
53089 margin.left = showY1OnRight ? maxY2Padding : maxY1Padding;
53090 margin.right = showY1OnRight ? maxY1Padding : maxY2Padding;
53091 margin.right += interactivityRightMargin; // for mobile interactive legend
53092 margin.bottom = maxXAxisBottom;
53093 return margin;
53094 };
53095 CartesianAxes.prototype.isLogScaleAllowed = function (axisType) {
53096 var axes = this.layout && this.layout.axes;
53097 if (!axes)
53098 return false;
53099 switch (axisType) {
53100 case 0 /* X */:
53101 return axes.x.isLogScaleAllowed;
53102 case 1 /* Y1 */:
53103 return axes.y1.isLogScaleAllowed;
53104 case 2 /* Y2 */:
53105 return axes.y2 && axes.y2.isLogScaleAllowed;
53106 }
53107 };
53108 CartesianAxes.prototype.axesHaveTicks = function (viewport) {
53109 if (!this.layout)
53110 return false;
53111 var margin = this.layout.margin;
53112 var width = viewport.width - (margin.left + margin.right);
53113 var height = viewport.height - (margin.top + margin.bottom);
53114 // TODO: this is never the case, remove.
53115 if (visuals.AxisHelper.getRecommendedNumberOfTicksForXAxis(width) === 0
53116 && visuals.AxisHelper.getRecommendedNumberOfTicksForYAxis(height) === 0) {
53117 return false;
53118 }
53119 return true;
53120 };
53121 CartesianAxes.prototype.shouldRenderAxisTitle = function (axisProperties, defaultValue, secondary) {
53122 var propertyName = secondary ? 'secShowAxisTitle' : 'showAxisTitle';
53123 return !!this.getAxisProperty(axisProperties, propertyName, defaultValue);
53124 };
53125 CartesianAxes.prototype.shouldRenderAxis = function (axisProperties, secondary) {
53126 if (secondary === void 0) { secondary = false; }
53127 if (!axisProperties)
53128 return false;
53129 var propertyName = secondary ? 'secShow' : 'show';
53130 return this.getAxisProperty(axisProperties, propertyName, true)
53131 && axisProperties.values
53132 && axisProperties.values.length > 0;
53133 };
53134 CartesianAxes.prototype.getAxisProperty = function (axisProperties, propertyName, defaultValue) {
53135 if (!axisProperties)
53136 return defaultValue;
53137 var properties = axisProperties.isCategoryAxis
53138 ? this.categoryAxisProperties
53139 : this.valueAxisProperties;
53140 if (properties && properties[propertyName] != null)
53141 return properties[propertyName];
53142 else
53143 return defaultValue;
53144 };
53145 // TODO: clean this up
53146 CartesianAxes.prototype.addUnitTypeToAxisLabels = function (axes) {
53147 var unitType = CartesianAxes.getUnitType(axes.x.formatter);
53148 if (axes.x.isCategoryAxis) {
53149 this.categoryAxisHasUnitType = unitType != null;
53150 }
53151 else {
53152 this.valueAxisHasUnitType = unitType != null;
53153 }
53154 if (axes.x.axisLabel && unitType) {
53155 if (axes.x.isCategoryAxis) {
53156 axes.x.axisLabel = visuals.AxisHelper.createAxisLabel(this.categoryAxisProperties, axes.x.axisLabel, unitType);
53157 }
53158 else {
53159 axes.x.axisLabel = visuals.AxisHelper.createAxisLabel(this.valueAxisProperties, axes.x.axisLabel, unitType);
53160 }
53161 }
53162 unitType = CartesianAxes.getUnitType(axes.y1.formatter);
53163 if (!axes.y1.isCategoryAxis) {
53164 this.valueAxisHasUnitType = unitType != null;
53165 }
53166 else {
53167 this.categoryAxisHasUnitType = unitType != null;
53168 }
53169 if (axes.y1.axisLabel && unitType) {
53170 if (!axes.y1.isCategoryAxis) {
53171 axes.y1.axisLabel = visuals.AxisHelper.createAxisLabel(this.valueAxisProperties, axes.y1.axisLabel, unitType);
53172 }
53173 else {
53174 axes.y1.axisLabel = visuals.AxisHelper.createAxisLabel(this.categoryAxisProperties, axes.y1.axisLabel, unitType);
53175 }
53176 }
53177 if (axes.y2) {
53178 var unitType_1 = CartesianAxes.getUnitType(axes.y2.formatter);
53179 this.secondaryValueAxisHasUnitType = unitType_1 != null;
53180 if (axes.y2.axisLabel && unitType_1) {
53181 axes.y2.axisLabel = visuals.AxisHelper.createAxisLabel(this.valueAxisProperties, axes.y2.axisLabel, unitType_1, true);
53182 }
53183 }
53184 };
53185 CartesianAxes.getUnitType = function (formatter) {
53186 if (formatter &&
53187 formatter.displayUnit &&
53188 formatter.displayUnit.value > 1)
53189 return formatter.displayUnit.title;
53190 };
53191 CartesianAxes.YAxisLabelPadding = 20;
53192 CartesianAxes.XAxisLabelPadding = 18;
53193 CartesianAxes.MaxMarginFactor = 0.25;
53194 CartesianAxes.MinimumMargin = {
53195 left: 1,
53196 right: 1,
53197 top: 8,
53198 bottom: 25,
53199 };
53200 return CartesianAxes;
53201 }());
53202 visuals.CartesianAxes = CartesianAxes;
53203 var CartesianLayerFactory;
53204 (function (CartesianLayerFactory) {
53205 function createLayers(type, objects, interactivityService, animator, isScrollable, tooltipsEnabled, lineChartLabelDensityEnabled) {
53206 if (isScrollable === void 0) { isScrollable = false; }
53207 var layers = [];
53208 var cartesianOptions = {
53209 isScrollable: isScrollable,
53210 animator: animator,
53211 interactivityService: interactivityService,
53212 tooltipsEnabled: tooltipsEnabled,
53213 lineChartLabelDensityEnabled: lineChartLabelDensityEnabled,
53214 };
53215 switch (type) {
53216 case 1 /* Area */:
53217 layers.push(createLineChartLayer(2 /* area */, /* inComboChart */ false, cartesianOptions));
53218 //layers.push(createLineChartLayer(LineChartType.default, /* inComboChart */ false, cartesianOptions, true));
53219 break;
53220 case 0 /* Line */:
53221 layers.push(createLineChartLayer(1 /* default */, /* inComboChart */ false, cartesianOptions));
53222 //layers.push(createLineChartLayer(LineChartType.default, /* inComboChart */ false, cartesianOptions, true));
53223 break;
53224 case 2 /* StackedArea */:
53225 layers.push(createLineChartLayer(16 /* stackedArea */, /* inComboChart */ false, cartesianOptions));
53226 break;
53227 case 9 /* Scatter */:
53228 layers.push(createScatterChartLayer(cartesianOptions));
53229 //layers.push(createLineChartLayer(LineChartType.default, /* inComboChart */ false, cartesianOptions, true));
53230 break;
53231 case 12 /* Waterfall */:
53232 layers.push(createWaterfallChartLayer(cartesianOptions));
53233 break;
53234 case 11 /* DataDot */:
53235 layers.push(createDataDotChartLayer(cartesianOptions));
53236 break;
53237 case 4 /* StackedColumn */:
53238 layers.push(createColumnChartLayer(visuals.ColumnChartType.stackedColumn, cartesianOptions));
53239 break;
53240 case 3 /* ClusteredColumn */:
53241 layers.push(createColumnChartLayer(visuals.ColumnChartType.clusteredColumn, cartesianOptions));
53242 break;
53243 case 8 /* HundredPercentStackedColumn */:
53244 layers.push(createColumnChartLayer(visuals.ColumnChartType.hundredPercentStackedColumn, cartesianOptions));
53245 break;
53246 case 6 /* StackedBar */:
53247 layers.push(createColumnChartLayer(visuals.ColumnChartType.stackedBar, cartesianOptions));
53248 break;
53249 case 5 /* ClusteredBar */:
53250 layers.push(createColumnChartLayer(visuals.ColumnChartType.clusteredBar, cartesianOptions));
53251 break;
53252 case 7 /* HundredPercentStackedBar */:
53253 layers.push(createColumnChartLayer(visuals.ColumnChartType.hundredPercentStackedBar, cartesianOptions));
53254 break;
53255 case 10 /* ComboChart */:
53256 var columnType = getComboColumnType();
53257 layers.push(createColumnChartLayer(columnType, cartesianOptions));
53258 layers.push(createLineChartLayer(1 /* default */, /* inComboChart */ true, cartesianOptions));
53259 break;
53260 case 13 /* LineClusteredColumnCombo */:
53261 layers.push(createColumnChartLayer(visuals.ColumnChartType.clusteredColumn, cartesianOptions));
53262 layers.push(createLineChartLayer(1 /* default */, /* inComboChart */ true, cartesianOptions));
53263 break;
53264 case 14 /* LineStackedColumnCombo */:
53265 layers.push(createColumnChartLayer(visuals.ColumnChartType.stackedColumn, cartesianOptions));
53266 layers.push(createLineChartLayer(1 /* default */, /* inComboChart */ true, cartesianOptions));
53267 break;
53268 case 15 /* DataDotClusteredColumnCombo */:
53269 layers.push(createColumnChartLayer(visuals.ColumnChartType.clusteredColumn, cartesianOptions));
53270 layers.push(createDataDotChartLayer(cartesianOptions));
53271 break;
53272 case 16 /* DataDotStackedColumnCombo */:
53273 layers.push(createColumnChartLayer(visuals.ColumnChartType.stackedColumn, cartesianOptions));
53274 layers.push(createDataDotChartLayer(cartesianOptions));
53275 break;
53276 }
53277 return layers;
53278 }
53279 CartesianLayerFactory.createLayers = createLayers;
53280 function createLineChartLayer(type, inComboChart, defaultOptions, isTrendLayer) {
53281 var options = {
53282 animator: defaultOptions.animator,
53283 interactivityService: defaultOptions.interactivityService,
53284 isScrollable: defaultOptions.isScrollable,
53285 tooltipsEnabled: !isTrendLayer && defaultOptions.tooltipsEnabled,
53286 chartType: type,
53287 lineChartLabelDensityEnabled: defaultOptions.lineChartLabelDensityEnabled,
53288 isTrendLayer: isTrendLayer,
53289 };
53290 if (inComboChart) {
53291 options.chartType = options.chartType | 8 /* lineShadow */;
53292 }
53293 return new visuals.LineChart(options);
53294 }
53295 function createScatterChartLayer(defaultOptions) {
53296 defaultOptions.isScrollable = false;
53297 return new visuals.ScatterChart(defaultOptions);
53298 }
53299 function createWaterfallChartLayer(defaultOptions) {
53300 return new visuals.WaterfallChart(defaultOptions);
53301 }
53302 function createDataDotChartLayer(defaultOptions) {
53303 return new visuals.DataDotChart(defaultOptions);
53304 }
53305 function createColumnChartLayer(type, defaultOptions) {
53306 var options = {
53307 animator: defaultOptions.animator,
53308 interactivityService: defaultOptions.interactivityService,
53309 isScrollable: defaultOptions.isScrollable,
53310 tooltipsEnabled: defaultOptions.tooltipsEnabled,
53311 chartType: type
53312 };
53313 return new visuals.ColumnChart(options);
53314 }
53315 function getComboColumnType(objects) {
53316 // This supports existing serialized forms of pinned combo-chart visuals
53317 var columnType = visuals.ColumnChartType.clusteredColumn;
53318 if (objects) {
53319 var comboChartTypes = objects.general;
53320 if (comboChartTypes) {
53321 switch (comboChartTypes.visualType1) {
53322 case 'Column':
53323 columnType = visuals.ColumnChartType.clusteredColumn;
53324 break;
53325 case 'ColumnStacked':
53326 columnType = visuals.ColumnChartType.stackedColumn;
53327 break;
53328 default:
53329 debug.assertFail('Unsupported cartesian chart type ' + comboChartTypes.visualType1);
53330 }
53331 // second visual is always LineChart (for now)
53332 if (comboChartTypes.visualType2) {
53333 debug.assert(comboChartTypes.visualType2 === 'Line', 'expecting a LineChart for VisualType2');
53334 }
53335 }
53336 }
53337 return columnType;
53338 }
53339 })(CartesianLayerFactory || (CartesianLayerFactory = {}));
53340 var SharedColorPalette = (function () {
53341 function SharedColorPalette(palette) {
53342 this.palette = palette;
53343 this.clearPreferredScale();
53344 }
53345 SharedColorPalette.prototype.getColorScaleByKey = function (scaleKey) {
53346 this.setPreferredScale(scaleKey);
53347 return this.preferredScale;
53348 };
53349 SharedColorPalette.prototype.getNewColorScale = function () {
53350 return this.preferredScale;
53351 };
53352 SharedColorPalette.prototype.getColorByIndex = function (index) {
53353 return this.palette.getColorByIndex(index);
53354 };
53355 SharedColorPalette.prototype.getSentimentColors = function () {
53356 return this.palette.getSentimentColors();
53357 };
53358 SharedColorPalette.prototype.getBasePickerColors = function () {
53359 return this.palette.getBasePickerColors();
53360 };
53361 SharedColorPalette.prototype.clearPreferredScale = function () {
53362 this.preferredScale = this.palette.getNewColorScale();
53363 this.rotated = false;
53364 };
53365 SharedColorPalette.prototype.rotateScale = function () {
53366 // We create a new rotated the scale such that the first color of the new scale is the first
53367 // free color of the previous scale. Note that the new scale does not have any colors allocated
53368 // to particular keys.
53369 this.preferredScale = this.preferredScale.clone();
53370 this.preferredScale.clearAndRotateScale();
53371 this.rotated = true;
53372 };
53373 SharedColorPalette.prototype.setPreferredScale = function (scaleKey) {
53374 if (!this.rotated) {
53375 // The first layer to express a preference sets the preferred scale.
53376 this.preferredScale = this.palette.getColorScaleByKey(scaleKey);
53377 }
53378 };
53379 return SharedColorPalette;
53380 }());
53381 visuals.SharedColorPalette = SharedColorPalette;
53382 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
53383})(powerbi || (powerbi = {}));
53384/*
53385 * Power BI Visualizations
53386 *
53387 * Copyright (c) Microsoft Corporation
53388 * All rights reserved.
53389 * MIT License
53390 *
53391 * Permission is hereby granted, free of charge, to any person obtaining a copy
53392 * of this software and associated documentation files (the ""Software""), to deal
53393 * in the Software without restriction, including without limitation the rights
53394 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53395 * copies of the Software, and to permit persons to whom the Software is
53396 * furnished to do so, subject to the following conditions:
53397 *
53398 * The above copyright notice and this permission notice shall be included in
53399 * all copies or substantial portions of the Software.
53400 *
53401 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53402 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53403 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53404 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53405 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53406 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53407 * THE SOFTWARE.
53408 */
53409var powerbi;
53410(function (powerbi) {
53411 var visuals;
53412 (function (visuals) {
53413 var EnumExtensions = jsCommon.EnumExtensions;
53414 var DataRoleHelper = powerbi.data.DataRoleHelper;
53415 var flagBar = 1 << 1;
53416 var flagColumn = 1 << 2;
53417 var flagClustered = 1 << 3;
53418 var flagStacked = 1 << 4;
53419 var flagStacked100 = flagStacked | (1 << 5);
53420 (function (ColumnChartType) {
53421 ColumnChartType[ColumnChartType["clusteredBar"] = flagBar | flagClustered] = "clusteredBar";
53422 ColumnChartType[ColumnChartType["clusteredColumn"] = flagColumn | flagClustered] = "clusteredColumn";
53423 ColumnChartType[ColumnChartType["hundredPercentStackedBar"] = flagBar | flagStacked100] = "hundredPercentStackedBar";
53424 ColumnChartType[ColumnChartType["hundredPercentStackedColumn"] = flagColumn | flagStacked100] = "hundredPercentStackedColumn";
53425 ColumnChartType[ColumnChartType["stackedBar"] = flagBar | flagStacked] = "stackedBar";
53426 ColumnChartType[ColumnChartType["stackedColumn"] = flagColumn | flagStacked] = "stackedColumn";
53427 })(visuals.ColumnChartType || (visuals.ColumnChartType = {}));
53428 var ColumnChartType = visuals.ColumnChartType;
53429 var RoleNames = {
53430 category: 'Category',
53431 series: 'Series',
53432 y: 'Y',
53433 };
53434 /**
53435 * Renders a stacked and clustered column chart.
53436 */
53437 var ColumnChart = (function () {
53438 function ColumnChart(options) {
53439 debug.assertValue(options, 'options');
53440 var chartType = options.chartType;
53441 debug.assertValue(chartType, 'chartType');
53442 this.chartType = chartType;
53443 this.categoryAxisType = null;
53444 this.animator = options.animator;
53445 this.isScrollable = options.isScrollable;
53446 this.tooltipsEnabled = options.tooltipsEnabled;
53447 this.interactivityService = options.interactivityService;
53448 }
53449 ColumnChart.customizeQuery = function (options) {
53450 var dataViewMapping = options.dataViewMappings[0];
53451 if (!dataViewMapping || !dataViewMapping.categorical || !dataViewMapping.categorical.categories)
53452 return;
53453 dataViewMapping.categorical.dataVolume = 4;
53454 if (visuals.CartesianChart.detectScalarMapping(dataViewMapping)) {
53455 var dataViewCategories = dataViewMapping.categorical.categories;
53456 dataViewCategories.dataReductionAlgorithm = { sample: {} };
53457 }
53458 };
53459 ColumnChart.getSortableRoles = function (options) {
53460 var dataViewMapping = options.dataViewMappings[0];
53461 if (!dataViewMapping || !dataViewMapping.categorical || !dataViewMapping.categorical.categories)
53462 return null;
53463 var dataViewCategories = dataViewMapping.categorical.categories;
53464 var categoryItems = dataViewCategories.for.in.items;
53465 if (!_.isEmpty(categoryItems)) {
53466 var categoryType = categoryItems[0].type;
53467 var objects = void 0;
53468 if (dataViewMapping.metadata)
53469 objects = dataViewMapping.metadata.objects;
53470 //TODO: column chart should be sortable by X if it has scalar axis
53471 // But currenly it doesn't support this. Return 'category' once
53472 // it is supported.
53473 if (!visuals.CartesianChart.getIsScalar(objects, visuals.columnChartProps.categoryAxis.axisType, categoryType)) {
53474 return ['Category', 'Y'];
53475 }
53476 }
53477 return null;
53478 };
53479 ColumnChart.prototype.updateVisualMetadata = function (x, y, margin) {
53480 this.xAxisProperties = x;
53481 this.yAxisProperties = y;
53482 this.margin = margin;
53483 };
53484 ColumnChart.prototype.init = function (options) {
53485 this.svg = options.svg;
53486 this.svg.classed(ColumnChart.ColumnChartClassName, true);
53487 this.unclippedGraphicsContext = this.svg.append('g').classed('columnChartUnclippedGraphicsContext', true);
53488 this.mainGraphicsContext = this.unclippedGraphicsContext.append('svg').classed('columnChartMainGraphicsContext', true);
53489 this.style = options.style;
53490 this.currentViewport = options.viewport;
53491 this.hostService = options.host;
53492 this.interactivity = options.interactivity;
53493 this.colors = this.style.colorPalette.dataColors;
53494 this.cartesianVisualHost = options.cartesianHost;
53495 this.options = options;
53496 this.isComboChart = visuals.ComboChart.isComboChart(options.chartType);
53497 this.element = options.element;
53498 };
53499 ColumnChart.prototype.getCategoryLayout = function (numCategoryValues, options) {
53500 var availableWidth;
53501 if (ColumnChart.isBar(this.chartType)) {
53502 availableWidth = this.currentViewport.height - (this.margin.top + this.margin.bottom);
53503 }
53504 else {
53505 availableWidth = this.currentViewport.width - (this.margin.left + this.margin.right);
53506 }
53507 var metaDataColumn = this.data ? this.data.categoryMetadata : undefined;
53508 var categoryDataType = visuals.AxisHelper.getCategoryValueType(metaDataColumn);
53509 var isScalar = this.data ? this.data.scalarCategoryAxis : false;
53510 var domain = visuals.AxisHelper.createDomain(this.data.series, categoryDataType, isScalar, options.forcedXDomain, options.ensureXDomain);
53511 return visuals.CartesianChart.getLayout(this.data, {
53512 availableWidth: availableWidth,
53513 categoryCount: numCategoryValues,
53514 domain: domain,
53515 isScalar: isScalar,
53516 isScrollable: this.isScrollable,
53517 trimOrdinalDataOnOverflow: options.trimOrdinalDataOnOverflow
53518 });
53519 };
53520 ColumnChart.converter = function (dataView, colors, is100PercentStacked, isScalar, dataViewMetadata, chartType, interactivityService, tooltipsEnabled) {
53521 if (is100PercentStacked === void 0) { is100PercentStacked = false; }
53522 if (isScalar === void 0) { isScalar = false; }
53523 if (dataViewMetadata === void 0) { dataViewMetadata = null; }
53524 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
53525 debug.assertValue(dataView, 'dataView');
53526 debug.assertValue(colors, 'colors');
53527 var xAxisCardProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataViewMetadata);
53528 var valueAxisProperties = visuals.CartesianHelper.getValueAxisProperties(dataViewMetadata);
53529 isScalar = visuals.CartesianHelper.isScalar(isScalar, xAxisCardProperties);
53530 var dataViewCat = visuals.ColumnUtil.applyUserMinMax(isScalar, dataView.categorical, xAxisCardProperties);
53531 var converterStrategy = new ColumnChartConverterHelper(dataView);
53532 var categoryInfo = visuals.converterHelper.getPivotedCategories(dataViewCat, visuals.columnChartProps.general.formatString);
53533 var categories = categoryInfo.categories, categoryFormatter = categoryInfo.categoryFormatter, categoryIdentities = categoryInfo.categoryIdentities, categoryMetadata = dataViewCat && dataViewCat.categories && dataViewCat.categories.length > 0 ? dataViewCat.categories[0].source : undefined;
53534 var labelSettings = visuals.dataLabelUtils.getDefaultColumnLabelSettings(is100PercentStacked || ColumnChart.isStacked(chartType));
53535 var defaultLegendLabelColor = visuals.LegendData.DefaultLegendLabelFillColor;
53536 var defaultDataPointColor = undefined;
53537 var showAllDataPoints = undefined;
53538 if (dataViewMetadata && dataViewMetadata.objects) {
53539 var objects = dataViewMetadata.objects;
53540 defaultDataPointColor = powerbi.DataViewObjects.getFillColor(objects, visuals.columnChartProps.dataPoint.defaultColor);
53541 showAllDataPoints = powerbi.DataViewObjects.getValue(objects, visuals.columnChartProps.dataPoint.showAllDataPoints);
53542 defaultLegendLabelColor = powerbi.DataViewObjects.getFillColor(objects, visuals.columnChartProps.legend.labelColor, visuals.LegendData.DefaultLegendLabelFillColor);
53543 var labelsObj = objects['labels'];
53544 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelsObj, labelSettings);
53545 }
53546 // Allocate colors
53547 var legendAndSeriesInfo = converterStrategy.getLegend(colors, defaultLegendLabelColor, defaultDataPointColor);
53548 var legend = legendAndSeriesInfo.legend.dataPoints;
53549 var seriesSources = legendAndSeriesInfo.seriesSources;
53550 // Determine data points
53551 var result = ColumnChart.createDataPoints(dataView, categories, categoryIdentities, legend, legendAndSeriesInfo.seriesObjects, converterStrategy, labelSettings, is100PercentStacked, isScalar, visuals.converterHelper.categoryIsAlsoSeriesRole(dataView, RoleNames.series, RoleNames.category), categoryInfo.categoryObjects, defaultDataPointColor, chartType, categoryMetadata, tooltipsEnabled);
53552 var columnSeries = result.series;
53553 var valuesMetadata = [];
53554 for (var j = 0, jlen = legend.length; j < jlen; j++) {
53555 valuesMetadata.push(seriesSources[j]);
53556 }
53557 var labels = visuals.converterHelper.createAxesLabels(xAxisCardProperties, valueAxisProperties, categoryMetadata, valuesMetadata);
53558 if (!ColumnChart.isColumn(chartType)) {
53559 // Replace between x and y axes
53560 var temp = labels.xAxisLabel;
53561 labels.xAxisLabel = labels.yAxisLabel;
53562 labels.yAxisLabel = temp;
53563 }
53564 if (interactivityService) {
53565 for (var _i = 0, columnSeries_1 = columnSeries; _i < columnSeries_1.length; _i++) {
53566 var series = columnSeries_1[_i];
53567 interactivityService.applySelectionStateToData(series.data);
53568 }
53569 interactivityService.applySelectionStateToData(legendAndSeriesInfo.legend.dataPoints);
53570 }
53571 return {
53572 categories: categories,
53573 categoryFormatter: categoryFormatter,
53574 series: columnSeries,
53575 valuesMetadata: valuesMetadata,
53576 legendData: legendAndSeriesInfo.legend,
53577 hasHighlights: result.hasHighlights,
53578 categoryMetadata: categoryMetadata,
53579 scalarCategoryAxis: isScalar,
53580 labelSettings: labelSettings,
53581 axesLabels: { x: labels.xAxisLabel, y: labels.yAxisLabel },
53582 hasDynamicSeries: result.hasDynamicSeries,
53583 isMultiMeasure: result.isMultiMeasure,
53584 defaultDataPointColor: defaultDataPointColor,
53585 showAllDataPoints: showAllDataPoints,
53586 };
53587 };
53588 ColumnChart.canSupportOverflow = function (chartType, seriesCount) {
53589 return !ColumnChart.isStacked(chartType) || seriesCount === 1;
53590 };
53591 ColumnChart.createDataPoints = function (dataView, categories, categoryIdentities, legend, seriesObjectsList, converterStrategy, defaultLabelSettings, is100PercentStacked, isScalar, isCategoryAlsoSeries, categoryObjectsList, defaultDataPointColor, chartType, categoryMetadata, tooltipsEnabled) {
53592 if (is100PercentStacked === void 0) { is100PercentStacked = false; }
53593 if (isScalar === void 0) { isScalar = false; }
53594 var dataViewCat = dataView.categorical;
53595 var grouped = dataViewCat && dataViewCat.values ? dataViewCat.values.grouped() : undefined;
53596 var categoryCount = categories.length;
53597 var seriesCount = legend.length;
53598 var columnSeries = [];
53599 if (seriesCount < 1 || categoryCount < 1)
53600 return { series: columnSeries, hasHighlights: false, hasDynamicSeries: false, isMultiMeasure: false };
53601 var dvCategories = dataViewCat.categories;
53602 categoryMetadata = !_.isEmpty(dvCategories) ? dvCategories[0].source : null;
53603 var categoryType = visuals.AxisHelper.getCategoryValueType(categoryMetadata);
53604 var isDateTime = visuals.AxisHelper.isDateTime(categoryType);
53605 var baseValuesPos = [], baseValuesNeg = [];
53606 var rawValues = [];
53607 var rawHighlightValues = [];
53608 var hasDynamicSeries = !!(dataViewCat.values && dataViewCat.values.source);
53609 var isMultiMeasure = !hasDynamicSeries && seriesCount > 1;
53610 var highlightsOverflow = false; // Overflow means the highlight larger than value or the signs being different
53611 var hasHighlights = converterStrategy.hasHighlightValues(0);
53612 for (var seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
53613 var seriesValues = [];
53614 var seriesHighlightValues = [];
53615 for (var categoryIndex = 0; categoryIndex < categoryCount; categoryIndex++) {
53616 var value = converterStrategy.getValueBySeriesAndCategory(seriesIndex, categoryIndex);
53617 seriesValues[categoryIndex] = value;
53618 if (hasHighlights) {
53619 var highlightValue = converterStrategy.getHighlightBySeriesAndCategory(seriesIndex, categoryIndex);
53620 seriesHighlightValues[categoryIndex] = highlightValue;
53621 // There are two cases where we don't use overflow logic; if all are false, use overflow logic appropriate for the chart.
53622 if (!((value >= 0 && highlightValue >= 0 && value >= highlightValue) ||
53623 (value <= 0 && highlightValue <= 0 && value <= highlightValue))) {
53624 highlightsOverflow = true;
53625 }
53626 }
53627 }
53628 rawValues.push(seriesValues);
53629 if (hasHighlights) {
53630 rawHighlightValues.push(seriesHighlightValues);
53631 }
53632 }
53633 if (highlightsOverflow && !ColumnChart.canSupportOverflow(chartType, seriesCount)) {
53634 highlightsOverflow = false;
53635 hasHighlights = false;
53636 rawValues = rawHighlightValues;
53637 }
53638 var dataPointObjects = categoryObjectsList, formatStringProp = visuals.columnChartProps.general.formatString;
53639 for (var seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
53640 var seriesDataPoints = [], legendItem = legend[seriesIndex], seriesLabelSettings = void 0;
53641 if (!hasDynamicSeries) {
53642 var labelsSeriesGroup = !_.isEmpty(grouped) && grouped[0].values ? grouped[0].values[seriesIndex] : null;
53643 var labelObjects = (labelsSeriesGroup && labelsSeriesGroup.source && labelsSeriesGroup.source.objects) ? labelsSeriesGroup.source.objects['labels'] : null;
53644 if (labelObjects) {
53645 seriesLabelSettings = powerbi.Prototype.inherit(defaultLabelSettings);
53646 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelObjects, seriesLabelSettings);
53647 }
53648 }
53649 columnSeries.push({
53650 displayName: legendItem.label,
53651 key: 'series' + seriesIndex,
53652 index: seriesIndex,
53653 data: seriesDataPoints,
53654 identity: legendItem.identity,
53655 color: legendItem.color,
53656 labelSettings: seriesLabelSettings,
53657 });
53658 if (seriesCount > 1)
53659 dataPointObjects = seriesObjectsList[seriesIndex];
53660 var valueColumnMetadata = dataViewCat.values[seriesIndex].source;
53661 var gradientMeasureIndex = visuals.GradientUtils.getGradientMeasureIndex(dataViewCat);
53662 var gradientValueColumn = visuals.GradientUtils.getGradientValueColumn(dataViewCat);
53663 var valueMeasureIndex = DataRoleHelper.getMeasureIndexOfRole(grouped, "Y");
53664 var pctFormatString = visuals.valueFormatter.getLocalizedString('Percentage');
53665 for (var categoryIndex = 0; categoryIndex < categoryCount; categoryIndex++) {
53666 if (seriesIndex === 0) {
53667 baseValuesPos.push(0);
53668 baseValuesNeg.push(0);
53669 }
53670 var value = visuals.AxisHelper.normalizeNonFiniteNumber(rawValues[seriesIndex][categoryIndex]);
53671 if (value == null) {
53672 // Optimization: Ignore null dataPoints from the fabricated category/series combination in the self cross-join.
53673 // However, we must retain the first series because it is used to compute things like axis scales, and value lookups.
53674 if (seriesIndex > 0)
53675 continue;
53676 }
53677 var originalValue = value;
53678 var categoryValue = categories[categoryIndex];
53679 // ignore variant measures
53680 if (isDateTime && categoryValue != null && !(categoryValue instanceof Date))
53681 continue;
53682 if (isDateTime && categoryValue)
53683 categoryValue = categoryValue.getTime();
53684 if (isScalar && (categoryValue == null || isNaN(categoryValue)))
53685 continue;
53686 var multipliers = void 0;
53687 if (is100PercentStacked)
53688 multipliers = visuals.StackedUtil.getStackedMultiplier(dataViewCat, categoryIndex, seriesCount, categoryCount, converterStrategy);
53689 var unadjustedValue = value, isNegative = value < 0;
53690 if (multipliers) {
53691 if (isNegative)
53692 value *= multipliers.neg;
53693 else
53694 value *= multipliers.pos;
53695 }
53696 var valueAbsolute = Math.abs(value);
53697 var position = void 0;
53698 if (isNegative) {
53699 position = baseValuesNeg[categoryIndex];
53700 if (!isNaN(valueAbsolute))
53701 baseValuesNeg[categoryIndex] -= valueAbsolute;
53702 }
53703 else {
53704 if (!isNaN(valueAbsolute))
53705 baseValuesPos[categoryIndex] += valueAbsolute;
53706 position = baseValuesPos[categoryIndex];
53707 }
53708 var seriesGroup = grouped && grouped.length > seriesIndex && grouped[seriesIndex].values ? grouped[seriesIndex].values[valueMeasureIndex] : null;
53709 var category = !_.isEmpty(dataViewCat.categories) ? dataViewCat.categories[0] : null;
53710 var identity = visuals.SelectionIdBuilder.builder()
53711 .withCategory(category, categoryIndex)
53712 .withSeries(dataViewCat.values, seriesGroup)
53713 .withMeasure(converterStrategy.getMeasureNameByIndex(seriesIndex))
53714 .createSelectionId();
53715 var rawCategoryValue = categories[categoryIndex];
53716 var color = ColumnChart.getDataPointColor(legendItem, categoryIndex, dataPointObjects);
53717 var gradientColumnForTooltip = gradientMeasureIndex === 0 ? null : gradientValueColumn;
53718 var tooltipInfo = void 0;
53719 if (tooltipsEnabled) {
53720 tooltipInfo = [];
53721 if (category) {
53722 tooltipInfo.push({
53723 displayName: category.source.displayName,
53724 value: visuals.converterHelper.formatFromMetadataColumn(rawCategoryValue, category.source, formatStringProp),
53725 });
53726 }
53727 if (hasDynamicSeries) {
53728 if (!category || category.source !== dataViewCat.values.source) {
53729 // Category/series on the same column -- don't repeat its value in the tooltip.
53730 tooltipInfo.push({
53731 displayName: dataViewCat.values.source.displayName,
53732 value: visuals.converterHelper.formatFromMetadataColumn(grouped[seriesIndex].name, dataViewCat.values.source, formatStringProp),
53733 });
53734 }
53735 }
53736 if (originalValue != null) {
53737 var valueString = void 0;
53738 var formattedOriginalValue = visuals.converterHelper.formatFromMetadataColumn(originalValue, valueColumnMetadata, formatStringProp);
53739 if (is100PercentStacked) {
53740 var originalPct = visuals.valueFormatter.format(valueAbsolute, pctFormatString);
53741 valueString = formattedOriginalValue + ' (' + originalPct + ')';
53742 }
53743 else {
53744 valueString = formattedOriginalValue;
53745 }
53746 tooltipInfo.push({
53747 displayName: valueColumnMetadata.displayName,
53748 value: valueString,
53749 });
53750 }
53751 if (gradientColumnForTooltip && gradientColumnForTooltip.values[categoryIndex] != null) {
53752 tooltipInfo.push({
53753 displayName: gradientColumnForTooltip.source.displayName,
53754 value: visuals.converterHelper.formatFromMetadataColumn(gradientColumnForTooltip.values[categoryIndex], gradientColumnForTooltip.source, formatStringProp),
53755 });
53756 }
53757 }
53758 var series = columnSeries[seriesIndex];
53759 var dataPointLabelSettings = (series.labelSettings) ? series.labelSettings : defaultLabelSettings;
53760 var labelColor = dataPointLabelSettings.labelColor;
53761 var lastValue = undefined;
53762 //Stacked column/bar label color is white by default (except last series)
53763 if ((ColumnChart.isStacked(chartType))) {
53764 lastValue = this.getStackedLabelColor(isNegative, seriesIndex, seriesCount, categoryIndex, rawValues);
53765 labelColor = (lastValue || (seriesIndex === seriesCount - 1 && !isNegative)) ? labelColor : visuals.dataLabelUtils.defaultInsideLabelColor;
53766 }
53767 var dataPoint = {
53768 categoryValue: categoryValue,
53769 value: value,
53770 position: position,
53771 valueAbsolute: valueAbsolute,
53772 valueOriginal: unadjustedValue,
53773 seriesIndex: seriesIndex,
53774 labelSettings: dataPointLabelSettings,
53775 categoryIndex: categoryIndex,
53776 color: color,
53777 selected: false,
53778 originalValue: value,
53779 originalPosition: position,
53780 originalValueAbsolute: valueAbsolute,
53781 identity: identity,
53782 key: identity.getKey(),
53783 tooltipInfo: tooltipInfo,
53784 labelFill: labelColor,
53785 labelFormatString: valueColumnMetadata.format,
53786 lastSeries: lastValue,
53787 chartType: chartType
53788 };
53789 seriesDataPoints.push(dataPoint);
53790 if (hasHighlights) {
53791 var valueHighlight = rawHighlightValues[seriesIndex][categoryIndex];
53792 var unadjustedValueHighlight = valueHighlight;
53793 var highlightedTooltip = true;
53794 if (valueHighlight === null) {
53795 valueHighlight = 0;
53796 highlightedTooltip = false;
53797 }
53798 if (is100PercentStacked) {
53799 valueHighlight *= multipliers.pos;
53800 }
53801 var absoluteValueHighlight = Math.abs(valueHighlight);
53802 var highlightPosition = position;
53803 if (valueHighlight > 0) {
53804 highlightPosition -= valueAbsolute - absoluteValueHighlight;
53805 }
53806 else if (valueHighlight === 0 && value > 0) {
53807 highlightPosition -= valueAbsolute;
53808 }
53809 var highlightIdentity = visuals.SelectionId.createWithHighlight(identity);
53810 var highlightedValueAndPct = void 0;
53811 var highlightedValueFormat = void 0;
53812 if (highlightedTooltip && unadjustedValueHighlight != null && valueHighlight != null) {
53813 var highlightedPct = visuals.valueFormatter.format(valueHighlight, pctFormatString);
53814 highlightedValueFormat = visuals.converterHelper.formatFromMetadataColumn(unadjustedValueHighlight, valueColumnMetadata, formatStringProp);
53815 highlightedValueAndPct = highlightedValueFormat + ' (' + highlightedPct + ')';
53816 }
53817 if (tooltipsEnabled) {
53818 var highlightValue = void 0;
53819 if (is100PercentStacked) {
53820 highlightValue = highlightedValueAndPct;
53821 }
53822 else {
53823 highlightValue = highlightedValueFormat;
53824 }
53825 if (highlightValue != null) {
53826 tooltipInfo.push({
53827 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
53828 value: highlightValue,
53829 });
53830 }
53831 }
53832 if (highlightedTooltip) {
53833 // Override non highlighted data point
53834 dataPoint.tooltipInfo = tooltipInfo;
53835 }
53836 var highlightDataPoint = {
53837 categoryValue: categoryValue,
53838 value: valueHighlight,
53839 position: highlightPosition,
53840 valueAbsolute: absoluteValueHighlight,
53841 valueOriginal: unadjustedValueHighlight,
53842 seriesIndex: seriesIndex,
53843 labelSettings: dataPointLabelSettings,
53844 categoryIndex: categoryIndex,
53845 color: color,
53846 selected: false,
53847 highlight: true,
53848 originalValue: value,
53849 originalPosition: position,
53850 originalValueAbsolute: valueAbsolute,
53851 drawThinner: highlightsOverflow,
53852 identity: highlightIdentity,
53853 key: highlightIdentity.getKey(),
53854 tooltipInfo: tooltipInfo,
53855 labelFormatString: valueColumnMetadata.format,
53856 labelFill: labelColor,
53857 lastSeries: lastValue,
53858 chartType: chartType
53859 };
53860 seriesDataPoints.push(highlightDataPoint);
53861 }
53862 }
53863 }
53864 return {
53865 series: columnSeries,
53866 hasHighlights: hasHighlights,
53867 hasDynamicSeries: hasDynamicSeries,
53868 isMultiMeasure: isMultiMeasure,
53869 };
53870 };
53871 ColumnChart.getDataPointColor = function (legendItem, categoryIndex, dataPointObjects) {
53872 debug.assertValue(legendItem, 'legendItem');
53873 debug.assertValue(categoryIndex, 'categoryIndex');
53874 debug.assertAnyValue(dataPointObjects, 'dataPointObjects');
53875 if (dataPointObjects) {
53876 var colorOverride = powerbi.DataViewObjects.getFillColor(dataPointObjects[categoryIndex], visuals.columnChartProps.dataPoint.fill);
53877 if (colorOverride)
53878 return colorOverride;
53879 }
53880 return legendItem.color;
53881 };
53882 ColumnChart.getStackedLabelColor = function (isNegative, seriesIndex, seriesCount, categoryIndex, rawValues) {
53883 var lastValue = !(isNegative && seriesIndex === seriesCount - 1 && seriesCount !== 1);
53884 //run for the next series and check if current series is last
53885 for (var i = seriesIndex + 1; i < seriesCount; i++) {
53886 var nextValues = visuals.AxisHelper.normalizeNonFiniteNumber(rawValues[i][categoryIndex]);
53887 if ((nextValues !== null) && (((!isNegative || (isNegative && seriesIndex === 0)) && nextValues > 0) || (isNegative && seriesIndex !== 0))) {
53888 lastValue = false;
53889 break;
53890 }
53891 }
53892 return lastValue;
53893 };
53894 ColumnChart.sliceSeries = function (series, endIndex, startIndex) {
53895 if (startIndex === void 0) { startIndex = 0; }
53896 var newSeries = [];
53897 if (series && series.length > 0) {
53898 for (var i = 0, len = series.length; i < len; i++) {
53899 var iNewSeries = newSeries[i] = powerbi.Prototype.inherit(series[i]);
53900 // TODO: [investigate] possible perf improvement.
53901 // if data[n].categoryIndex > endIndex implies data[n+1].categoryIndex > endIndex
53902 // then we could short circuit the filter loop.
53903 iNewSeries.data = series[i].data.filter(function (d) { return d.categoryIndex >= startIndex && d.categoryIndex < endIndex; });
53904 }
53905 }
53906 return newSeries;
53907 };
53908 ColumnChart.getInteractiveColumnChartDomElement = function (element) {
53909 return element.children("svg").get(0);
53910 };
53911 ColumnChart.prototype.setData = function (dataViews) {
53912 debug.assertValue(dataViews, "dataViews");
53913 var is100PctStacked = ColumnChart.isStacked100(this.chartType);
53914 this.data = {
53915 categories: [],
53916 categoryFormatter: null,
53917 series: [],
53918 valuesMetadata: [],
53919 legendData: null,
53920 hasHighlights: false,
53921 categoryMetadata: null,
53922 scalarCategoryAxis: false,
53923 labelSettings: visuals.dataLabelUtils.getDefaultColumnLabelSettings(is100PctStacked || ColumnChart.isStacked(this.chartType)),
53924 axesLabels: { x: null, y: null },
53925 hasDynamicSeries: false,
53926 defaultDataPointColor: null,
53927 isMultiMeasure: false,
53928 };
53929 if (dataViews.length > 0) {
53930 var dataView = this.dataView = dataViews[0];
53931 if (dataView && dataView.categorical) {
53932 var dvCategories = dataView.categorical.categories;
53933 var categoryMetadata = (dvCategories && dvCategories.length > 0)
53934 ? dvCategories[0].source
53935 : null;
53936 var categoryType = visuals.AxisHelper.getCategoryValueType(categoryMetadata);
53937 this.data = ColumnChart.converter(dataView, this.cartesianVisualHost.getSharedColors(), is100PctStacked, visuals.CartesianChart.getIsScalar(dataView.metadata ? dataView.metadata.objects : null, visuals.columnChartProps.categoryAxis.axisType, categoryType), dataView.metadata, this.chartType, this.interactivityService, this.tooltipsEnabled);
53938 }
53939 }
53940 this.setChartStrategy();
53941 };
53942 ColumnChart.prototype.setChartStrategy = function () {
53943 switch (this.chartType) {
53944 case ColumnChartType.clusteredBar:
53945 this.columnChart = new visuals.ClusteredBarChartStrategy();
53946 break;
53947 case ColumnChartType.clusteredColumn:
53948 this.columnChart = new visuals.ClusteredColumnChartStrategy();
53949 break;
53950 case ColumnChartType.stackedBar:
53951 case ColumnChartType.hundredPercentStackedBar:
53952 this.columnChart = new visuals.StackedBarChartStrategy();
53953 break;
53954 case ColumnChartType.stackedColumn:
53955 case ColumnChartType.hundredPercentStackedColumn:
53956 default:
53957 this.columnChart = new visuals.StackedColumnChartStrategy();
53958 break;
53959 }
53960 // For single series, render stacked as a clustered
53961 if (ColumnChart.isStacked(this.chartType) && this.data.series.length === 1) {
53962 switch (this.chartType) {
53963 case (ColumnChartType.stackedBar):
53964 this.columnChart = new visuals.ClusteredBarChartStrategy();
53965 break;
53966 case (ColumnChartType.stackedColumn):
53967 this.columnChart = new visuals.ClusteredColumnChartStrategy();
53968 break;
53969 }
53970 }
53971 };
53972 ColumnChart.prototype.calculateLegend = function () {
53973 // if we're in interactive mode, return the interactive legend
53974 if (this.interactivity && this.interactivity.isInteractiveLegend) {
53975 return this.createInteractiveLegendDataPoints(0);
53976 }
53977 var legendData = this.data ? this.data.legendData : null;
53978 var legendDataPoints = legendData ? legendData.dataPoints : [];
53979 if (_.isEmpty(legendDataPoints))
53980 return null;
53981 return legendData;
53982 };
53983 ColumnChart.prototype.hasLegend = function () {
53984 return this.data && (this.data.hasDynamicSeries || (this.data.series && this.data.series.length > 1));
53985 };
53986 ColumnChart.prototype.enumerateObjectInstances = function (enumeration, options) {
53987 switch (options.objectName) {
53988 case 'dataPoint':
53989 if (this.dataView && !visuals.GradientUtils.hasGradientRole(this.dataView.categorical))
53990 this.enumerateDataPoints(enumeration);
53991 break;
53992 case 'labels':
53993 this.enumerateDataLabels(enumeration);
53994 break;
53995 }
53996 };
53997 ColumnChart.prototype.enumerateDataLabels = function (enumeration) {
53998 var data = this.data, labelSettings = this.data.labelSettings, seriesCount = data.series.length, showLabelPerSeries = !data.hasDynamicSeries && (seriesCount > 1 || !data.categoryMetadata);
53999 //Draw default settings
54000 visuals.dataLabelUtils.enumerateDataLabels(this.getLabelSettingsOptions(enumeration, labelSettings, null, showLabelPerSeries));
54001 if (seriesCount === 0)
54002 return;
54003 //Draw series settings
54004 if (showLabelPerSeries && labelSettings.showLabelPerSeries) {
54005 for (var i = 0; i < seriesCount; i++) {
54006 var series = data.series[i], labelSettings_1 = (series.labelSettings) ? series.labelSettings : this.data.labelSettings;
54007 enumeration.pushContainer({ displayName: series.displayName });
54008 visuals.dataLabelUtils.enumerateDataLabels(this.getLabelSettingsOptions(enumeration, labelSettings_1, series));
54009 enumeration.popContainer();
54010 }
54011 }
54012 };
54013 ColumnChart.prototype.getLabelSettingsOptions = function (enumeration, labelSettings, series, showAll) {
54014 return {
54015 enumeration: enumeration,
54016 dataLabelsSettings: labelSettings,
54017 show: true,
54018 displayUnits: !ColumnChart.isStacked100(this.chartType),
54019 precision: true,
54020 selector: series && series.identity ? series.identity.getSelector() : null,
54021 showAll: showAll,
54022 fontSize: true,
54023 };
54024 };
54025 ColumnChart.prototype.enumerateDataPoints = function (enumeration) {
54026 var data = this.data;
54027 if (!data)
54028 return;
54029 var seriesCount = data.series.length;
54030 if (seriesCount === 0)
54031 return;
54032 if (data.hasDynamicSeries || seriesCount > 1 || !data.categoryMetadata) {
54033 for (var i = 0; i < seriesCount; i++) {
54034 var series = data.series[i];
54035 enumeration.pushInstance({
54036 objectName: 'dataPoint',
54037 displayName: series.displayName,
54038 selector: visuals.ColorHelper.normalizeSelector(series.identity.getSelector()),
54039 properties: {
54040 fill: { solid: { color: series.color } }
54041 },
54042 });
54043 }
54044 }
54045 else {
54046 // For single-category, single-measure column charts, the user can color the individual bars.
54047 var singleSeriesData = data.series[0].data;
54048 var categoryFormatter = data.categoryFormatter;
54049 // Add default color and show all slices
54050 enumeration.pushInstance({
54051 objectName: 'dataPoint',
54052 selector: null,
54053 properties: {
54054 defaultColor: { solid: { color: data.defaultDataPointColor || this.colors.getColorByIndex(0).value } }
54055 }
54056 }).pushInstance({
54057 objectName: 'dataPoint',
54058 selector: null,
54059 properties: {
54060 showAllDataPoints: !!data.showAllDataPoints
54061 }
54062 });
54063 if (data.showAllDataPoints) {
54064 for (var i = 0; i < singleSeriesData.length; i++) {
54065 var singleSeriesDataPoints = singleSeriesData[i], categoryValue = data.categories[i];
54066 enumeration.pushInstance({
54067 objectName: 'dataPoint',
54068 displayName: categoryFormatter ? categoryFormatter.format(categoryValue) : categoryValue,
54069 selector: visuals.ColorHelper.normalizeSelector(singleSeriesDataPoints.identity.getSelector(), /*isSingleSeries*/ true),
54070 properties: {
54071 fill: { solid: { color: singleSeriesDataPoints.color } }
54072 },
54073 });
54074 }
54075 }
54076 }
54077 };
54078 ColumnChart.prototype.calculateAxesProperties = function (options) {
54079 var data = this.data;
54080 this.currentViewport = options.viewport;
54081 var margin = this.margin = options.margin;
54082 var origCatgSize = (data && data.categories) ? data.categories.length : 0;
54083 var chartLayout = data ? this.getCategoryLayout(origCatgSize, options) : {
54084 categoryCount: 0,
54085 categoryThickness: visuals.CartesianChart.MinOrdinalRectThickness,
54086 outerPaddingRatio: visuals.CartesianChart.OuterPaddingRatio,
54087 isScalar: false
54088 };
54089 this.categoryAxisType = chartLayout.isScalar ? visuals.axisType.scalar : null;
54090 if (data && !chartLayout.isScalar && !this.isScrollable && options.trimOrdinalDataOnOverflow) {
54091 // trim data that doesn't fit on dashboard
54092 var catgSize = Math.min(origCatgSize, chartLayout.categoryCount);
54093 if (catgSize !== origCatgSize) {
54094 data = powerbi.Prototype.inherit(data);
54095 data.series = ColumnChart.sliceSeries(data.series, catgSize);
54096 data.categories = data.categories.slice(0, catgSize);
54097 }
54098 }
54099 this.columnChart.setData(data);
54100 var preferredPlotArea = this.getPreferredPlotArea(chartLayout.isScalar, chartLayout.categoryCount, chartLayout.categoryThickness);
54101 var is100Pct = ColumnChart.isStacked100(this.chartType);
54102 var chartContext = {
54103 height: preferredPlotArea.height,
54104 width: preferredPlotArea.width,
54105 duration: 0,
54106 hostService: this.hostService,
54107 unclippedGraphicsContext: this.unclippedGraphicsContext,
54108 mainGraphicsContext: this.mainGraphicsContext,
54109 margin: this.margin,
54110 layout: chartLayout,
54111 animator: this.animator,
54112 interactivityService: this.interactivityService,
54113 viewportHeight: this.currentViewport.height - (margin.top + margin.bottom),
54114 viewportWidth: this.currentViewport.width - (margin.left + margin.right),
54115 is100Pct: is100Pct,
54116 isComboChart: this.isComboChart,
54117 };
54118 this.ApplyInteractivity(chartContext);
54119 this.columnChart.setupVisualProps(chartContext);
54120 var ensureXDomain;
54121 var ensureYDomain;
54122 var isBarChart = ColumnChart.isBar(this.chartType);
54123 if (isBarChart) {
54124 var temp = options.forcedXDomain;
54125 options.forcedXDomain = options.forcedYDomain;
54126 options.forcedYDomain = temp;
54127 // In the case of clustered and stacked bar charts, the y1 reference line is a vertical line
54128 ensureXDomain = options.ensureYDomain;
54129 }
54130 else {
54131 ensureYDomain = options.ensureYDomain;
54132 }
54133 this.xAxisProperties = this.columnChart.setXScale(is100Pct, options.forcedTickCount, options.forcedXDomain, isBarChart ? options.valueAxisScaleType : options.categoryAxisScaleType, isBarChart ? options.valueAxisDisplayUnits : options.categoryAxisDisplayUnits, isBarChart ? options.valueAxisPrecision : options.categoryAxisPrecision, ensureXDomain);
54134 this.yAxisProperties = this.columnChart.setYScale(is100Pct, options.forcedTickCount, options.forcedYDomain, isBarChart ? options.categoryAxisScaleType : options.valueAxisScaleType, isBarChart ? options.categoryAxisDisplayUnits : options.valueAxisDisplayUnits, isBarChart ? options.categoryAxisPrecision : options.valueAxisPrecision, ensureYDomain);
54135 if (options.showCategoryAxisLabel && this.xAxisProperties.isCategoryAxis || options.showValueAxisLabel && !this.xAxisProperties.isCategoryAxis) {
54136 this.xAxisProperties.axisLabel = data.axesLabels.x;
54137 }
54138 else {
54139 this.xAxisProperties.axisLabel = null;
54140 }
54141 if (options.showValueAxisLabel && !this.yAxisProperties.isCategoryAxis || options.showCategoryAxisLabel && this.yAxisProperties.isCategoryAxis) {
54142 this.yAxisProperties.axisLabel = data.axesLabels.y;
54143 }
54144 else {
54145 this.yAxisProperties.axisLabel = null;
54146 }
54147 return [this.xAxisProperties, this.yAxisProperties];
54148 };
54149 ColumnChart.prototype.getPreferredPlotArea = function (isScalar, categoryCount, categoryThickness) {
54150 var plotArea = {
54151 height: this.currentViewport.height - this.margin.top - this.margin.bottom,
54152 width: this.currentViewport.width - this.margin.left - this.margin.right
54153 };
54154 if (this.isScrollable && !isScalar) {
54155 var preferredCategorySpan = visuals.CartesianChart.getPreferredCategorySpan(categoryCount, categoryThickness);
54156 if (ColumnChart.isBar(this.chartType)) {
54157 plotArea.height = Math.max(preferredCategorySpan, plotArea.height);
54158 }
54159 else
54160 plotArea.width = Math.max(preferredCategorySpan, plotArea.width);
54161 }
54162 return plotArea;
54163 };
54164 ColumnChart.prototype.ApplyInteractivity = function (chartContext) {
54165 var _this = this;
54166 var interactivity = this.interactivity;
54167 if (interactivity) {
54168 if (interactivity.dragDataPoint) {
54169 chartContext.onDragStart = function (datum) {
54170 if (!datum.identity)
54171 return;
54172 _this.hostService.onDragStart({
54173 event: d3.event,
54174 data: {
54175 data: datum.identity.getSelector()
54176 }
54177 });
54178 };
54179 }
54180 if (interactivity.isInteractiveLegend) {
54181 var dragMove = function () {
54182 var mousePoint = d3.mouse(_this.mainGraphicsContext[0][0]); // get the x and y for the column area itself
54183 var x = mousePoint[0];
54184 var y = mousePoint[1];
54185 var index = _this.columnChart.getClosestColumnIndex(x, y);
54186 _this.selectColumn(index);
54187 };
54188 var ColumnChartSvg = ColumnChart.getInteractiveColumnChartDomElement(this.element);
54189 //set click interaction on the visual
54190 this.svg.on('click', dragMove);
54191 //set click interaction on the background
54192 d3.select(ColumnChartSvg)
54193 .on('click', dragMove)
54194 .style('touch-action', 'none');
54195 var drag = d3.behavior.drag()
54196 .origin(Object)
54197 .on("drag", dragMove);
54198 //set drag interaction on the visual
54199 this.svg.call(drag);
54200 //set drag interaction on the background
54201 d3.select(ColumnChartSvg).call(drag);
54202 }
54203 }
54204 };
54205 ColumnChart.prototype.selectColumn = function (indexOfColumnSelected, force) {
54206 if (force === void 0) { force = false; }
54207 if (!force && this.lastInteractiveSelectedColumnIndex === indexOfColumnSelected)
54208 return; // same column, nothing to do here
54209 var legendData = this.createInteractiveLegendDataPoints(indexOfColumnSelected);
54210 var legendDataPoints = legendData.dataPoints;
54211 this.cartesianVisualHost.updateLegend(legendData);
54212 if (legendDataPoints.length > 0) {
54213 this.columnChart.selectColumn(indexOfColumnSelected, this.lastInteractiveSelectedColumnIndex);
54214 }
54215 this.lastInteractiveSelectedColumnIndex = indexOfColumnSelected;
54216 };
54217 ColumnChart.prototype.createInteractiveLegendDataPoints = function (columnIndex) {
54218 var data = this.data;
54219 if (!data || _.isEmpty(data.series))
54220 return { dataPoints: [] };
54221 var formatStringProp = visuals.columnChartProps.general.formatString;
54222 var legendDataPoints = [];
54223 var category = data.categories && data.categories[columnIndex];
54224 var allSeries = data.series;
54225 var dataPoints = data.legendData && data.legendData.dataPoints;
54226 var converterStrategy = new ColumnChartConverterHelper(this.dataView);
54227 for (var i = 0, len = allSeries.length; i < len; i++) {
54228 var measure = converterStrategy.getValueBySeriesAndCategory(i, columnIndex);
54229 var valueMetadata = data.valuesMetadata[i];
54230 var formattedLabel = visuals.converterHelper.getFormattedLegendLabel(valueMetadata, this.dataView.categorical.values, formatStringProp);
54231 var dataPointColor = void 0;
54232 if (allSeries.length === 1) {
54233 var series = allSeries[0];
54234 dataPointColor = series.data.length > columnIndex && series.data[columnIndex].color;
54235 }
54236 else {
54237 dataPointColor = dataPoints.length > i && dataPoints[i].color;
54238 }
54239 legendDataPoints.push({
54240 color: dataPointColor,
54241 icon: visuals.LegendIcon.Box,
54242 label: formattedLabel,
54243 category: data.categoryFormatter ? data.categoryFormatter.format(category) : category,
54244 measure: visuals.valueFormatter.format(measure, visuals.valueFormatter.getFormatString(valueMetadata, formatStringProp)),
54245 identity: visuals.SelectionId.createNull(),
54246 selected: false
54247 });
54248 }
54249 return { dataPoints: legendDataPoints };
54250 };
54251 ColumnChart.prototype.overrideXScale = function (xProperties) {
54252 this.xAxisProperties = xProperties;
54253 };
54254 ColumnChart.prototype.render = function (suppressAnimations) {
54255 var columnChartDrawInfo = this.columnChart.drawColumns(!suppressAnimations /* useAnimations */);
54256 var data = this.data;
54257 var margin = this.margin;
54258 var viewport = this.currentViewport;
54259 var height = viewport.height - (margin.top + margin.bottom);
54260 var width = viewport.width - (margin.left + margin.right);
54261 this.mainGraphicsContext
54262 .attr('height', height)
54263 .attr('width', width);
54264 if (this.tooltipsEnabled)
54265 visuals.TooltipManager.addTooltip(columnChartDrawInfo.eventGroup, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
54266 var allDataPoints = [];
54267 var behaviorOptions = undefined;
54268 if (this.interactivityService) {
54269 for (var i = 0, ilen = data.series.length; i < ilen; i++) {
54270 allDataPoints = allDataPoints.concat(data.series[i].data);
54271 }
54272 behaviorOptions = {
54273 datapoints: allDataPoints,
54274 eventGroup: columnChartDrawInfo.eventGroup,
54275 bars: columnChartDrawInfo.shapesSelection,
54276 hasHighlights: data.hasHighlights,
54277 mainGraphicsContext: this.mainGraphicsContext,
54278 viewport: columnChartDrawInfo.viewport,
54279 axisOptions: columnChartDrawInfo.axisOptions,
54280 showLabel: data.labelSettings.show
54281 };
54282 }
54283 if (this.interactivity && this.interactivity.isInteractiveLegend) {
54284 if (this.data.series.length > 0) {
54285 this.selectColumn(visuals.CartesianHelper.findMaxCategoryIndex(this.data.series), true); // start with the last column
54286 }
54287 }
54288 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
54289 return { dataPoints: allDataPoints, behaviorOptions: behaviorOptions, labelDataPoints: columnChartDrawInfo.labelDataPoints, labelsAreNumeric: true };
54290 };
54291 ColumnChart.prototype.onClearSelection = function () {
54292 if (this.interactivityService) {
54293 this.interactivityService.clearSelection();
54294 }
54295 };
54296 ColumnChart.prototype.getVisualCategoryAxisIsScalar = function () {
54297 return this.data ? this.data.scalarCategoryAxis : false;
54298 };
54299 ColumnChart.prototype.getSupportedCategoryAxisType = function () {
54300 var metaDataColumn = this.data ? this.data.categoryMetadata : undefined;
54301 var valueType = visuals.AxisHelper.getCategoryValueType(metaDataColumn);
54302 var isOrdinal = visuals.AxisHelper.isOrdinal(valueType);
54303 return isOrdinal ? visuals.axisType.categorical : visuals.axisType.both;
54304 };
54305 ColumnChart.prototype.setFilteredData = function (startIndex, endIndex) {
54306 var data = powerbi.Prototype.inherit(this.data);
54307 data.series = ColumnChart.sliceSeries(data.series, endIndex, startIndex);
54308 data.categories = data.categories.slice(startIndex, endIndex);
54309 this.columnChart.setData(data);
54310 return data;
54311 };
54312 ColumnChart.getLabelFill = function (labelColor, isInside, isCombo) {
54313 if (labelColor) {
54314 return labelColor;
54315 }
54316 if (isInside && !isCombo) {
54317 return visuals.NewDataLabelUtils.defaultInsideLabelColor;
54318 }
54319 return visuals.NewDataLabelUtils.defaultLabelColor;
54320 };
54321 ColumnChart.prototype.supportsTrendLine = function () {
54322 var isScalar = this.data ? this.data.scalarCategoryAxis : false;
54323 return this.chartType === ColumnChartType.clusteredColumn && isScalar;
54324 };
54325 ColumnChart.isBar = function (chartType) {
54326 return EnumExtensions.hasFlag(chartType, flagBar);
54327 };
54328 ColumnChart.isColumn = function (chartType) {
54329 return EnumExtensions.hasFlag(chartType, flagColumn);
54330 };
54331 ColumnChart.isClustered = function (chartType) {
54332 return EnumExtensions.hasFlag(chartType, flagClustered);
54333 };
54334 ColumnChart.isStacked = function (chartType) {
54335 return EnumExtensions.hasFlag(chartType, flagStacked);
54336 };
54337 ColumnChart.isStacked100 = function (chartType) {
54338 return EnumExtensions.hasFlag(chartType, flagStacked100);
54339 };
54340 ColumnChart.ColumnChartClassName = 'columnChart';
54341 ColumnChart.clusteredValidLabelPositions = [16 /* OutsideEnd */, 4 /* InsideEnd */, 1 /* InsideCenter */, 2 /* InsideBase */];
54342 ColumnChart.stackedValidLabelPositions = [1 /* InsideCenter */, 4 /* InsideEnd */, 2 /* InsideBase */];
54343 ColumnChart.SeriesClasses = jsCommon.CssConstants.createClassAndSelector('series');
54344 return ColumnChart;
54345 }());
54346 visuals.ColumnChart = ColumnChart;
54347 var ColumnChartConverterHelper = (function () {
54348 function ColumnChartConverterHelper(dataView) {
54349 this.dataView = dataView && dataView.categorical;
54350 this.reader = powerbi.data.createIDataViewCategoricalReader(dataView);
54351 }
54352 ColumnChartConverterHelper.prototype.getLegend = function (colors, defaultLegendLabelColor, defaultColor) {
54353 var legend = [];
54354 var seriesSources = [];
54355 var seriesObjects = [];
54356 var grouped = false;
54357 var colorHelper = new visuals.ColorHelper(colors, visuals.columnChartProps.dataPoint.fill, defaultColor);
54358 var legendTitle = undefined;
54359 if (this.dataView && this.dataView.values) {
54360 var allValues = this.dataView.values;
54361 var valueGroups = allValues.grouped();
54362 var hasDynamicSeries = !!(allValues && allValues.source);
54363 var formatStringProp = visuals.columnChartProps.general.formatString;
54364 for (var valueGroupsIndex = 0, valueGroupsLen = valueGroups.length; valueGroupsIndex < valueGroupsLen; valueGroupsIndex++) {
54365 var valueGroup = valueGroups[valueGroupsIndex], valueGroupObjects = valueGroup.objects, values = valueGroup.values;
54366 for (var valueIndex = 0, valuesLen = values.length; valueIndex < valuesLen; valueIndex++) {
54367 var series = values[valueIndex];
54368 var source = series.source;
54369 // Gradient measures do not create series.
54370 if (DataRoleHelper.hasRole(source, 'Gradient') && !DataRoleHelper.hasRole(source, 'Y'))
54371 continue;
54372 seriesSources.push(source);
54373 seriesObjects.push(series.objects);
54374 var selectionId = series.identity ?
54375 visuals.SelectionId.createWithIdAndMeasure(series.identity, source.queryName) :
54376 visuals.SelectionId.createWithMeasure(this.getMeasureNameByIndex(valueIndex));
54377 var label = visuals.converterHelper.getFormattedLegendLabel(source, allValues, formatStringProp);
54378 var color = hasDynamicSeries
54379 ? colorHelper.getColorForSeriesValue(valueGroupObjects, allValues.identityFields, source.groupName)
54380 : colorHelper.getColorForMeasure(source.objects, source.queryName);
54381 legend.push({
54382 icon: visuals.LegendIcon.Box,
54383 color: color,
54384 label: label,
54385 identity: selectionId,
54386 selected: false,
54387 });
54388 if (series.identity && source.groupName !== undefined) {
54389 grouped = true;
54390 }
54391 }
54392 }
54393 var dvValues = this.dataView.values;
54394 legendTitle = dvValues && dvValues.source ? dvValues.source.displayName : "";
54395 }
54396 var legendData = {
54397 title: legendTitle,
54398 dataPoints: legend,
54399 grouped: grouped,
54400 labelColor: defaultLegendLabelColor,
54401 };
54402 return {
54403 legend: legendData,
54404 seriesSources: seriesSources,
54405 seriesObjects: seriesObjects,
54406 };
54407 };
54408 ColumnChartConverterHelper.prototype.getValueBySeriesAndCategory = function (series, category) {
54409 if (this.reader.hasDynamicSeries()) {
54410 // Combo chart dynamic series is broken when line and column have the same measure, so for now,
54411 // work around this by using the grouped directly instead of relying on the reader and roles
54412 var grouped = this.dataView.values.grouped();
54413 return grouped[series].values[0].values[category];
54414 }
54415 return this.reader.getValue('Y', category, series);
54416 };
54417 ColumnChartConverterHelper.prototype.getMeasureNameByIndex = function (index) {
54418 return this.dataView.values[index].source.queryName;
54419 };
54420 ColumnChartConverterHelper.prototype.hasHighlightValues = function (series) {
54421 var column = this.dataView && this.dataView.values ? this.dataView.values[series] : undefined;
54422 return column && !!column.highlights;
54423 };
54424 ColumnChartConverterHelper.prototype.getHighlightBySeriesAndCategory = function (series, category) {
54425 return this.dataView.values[series].highlights[category];
54426 };
54427 return ColumnChartConverterHelper;
54428 }());
54429 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
54430})(powerbi || (powerbi = {}));
54431/*
54432 * Power BI Visualizations
54433 *
54434 * Copyright (c) Microsoft Corporation
54435 * All rights reserved.
54436 * MIT License
54437 *
54438 * Permission is hereby granted, free of charge, to any person obtaining a copy
54439 * of this software and associated documentation files (the ""Software""), to deal
54440 * in the Software without restriction, including without limitation the rights
54441 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54442 * copies of the Software, and to permit persons to whom the Software is
54443 * furnished to do so, subject to the following conditions:
54444 *
54445 * The above copyright notice and this permission notice shall be included in
54446 * all copies or substantial portions of the Software.
54447 *
54448 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54449 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
54450 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54451 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54452 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54453 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54454 * THE SOFTWARE.
54455 */
54456var powerbi;
54457(function (powerbi) {
54458 var visuals;
54459 (function (visuals) {
54460 var PixelConverter = jsCommon.PixelConverter;
54461 var ClusteredColumnChartStrategy = (function () {
54462 function ClusteredColumnChartStrategy() {
54463 }
54464 ClusteredColumnChartStrategy.prototype.setupVisualProps = function (columnChartProps) {
54465 this.graphicsContext = columnChartProps;
54466 this.margin = columnChartProps.margin;
54467 this.width = this.graphicsContext.width;
54468 this.height = this.graphicsContext.height;
54469 this.categoryLayout = columnChartProps.layout;
54470 this.animator = columnChartProps.animator;
54471 this.interactivityService = columnChartProps.interactivityService;
54472 this.viewportHeight = columnChartProps.viewportHeight;
54473 this.viewportWidth = columnChartProps.viewportWidth;
54474 this.isComboChart = columnChartProps.isComboChart;
54475 };
54476 ClusteredColumnChartStrategy.prototype.setData = function (data) {
54477 this.data = data;
54478 };
54479 ClusteredColumnChartStrategy.prototype.setXScale = function (is100Pct, forcedTickCount, forcedXDomain, axisScaleType, axisDisplayUnits, axisPrecision, ensureXDomain) {
54480 var width = this.width;
54481 var forcedXMin, forcedXMax;
54482 if (forcedXDomain && forcedXDomain.length === 2) {
54483 forcedXMin = forcedXDomain[0];
54484 forcedXMax = forcedXDomain[1];
54485 }
54486 var props = this.xProps = visuals.ColumnUtil.getCategoryAxis(this.data, width, this.categoryLayout, false, forcedXMin, forcedXMax, axisScaleType, axisDisplayUnits, axisPrecision, ensureXDomain);
54487 // create clustered offset scale
54488 var seriesLength = this.data.series.length;
54489 var columnWidth = (this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio)) / seriesLength;
54490 this.seriesOffsetScale = d3.scale.ordinal()
54491 .domain(this.data.series.map(function (s) { return s.index; }))
54492 .rangeBands([0, seriesLength * columnWidth]);
54493 return props;
54494 };
54495 ClusteredColumnChartStrategy.prototype.setYScale = function (is100Pct, forcedTickCount, forcedYDomain, axisScaleType, axisDisplayUnits, axisPrecision, ensureYDomain) {
54496 debug.assert(!is100Pct, 'Cannot have 100% clustered chart.');
54497 var height = this.viewportHeight;
54498 var valueDomain = visuals.AxisHelper.createValueDomain(this.data.series, true) || visuals.emptyDomain;
54499 var combinedDomain = visuals.AxisHelper.combineDomain(forcedYDomain, valueDomain, ensureYDomain);
54500 var shouldClamp = visuals.AxisHelper.scaleShouldClamp(combinedDomain, valueDomain);
54501 this.yProps = visuals.AxisHelper.createAxis({
54502 pixelSpan: height,
54503 dataDomain: combinedDomain,
54504 metaDataColumn: this.data.valuesMetadata[0],
54505 formatString: visuals.valueFormatter.getFormatString(this.data.valuesMetadata[0], visuals.columnChartProps.general.formatString),
54506 outerPadding: 0,
54507 isScalar: true,
54508 isVertical: true,
54509 forcedTickCount: forcedTickCount,
54510 useTickIntervalForDisplayUnits: true,
54511 isCategoryAxis: false,
54512 scaleType: axisScaleType,
54513 axisDisplayUnits: axisDisplayUnits,
54514 axisPrecision: axisPrecision,
54515 shouldClamp: shouldClamp,
54516 });
54517 return this.yProps;
54518 };
54519 ClusteredColumnChartStrategy.prototype.drawColumns = function (useAnimation) {
54520 var data = this.data;
54521 debug.assertValue(data, 'data could not be null or undefined');
54522 this.columnsCenters = null; // invalidate the columnsCenters so that will be calculated again
54523 var categoryWidth = (this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio));
54524 var columnWidth = categoryWidth / data.series.length;
54525 var axisOptions = {
54526 columnWidth: columnWidth,
54527 categoryWidth: categoryWidth,
54528 xScale: this.xProps.scale,
54529 yScale: this.yProps.scale,
54530 seriesOffsetScale: this.seriesOffsetScale,
54531 isScalar: this.categoryLayout.isScalar,
54532 margin: this.margin,
54533 };
54534 var clusteredColumnLayout = this.layout = ClusteredColumnChartStrategy.getLayout(data, axisOptions);
54535 var dataLabelSettings = data.labelSettings;
54536 var labelDataPoints = [];
54537 if (dataLabelSettings && dataLabelSettings.show) {
54538 labelDataPoints = this.createLabelDataPoints();
54539 }
54540 var result;
54541 var shapes;
54542 var series = visuals.ColumnUtil.drawSeries(data, this.graphicsContext.mainGraphicsContext, axisOptions);
54543 if (this.animator && useAnimation) {
54544 result = this.animator.animate({
54545 viewModel: data,
54546 series: series,
54547 layout: clusteredColumnLayout,
54548 itemCS: ClusteredColumnChartStrategy.classes.item,
54549 interactivityService: this.interactivityService,
54550 mainGraphicsContext: this.graphicsContext.mainGraphicsContext,
54551 viewPort: { height: this.height, width: this.width }
54552 });
54553 shapes = result.shapes;
54554 }
54555 if (!this.animator || !useAnimation || result.failed) {
54556 shapes = visuals.ColumnUtil.drawDefaultShapes(data, series, clusteredColumnLayout, ClusteredColumnChartStrategy.classes.item, !this.animator, this.interactivityService && this.interactivityService.hasSelection());
54557 }
54558 visuals.ColumnUtil.applyInteractivity(shapes, this.graphicsContext.onDragStart);
54559 return {
54560 eventGroup: this.graphicsContext.mainGraphicsContext,
54561 shapesSelection: shapes,
54562 viewport: { height: this.height, width: this.width },
54563 axisOptions: axisOptions,
54564 labelDataPoints: labelDataPoints,
54565 };
54566 };
54567 ClusteredColumnChartStrategy.prototype.selectColumn = function (selectedColumnIndex, lastSelectedColumnIndex) {
54568 visuals.ColumnUtil.setChosenColumnOpacity(this.graphicsContext.mainGraphicsContext, ClusteredColumnChartStrategy.classes.item.selector, selectedColumnIndex, lastSelectedColumnIndex);
54569 this.moveHandle(selectedColumnIndex);
54570 };
54571 ClusteredColumnChartStrategy.prototype.getClosestColumnIndex = function (x, y) {
54572 return visuals.ColumnUtil.getClosestColumnIndex(x, this.getColumnsCenters());
54573 };
54574 /**
54575 * Get the chart's columns centers (x value).
54576 */
54577 ClusteredColumnChartStrategy.prototype.getColumnsCenters = function () {
54578 var _this = this;
54579 if (!this.columnsCenters) {
54580 var categoryWidth = this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio);
54581 // use the axis scale and first series data to get category centers
54582 if (this.data.series.length > 0) {
54583 var xScaleOffset_1 = 0;
54584 if (!this.categoryLayout.isScalar)
54585 xScaleOffset_1 = categoryWidth / 2;
54586 var firstSeries = this.data.series[0];
54587 this.columnsCenters = firstSeries.data.map(function (d) { return _this.xProps.scale(_this.categoryLayout.isScalar ? d.categoryValue : d.categoryIndex) + xScaleOffset_1; });
54588 }
54589 }
54590 return this.columnsCenters;
54591 };
54592 ClusteredColumnChartStrategy.prototype.moveHandle = function (selectedColumnIndex) {
54593 var columnCenters = this.getColumnsCenters();
54594 var x = columnCenters[selectedColumnIndex];
54595 var hoverLine = d3.select('.interactive-hover-line');
54596 if (!hoverLine.empty() && !this.columnSelectionLineHandle) {
54597 this.columnSelectionLineHandle = d3.select(hoverLine.node().parentNode);
54598 }
54599 if (!this.columnSelectionLineHandle) {
54600 var handle = this.columnSelectionLineHandle = this.graphicsContext.unclippedGraphicsContext.append('g');
54601 handle.append('line')
54602 .classed('interactive-hover-line', true)
54603 .attr({
54604 x1: x,
54605 x2: x,
54606 y1: 0,
54607 y2: this.height,
54608 });
54609 handle.append('circle')
54610 .attr({
54611 cx: x,
54612 cy: this.height,
54613 r: '6px',
54614 })
54615 .classed('drag-handle', true);
54616 }
54617 else {
54618 var handle = this.columnSelectionLineHandle;
54619 handle.select('line').attr({ x1: x, x2: x });
54620 handle.select('circle').attr({ cx: x });
54621 }
54622 };
54623 ClusteredColumnChartStrategy.getLayout = function (data, axisOptions) {
54624 var columnWidth = axisOptions.columnWidth;
54625 var halfColumnWidth = 0.5 * columnWidth;
54626 var quarterColumnWidth = halfColumnWidth / 2;
54627 var isScalar = axisOptions.isScalar;
54628 var xScale = axisOptions.xScale;
54629 var yScale = axisOptions.yScale;
54630 var seriesOffsetScale = axisOptions.seriesOffsetScale;
54631 var scaledY0 = yScale(0);
54632 var xScaleOffset = 0;
54633 if (isScalar)
54634 xScaleOffset = axisOptions.categoryWidth / 2;
54635 return {
54636 shapeLayout: {
54637 width: function (d) { return d.drawThinner ? halfColumnWidth : columnWidth; },
54638 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex) + seriesOffsetScale(d.seriesIndex) - xScaleOffset + (d.drawThinner ? quarterColumnWidth : 0); },
54639 y: function (d) { return scaledY0 + visuals.AxisHelper.diffScaled(yScale, Math.max(0, d.value), 0); },
54640 height: function (d) { return Math.abs(visuals.AxisHelper.diffScaled(yScale, 0, d.value)); },
54641 },
54642 shapeLayoutWithoutHighlights: {
54643 width: function (d) { return columnWidth; },
54644 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex) + seriesOffsetScale(d.seriesIndex) - xScaleOffset; },
54645 y: function (d) { return scaledY0 + visuals.AxisHelper.diffScaled(yScale, Math.max(0, d.originalValue), 0); },
54646 height: function (d) { return Math.abs(visuals.AxisHelper.diffScaled(yScale, 0, d.originalValue)); },
54647 },
54648 zeroShapeLayout: {
54649 width: function (d) { return d.drawThinner ? halfColumnWidth : columnWidth; },
54650 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex) + seriesOffsetScale(d.seriesIndex) - xScaleOffset + (d.drawThinner ? quarterColumnWidth : 0); },
54651 y: function (d) { return scaledY0; },
54652 height: function (d) { return 0; },
54653 },
54654 };
54655 };
54656 ClusteredColumnChartStrategy.prototype.createLabelDataPoints = function () {
54657 var labelDataPoints = [];
54658 var data = this.data;
54659 var series = data.series;
54660 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
54661 var shapeLayout = this.layout.shapeLayout;
54662 for (var _i = 0, series_2 = series; _i < series_2.length; _i++) {
54663 var currentSeries = series_2[_i];
54664 var labelSettings = currentSeries.labelSettings ? currentSeries.labelSettings : data.labelSettings;
54665 if (!labelSettings.show)
54666 continue;
54667 var axisFormatter = visuals.NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter(this.yProps.formatter, labelSettings);
54668 for (var _a = 0, _b = currentSeries.data; _a < _b.length; _a++) {
54669 var dataPoint = _b[_a];
54670 if ((data.hasHighlights && !dataPoint.highlight) || dataPoint.value == null) {
54671 continue;
54672 }
54673 // Calculate parent rectangle
54674 var parentRect = {
54675 left: shapeLayout.x(dataPoint),
54676 top: shapeLayout.y(dataPoint),
54677 width: shapeLayout.width(dataPoint),
54678 height: shapeLayout.height(dataPoint),
54679 };
54680 // Calculate label text
54681 var formatString = dataPoint.labelFormatString;
54682 var formatter = formattersCache.getOrCreate(formatString, labelSettings, axisFormatter);
54683 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(dataPoint.value));
54684 // Calculate text size
54685 var properties = {
54686 text: text,
54687 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
54688 fontSize: PixelConverter.fromPoint(labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt),
54689 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
54690 };
54691 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
54692 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
54693 labelDataPoints.push({
54694 isPreferred: true,
54695 text: text,
54696 textSize: {
54697 width: textWidth,
54698 height: textHeight,
54699 },
54700 outsideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, false, this.isComboChart),
54701 insideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, true, this.isComboChart),
54702 parentType: 1 /* Rectangle */,
54703 parentShape: {
54704 rect: parentRect,
54705 orientation: dataPoint.value >= 0 ? 1 /* VerticalBottomBased */ : 2 /* VerticalTopBased */,
54706 validPositions: visuals.ColumnChart.clusteredValidLabelPositions,
54707 },
54708 identity: dataPoint.identity,
54709 fontSize: labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt,
54710 });
54711 }
54712 }
54713 return labelDataPoints;
54714 };
54715 ClusteredColumnChartStrategy.classes = {
54716 item: {
54717 class: 'column',
54718 selector: '.column',
54719 },
54720 };
54721 return ClusteredColumnChartStrategy;
54722 }());
54723 visuals.ClusteredColumnChartStrategy = ClusteredColumnChartStrategy;
54724 var ClusteredBarChartStrategy = (function () {
54725 function ClusteredBarChartStrategy() {
54726 }
54727 ClusteredBarChartStrategy.prototype.setupVisualProps = function (barChartProps) {
54728 this.graphicsContext = barChartProps;
54729 this.margin = barChartProps.margin;
54730 this.width = this.graphicsContext.width;
54731 this.height = this.graphicsContext.height;
54732 this.categoryLayout = barChartProps.layout;
54733 this.animator = barChartProps.animator;
54734 this.interactivityService = barChartProps.interactivityService;
54735 this.viewportHeight = barChartProps.viewportHeight;
54736 this.viewportWidth = barChartProps.viewportWidth;
54737 this.isComboChart = barChartProps.isComboChart;
54738 };
54739 ClusteredBarChartStrategy.prototype.setData = function (data) {
54740 this.data = data;
54741 };
54742 ClusteredBarChartStrategy.prototype.setYScale = function (is100Pct, forcedTickCount, forcedYDomain, axisScaleType, axisDisplayUnits, axisPrecision, ensureYDomain) {
54743 var height = this.height;
54744 var forcedYMin, forcedYMax;
54745 if (forcedYDomain && forcedYDomain.length === 2) {
54746 forcedYMin = forcedYDomain[0];
54747 forcedYMax = forcedYDomain[1];
54748 }
54749 var props = this.yProps = visuals.ColumnUtil.getCategoryAxis(this.data, height, this.categoryLayout, true, forcedYMin, forcedYMax, axisScaleType, axisDisplayUnits, axisPrecision, ensureYDomain);
54750 // create clustered offset scale
54751 var seriesLength = this.data.series.length;
54752 var columnWidth = (this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio)) / seriesLength;
54753 this.seriesOffsetScale = d3.scale.ordinal()
54754 .domain(this.data.series.map(function (s) { return s.index; }))
54755 .rangeBands([0, seriesLength * columnWidth]);
54756 return props;
54757 };
54758 ClusteredBarChartStrategy.prototype.setXScale = function (is100Pct, forcedTickCount, forcedXDomain, axisScaleType, axisDisplayUnits, axisPrecision, ensureXDomain) {
54759 debug.assert(!is100Pct, 'Cannot have 100% clustered chart.');
54760 debug.assert(forcedTickCount === undefined, 'Cannot have clustered bar chart as combo chart.');
54761 var width = this.width;
54762 var valueDomain = visuals.AxisHelper.createValueDomain(this.data.series, true) || visuals.emptyDomain;
54763 var combinedDomain = visuals.AxisHelper.combineDomain(forcedXDomain, valueDomain, ensureXDomain);
54764 var shouldClamp = visuals.AxisHelper.scaleShouldClamp(combinedDomain, valueDomain);
54765 this.xProps = visuals.AxisHelper.createAxis({
54766 pixelSpan: width,
54767 dataDomain: combinedDomain,
54768 metaDataColumn: this.data.valuesMetadata[0],
54769 formatString: visuals.valueFormatter.getFormatString(this.data.valuesMetadata[0], visuals.columnChartProps.general.formatString),
54770 outerPadding: 0,
54771 isScalar: true,
54772 isVertical: false,
54773 forcedTickCount: forcedTickCount,
54774 useTickIntervalForDisplayUnits: true,
54775 isCategoryAxis: false,
54776 scaleType: axisScaleType,
54777 axisDisplayUnits: axisDisplayUnits,
54778 axisPrecision: axisPrecision,
54779 shouldClamp: shouldClamp,
54780 });
54781 this.xProps.axis.tickSize(-this.viewportHeight, 0);
54782 return this.xProps;
54783 };
54784 ClusteredBarChartStrategy.prototype.drawColumns = function (useAnimation) {
54785 var data = this.data;
54786 debug.assertValue(data, 'data could not be null or undefined');
54787 this.barsCenters = null; // invalidate the columnsCenters so that will be calculated again
54788 var categoryWidth = (this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio));
54789 var columnWidth = categoryWidth / data.series.length;
54790 var axisOptions = {
54791 columnWidth: columnWidth,
54792 categoryWidth: categoryWidth,
54793 xScale: this.xProps.scale,
54794 yScale: this.yProps.scale,
54795 seriesOffsetScale: this.seriesOffsetScale,
54796 isScalar: this.categoryLayout.isScalar,
54797 margin: this.margin,
54798 };
54799 var clusteredBarLayout = this.layout = ClusteredBarChartStrategy.getLayout(data, axisOptions);
54800 var dataLabelSettings = data.labelSettings;
54801 var labelDataPoints = [];
54802 if (dataLabelSettings && dataLabelSettings.show) {
54803 labelDataPoints = this.createLabelDataPoints();
54804 }
54805 var result;
54806 var shapes;
54807 var series = visuals.ColumnUtil.drawSeries(data, this.graphicsContext.mainGraphicsContext, axisOptions);
54808 if (this.animator && useAnimation) {
54809 result = this.animator.animate({
54810 viewModel: data,
54811 series: series,
54812 layout: clusteredBarLayout,
54813 itemCS: ClusteredBarChartStrategy.classes.item,
54814 interactivityService: this.interactivityService,
54815 mainGraphicsContext: this.graphicsContext.mainGraphicsContext,
54816 viewPort: { height: this.height, width: this.width }
54817 });
54818 shapes = result.shapes;
54819 }
54820 if (!this.animator || !useAnimation || result.failed) {
54821 shapes = visuals.ColumnUtil.drawDefaultShapes(data, series, clusteredBarLayout, ClusteredBarChartStrategy.classes.item, !this.animator, this.interactivityService && this.interactivityService.hasSelection());
54822 }
54823 visuals.ColumnUtil.applyInteractivity(shapes, this.graphicsContext.onDragStart);
54824 return {
54825 eventGroup: this.graphicsContext.mainGraphicsContext,
54826 shapesSelection: shapes,
54827 viewport: { height: this.height, width: this.width },
54828 axisOptions: axisOptions,
54829 labelDataPoints: labelDataPoints,
54830 };
54831 };
54832 ClusteredBarChartStrategy.prototype.selectColumn = function (selectedColumnIndex, lastSelectedColumnIndex) {
54833 visuals.ColumnUtil.setChosenColumnOpacity(this.graphicsContext.mainGraphicsContext, ClusteredBarChartStrategy.classes.item.selector, selectedColumnIndex, lastSelectedColumnIndex);
54834 this.moveHandle(selectedColumnIndex);
54835 };
54836 ClusteredBarChartStrategy.prototype.getClosestColumnIndex = function (x, y) {
54837 return visuals.ColumnUtil.getClosestColumnIndex(y, this.getBarsCenters());
54838 };
54839 /**
54840 * Get the chart's columns centers (y value).
54841 */
54842 ClusteredBarChartStrategy.prototype.getBarsCenters = function () {
54843 var _this = this;
54844 if (!this.barsCenters) {
54845 var barWidth = this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio);
54846 // use the axis scale and first series data to get category centers
54847 if (this.data.series.length > 0) {
54848 var yScaleOffset_1 = 0;
54849 if (!this.categoryLayout.isScalar)
54850 yScaleOffset_1 = barWidth / 2;
54851 var firstSeries = this.data.series[0];
54852 this.barsCenters = firstSeries.data.map(function (d) { return _this.yProps.scale(_this.categoryLayout.isScalar ? d.categoryValue : d.categoryIndex) + yScaleOffset_1; });
54853 }
54854 }
54855 return this.barsCenters;
54856 };
54857 ClusteredBarChartStrategy.prototype.moveHandle = function (selectedColumnIndex) {
54858 var barCenters = this.getBarsCenters();
54859 var y = barCenters[selectedColumnIndex];
54860 var hoverLine = d3.select('.interactive-hover-line');
54861 if (!hoverLine.empty() && !this.columnSelectionLineHandle) {
54862 this.columnSelectionLineHandle = d3.select(hoverLine.node().parentNode);
54863 }
54864 if (!this.columnSelectionLineHandle) {
54865 var handle = this.columnSelectionLineHandle = this.graphicsContext.unclippedGraphicsContext.append('g');
54866 handle.append('line')
54867 .classed('interactive-hover-line', true)
54868 .attr({
54869 x1: 0,
54870 x2: this.width,
54871 y1: y,
54872 y2: y,
54873 });
54874 handle.append('circle')
54875 .attr({
54876 cx: 0,
54877 cy: y,
54878 r: '6px',
54879 })
54880 .classed('drag-handle', true);
54881 }
54882 else {
54883 var handle = this.columnSelectionLineHandle;
54884 handle.select('line').attr({ y1: y, y2: y });
54885 handle.select('circle').attr({ cy: y });
54886 }
54887 };
54888 ClusteredBarChartStrategy.getLayout = function (data, axisOptions) {
54889 var columnWidth = axisOptions.columnWidth;
54890 var halfColumnWidth = 0.5 * columnWidth;
54891 var quarterColumnWidth = halfColumnWidth / 2;
54892 var isScalar = axisOptions.isScalar;
54893 var xScale = axisOptions.xScale;
54894 var yScale = axisOptions.yScale;
54895 var seriesOffsetScale = axisOptions.seriesOffsetScale;
54896 var scaledX0 = xScale(0);
54897 var yScaleOffset = 0;
54898 if (isScalar)
54899 yScaleOffset = axisOptions.categoryWidth / 2;
54900 return {
54901 shapeLayout: {
54902 width: function (d) { return Math.abs(visuals.AxisHelper.diffScaled(xScale, 0, d.value)); },
54903 x: function (d) { return scaledX0 + visuals.AxisHelper.diffScaled(xScale, Math.min(0, d.value), 0); },
54904 y: function (d) { return yScale(isScalar ? d.categoryValue : d.categoryIndex) + seriesOffsetScale(d.seriesIndex) - yScaleOffset + (d.drawThinner ? quarterColumnWidth : 0); },
54905 height: function (d) { return d.drawThinner ? halfColumnWidth : columnWidth; },
54906 },
54907 shapeLayoutWithoutHighlights: {
54908 width: function (d) { return Math.abs(visuals.AxisHelper.diffScaled(xScale, 0, d.originalValue)); },
54909 x: function (d) { return scaledX0 + visuals.AxisHelper.diffScaled(xScale, Math.min(0, d.originalValue), 0); },
54910 y: function (d) { return yScale(isScalar ? d.categoryValue : d.categoryIndex) + seriesOffsetScale(d.seriesIndex) - yScaleOffset; },
54911 height: function (d) { return columnWidth; },
54912 },
54913 zeroShapeLayout: {
54914 width: function (d) { return 0; },
54915 x: function (d) { return scaledX0 + visuals.AxisHelper.diffScaled(xScale, Math.min(0, d.value), 0); },
54916 y: function (d) { return yScale(isScalar ? d.categoryValue : d.categoryIndex) + seriesOffsetScale(d.seriesIndex) - yScaleOffset + (d.drawThinner ? quarterColumnWidth : 0); },
54917 height: function (d) { return d.drawThinner ? halfColumnWidth : columnWidth; },
54918 },
54919 };
54920 };
54921 ClusteredBarChartStrategy.prototype.createLabelDataPoints = function () {
54922 var labelDataPoints = [];
54923 var data = this.data;
54924 var series = data.series;
54925 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
54926 var shapeLayout = this.layout.shapeLayout;
54927 for (var _i = 0, series_3 = series; _i < series_3.length; _i++) {
54928 var currentSeries = series_3[_i];
54929 var labelSettings = currentSeries.labelSettings ? currentSeries.labelSettings : data.labelSettings;
54930 if (!labelSettings.show)
54931 continue;
54932 var axisFormatter = visuals.NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter(this.yProps.formatter, labelSettings);
54933 for (var _a = 0, _b = currentSeries.data; _a < _b.length; _a++) {
54934 var dataPoint = _b[_a];
54935 if ((this.interactivityService && this.interactivityService.hasSelection() && !dataPoint.selected) || (data.hasHighlights && !dataPoint.highlight) || dataPoint.value == null) {
54936 continue;
54937 }
54938 // Calculate label text
54939 var formatString = dataPoint.labelFormatString;
54940 var formatter = formattersCache.getOrCreate(formatString, labelSettings, axisFormatter);
54941 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(dataPoint.value));
54942 // Calculate text size
54943 var properties = {
54944 text: text,
54945 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
54946 fontSize: PixelConverter.fromPoint(labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt),
54947 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
54948 };
54949 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
54950 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
54951 // Calculate parent rectangle
54952 var parentRect = {
54953 left: shapeLayout.x(dataPoint),
54954 top: shapeLayout.y(dataPoint),
54955 width: shapeLayout.width(dataPoint),
54956 height: shapeLayout.height(dataPoint),
54957 };
54958 labelDataPoints.push({
54959 isPreferred: true,
54960 text: text,
54961 textSize: {
54962 width: textWidth,
54963 height: textHeight,
54964 },
54965 outsideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, false, this.isComboChart),
54966 insideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, true, this.isComboChart),
54967 parentType: 1 /* Rectangle */,
54968 parentShape: {
54969 rect: parentRect,
54970 orientation: dataPoint.value >= 0 ? 3 /* HorizontalLeftBased */ : 4 /* HorizontalRightBased */,
54971 validPositions: visuals.ColumnChart.clusteredValidLabelPositions,
54972 },
54973 identity: dataPoint.identity,
54974 fontSize: labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt,
54975 });
54976 }
54977 }
54978 return labelDataPoints;
54979 };
54980 ClusteredBarChartStrategy.classes = {
54981 item: {
54982 class: 'bar',
54983 selector: '.bar'
54984 },
54985 };
54986 return ClusteredBarChartStrategy;
54987 }());
54988 visuals.ClusteredBarChartStrategy = ClusteredBarChartStrategy;
54989 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
54990})(powerbi || (powerbi = {}));
54991/*
54992 * Power BI Visualizations
54993 *
54994 * Copyright (c) Microsoft Corporation
54995 * All rights reserved.
54996 * MIT License
54997 *
54998 * Permission is hereby granted, free of charge, to any person obtaining a copy
54999 * of this software and associated documentation files (the ""Software""), to deal
55000 * in the Software without restriction, including without limitation the rights
55001 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55002 * copies of the Software, and to permit persons to whom the Software is
55003 * furnished to do so, subject to the following conditions:
55004 *
55005 * The above copyright notice and this permission notice shall be included in
55006 * all copies or substantial portions of the Software.
55007 *
55008 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55009 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55010 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55011 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55012 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55013 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55014 * THE SOFTWARE.
55015 */
55016var powerbi;
55017(function (powerbi) {
55018 var visuals;
55019 (function (visuals) {
55020 var PixelConverter = jsCommon.PixelConverter;
55021 var StackedColumnChartStrategy = (function () {
55022 function StackedColumnChartStrategy() {
55023 }
55024 StackedColumnChartStrategy.prototype.setupVisualProps = function (columnChartProps) {
55025 this.graphicsContext = columnChartProps;
55026 this.margin = columnChartProps.margin;
55027 this.width = this.graphicsContext.width;
55028 this.height = this.graphicsContext.height;
55029 this.categoryLayout = columnChartProps.layout;
55030 this.animator = columnChartProps.animator;
55031 this.interactivityService = columnChartProps.interactivityService;
55032 this.viewportHeight = columnChartProps.viewportHeight;
55033 this.viewportWidth = columnChartProps.viewportWidth;
55034 this.isComboChart = columnChartProps.isComboChart;
55035 };
55036 StackedColumnChartStrategy.prototype.setData = function (data) {
55037 this.data = data;
55038 };
55039 StackedColumnChartStrategy.prototype.setXScale = function (is100Pct, forcedTickCount, forcedXDomain, axisScaleType, axisDisplayUnits, axisPrecision, xReferenceLineValue) {
55040 var width = this.width;
55041 var forcedXMin, forcedXMax;
55042 if (forcedXDomain && forcedXDomain.length === 2) {
55043 forcedXMin = forcedXDomain[0];
55044 forcedXMax = forcedXDomain[1];
55045 }
55046 var props = this.xProps = visuals.ColumnUtil.getCategoryAxis(this.data, width, this.categoryLayout, false, forcedXMin, forcedXMax, axisScaleType, axisDisplayUnits, axisPrecision, xReferenceLineValue);
55047 return props;
55048 };
55049 StackedColumnChartStrategy.prototype.setYScale = function (is100Pct, forcedTickCount, forcedYDomain, axisScaleType, axisDisplayUnits, axisPrecision, y1ReferenceLineValue) {
55050 var height = this.viewportHeight;
55051 var valueDomain = visuals.StackedUtil.calcValueDomain(this.data.series, is100Pct);
55052 var valueDomainArr = [valueDomain.min, valueDomain.max];
55053 var combinedDomain = visuals.AxisHelper.combineDomain(forcedYDomain, valueDomainArr, y1ReferenceLineValue);
55054 var shouldClamp = visuals.AxisHelper.scaleShouldClamp(combinedDomain, valueDomainArr);
55055 var metadataColumn = this.data.valuesMetadata[0];
55056 var formatString = is100Pct ?
55057 this.graphicsContext.hostService.getLocalizedString('Percentage')
55058 : visuals.valueFormatter.getFormatString(metadataColumn, visuals.columnChartProps.general.formatString);
55059 this.yProps = visuals.AxisHelper.createAxis({
55060 pixelSpan: height,
55061 dataDomain: combinedDomain,
55062 metaDataColumn: metadataColumn,
55063 formatString: formatString,
55064 outerPadding: 0,
55065 isScalar: true,
55066 isVertical: true,
55067 forcedTickCount: forcedTickCount,
55068 useTickIntervalForDisplayUnits: true,
55069 isCategoryAxis: false,
55070 scaleType: axisScaleType,
55071 axisDisplayUnits: axisDisplayUnits,
55072 axisPrecision: axisPrecision,
55073 is100Pct: is100Pct,
55074 shouldClamp: shouldClamp,
55075 });
55076 return this.yProps;
55077 };
55078 StackedColumnChartStrategy.prototype.drawColumns = function (useAnimation) {
55079 var data = this.data;
55080 debug.assertValue(data, 'data should not be null or undefined');
55081 this.columnsCenters = null; // invalidate the columnsCenters so that will be calculated again
55082 var axisOptions = {
55083 columnWidth: this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio),
55084 xScale: this.xProps.scale,
55085 yScale: this.yProps.scale,
55086 isScalar: this.categoryLayout.isScalar,
55087 margin: this.margin,
55088 };
55089 var stackedColumnLayout = this.layout = StackedColumnChartStrategy.getLayout(data, axisOptions);
55090 var dataLabelSettings = data.labelSettings;
55091 var labelDataPoints = [];
55092 if (dataLabelSettings && dataLabelSettings.show) {
55093 labelDataPoints = this.createLabelDataPoints();
55094 }
55095 var result;
55096 var shapes;
55097 var series = visuals.ColumnUtil.drawSeries(data, this.graphicsContext.mainGraphicsContext, axisOptions);
55098 if (this.animator && useAnimation) {
55099 result = this.animator.animate({
55100 viewModel: data,
55101 series: series,
55102 layout: stackedColumnLayout,
55103 itemCS: StackedColumnChartStrategy.classes.item,
55104 interactivityService: this.interactivityService,
55105 mainGraphicsContext: this.graphicsContext.mainGraphicsContext,
55106 viewPort: { height: this.height, width: this.width },
55107 });
55108 shapes = result.shapes;
55109 }
55110 if (!this.animator || !useAnimation || result.failed) {
55111 shapes = visuals.ColumnUtil.drawDefaultShapes(data, series, stackedColumnLayout, StackedColumnChartStrategy.classes.item, !this.animator, this.interactivityService && this.interactivityService.hasSelection());
55112 }
55113 visuals.ColumnUtil.applyInteractivity(shapes, this.graphicsContext.onDragStart);
55114 return {
55115 eventGroup: this.graphicsContext.mainGraphicsContext,
55116 shapesSelection: shapes,
55117 viewport: { height: this.height, width: this.width },
55118 axisOptions: axisOptions,
55119 labelDataPoints: labelDataPoints,
55120 };
55121 };
55122 StackedColumnChartStrategy.prototype.selectColumn = function (selectedColumnIndex, lastSelectedColumnIndex) {
55123 visuals.ColumnUtil.setChosenColumnOpacity(this.graphicsContext.mainGraphicsContext, StackedColumnChartStrategy.classes.item.selector, selectedColumnIndex, lastSelectedColumnIndex);
55124 this.moveHandle(selectedColumnIndex);
55125 };
55126 StackedColumnChartStrategy.prototype.getClosestColumnIndex = function (x, y) {
55127 return visuals.ColumnUtil.getClosestColumnIndex(x, this.getColumnsCenters());
55128 };
55129 /**
55130 * Get the chart's columns centers (x value).
55131 */
55132 StackedColumnChartStrategy.prototype.getColumnsCenters = function () {
55133 var _this = this;
55134 if (!this.columnsCenters) {
55135 var categoryWidth = this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio);
55136 // use the axis scale and first series data to get category centers
55137 if (this.data.series.length > 0) {
55138 var xScaleOffset_2 = 0;
55139 if (!this.categoryLayout.isScalar)
55140 xScaleOffset_2 = categoryWidth / 2;
55141 var firstSeries = this.data.series[0];
55142 this.columnsCenters = firstSeries.data.map(function (d) { return _this.xProps.scale(_this.categoryLayout.isScalar ? d.categoryValue : d.categoryIndex) + xScaleOffset_2; });
55143 }
55144 }
55145 return this.columnsCenters;
55146 };
55147 StackedColumnChartStrategy.prototype.moveHandle = function (selectedColumnIndex) {
55148 var columnCenters = this.getColumnsCenters();
55149 var x = columnCenters[selectedColumnIndex];
55150 var hoverLine = d3.select('.interactive-hover-line');
55151 if (!hoverLine.empty() && !this.columnSelectionLineHandle) {
55152 this.columnSelectionLineHandle = d3.select(hoverLine.node().parentNode);
55153 }
55154 if (!this.columnSelectionLineHandle) {
55155 var handle = this.columnSelectionLineHandle = this.graphicsContext.unclippedGraphicsContext.append('g');
55156 handle.append('line')
55157 .classed('interactive-hover-line', true)
55158 .attr({
55159 x1: x,
55160 x2: x,
55161 y1: 0,
55162 y2: this.height,
55163 });
55164 handle.append('circle')
55165 .attr({
55166 cx: x,
55167 cy: this.height,
55168 r: '6px',
55169 })
55170 .classed('drag-handle', true);
55171 }
55172 else {
55173 var handle = this.columnSelectionLineHandle;
55174 handle.select('line').attr({ x1: x, x2: x });
55175 handle.select('circle').attr({ cx: x });
55176 }
55177 };
55178 StackedColumnChartStrategy.getLayout = function (data, axisOptions) {
55179 var columnWidth = axisOptions.columnWidth;
55180 var isScalar = axisOptions.isScalar;
55181 var xScale = axisOptions.xScale;
55182 var yScale = axisOptions.yScale;
55183 var xScaleOffset = 0;
55184 if (isScalar)
55185 xScaleOffset = columnWidth / 2;
55186 // d.position is the top left corner (for drawing) - set in columnChart.converter
55187 // for positive values, this is the previous stack position + the new value,
55188 // for negative values it is just the previous stack position
55189 return {
55190 shapeLayout: {
55191 width: function (d) { return columnWidth; },
55192 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex) - xScaleOffset; },
55193 y: function (d) { return yScale(d.position); },
55194 height: function (d) { return yScale(d.position - d.valueAbsolute) - yScale(d.position); },
55195 },
55196 shapeLayoutWithoutHighlights: {
55197 width: function (d) { return columnWidth; },
55198 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex) - xScaleOffset; },
55199 y: function (d) { return yScale(d.originalPosition); },
55200 height: function (d) { return yScale(d.originalPosition - d.originalValueAbsolute) - yScale(d.originalPosition); },
55201 },
55202 zeroShapeLayout: {
55203 width: function (d) { return columnWidth; },
55204 x: function (d) { return xScale(isScalar ? d.categoryValue : d.categoryIndex) - xScaleOffset; },
55205 y: function (d) { return d.value >= 0 ? yScale(d.position - d.valueAbsolute) : yScale(d.position); },
55206 height: function (d) { return 0; }
55207 },
55208 };
55209 };
55210 StackedColumnChartStrategy.prototype.createLabelDataPoints = function () {
55211 var labelDataPoints = [];
55212 var data = this.data;
55213 var series = data.series;
55214 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
55215 var shapeLayout = this.layout.shapeLayout;
55216 for (var _i = 0, series_4 = series; _i < series_4.length; _i++) {
55217 var currentSeries = series_4[_i];
55218 var labelSettings = currentSeries.labelSettings ? currentSeries.labelSettings : data.labelSettings;
55219 if (!labelSettings.show)
55220 continue;
55221 var axisFormatter = visuals.NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter(this.yProps.formatter, labelSettings);
55222 for (var _a = 0, _b = currentSeries.data; _a < _b.length; _a++) {
55223 var dataPoint = _b[_a];
55224 if ((data.hasHighlights && !dataPoint.highlight) || dataPoint.value == null) {
55225 continue;
55226 }
55227 // Calculate parent rectangle
55228 var parentRect = {
55229 left: shapeLayout.x(dataPoint),
55230 top: shapeLayout.y(dataPoint),
55231 width: shapeLayout.width(dataPoint),
55232 height: shapeLayout.height(dataPoint),
55233 };
55234 // Calculate label text
55235 var formatString = "";
55236 if (this.graphicsContext.is100Pct) {
55237 formatString = visuals.NewDataLabelUtils.hundredPercentFormat;
55238 }
55239 else {
55240 formatString = dataPoint.labelFormatString;
55241 }
55242 var formatter = formattersCache.getOrCreate(formatString, labelSettings, axisFormatter);
55243 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(dataPoint.value));
55244 // Calculate text size
55245 var properties = {
55246 text: text,
55247 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
55248 fontSize: PixelConverter.fromPoint(labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt),
55249 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
55250 };
55251 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
55252 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
55253 labelDataPoints.push({
55254 isPreferred: true,
55255 text: text,
55256 textSize: {
55257 width: textWidth,
55258 height: textHeight,
55259 },
55260 outsideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, false, this.isComboChart),
55261 insideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, true, this.isComboChart),
55262 parentType: 1 /* Rectangle */,
55263 parentShape: {
55264 rect: parentRect,
55265 orientation: dataPoint.value >= 0 ? 1 /* VerticalBottomBased */ : 2 /* VerticalTopBased */,
55266 validPositions: visuals.ColumnChart.stackedValidLabelPositions,
55267 },
55268 identity: dataPoint.identity,
55269 fontSize: labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt,
55270 });
55271 }
55272 }
55273 return labelDataPoints;
55274 };
55275 StackedColumnChartStrategy.classes = {
55276 item: {
55277 class: 'column',
55278 selector: '.column'
55279 },
55280 highlightItem: {
55281 class: 'highlightColumn',
55282 selector: '.highlightColumn'
55283 },
55284 };
55285 return StackedColumnChartStrategy;
55286 }());
55287 visuals.StackedColumnChartStrategy = StackedColumnChartStrategy;
55288 var StackedBarChartStrategy = (function () {
55289 function StackedBarChartStrategy() {
55290 }
55291 StackedBarChartStrategy.prototype.setupVisualProps = function (barChartProps) {
55292 this.graphicsContext = barChartProps;
55293 this.margin = barChartProps.margin;
55294 this.width = this.graphicsContext.width;
55295 this.height = this.graphicsContext.height;
55296 this.categoryLayout = barChartProps.layout;
55297 this.animator = barChartProps.animator;
55298 this.interactivityService = barChartProps.interactivityService;
55299 this.viewportHeight = barChartProps.viewportHeight;
55300 this.viewportWidth = barChartProps.viewportWidth;
55301 this.isComboChart = barChartProps.isComboChart;
55302 };
55303 StackedBarChartStrategy.prototype.setData = function (data) {
55304 this.data = data;
55305 };
55306 StackedBarChartStrategy.prototype.setYScale = function (is100Pct, forcedTickCount, forcedYDomain, axisScaleType, axisDisplayUnits, axisPrecision, ensureYDomain) {
55307 var height = this.height;
55308 var forcedYMin, forcedYMax;
55309 if (forcedYDomain && forcedYDomain.length === 2) {
55310 forcedYMin = forcedYDomain[0];
55311 forcedYMax = forcedYDomain[1];
55312 }
55313 var props = this.yProps = visuals.ColumnUtil.getCategoryAxis(this.data, height, this.categoryLayout, true, forcedYMin, forcedYMax, axisScaleType, axisDisplayUnits, axisPrecision, ensureYDomain);
55314 return props;
55315 };
55316 StackedBarChartStrategy.prototype.setXScale = function (is100Pct, forcedTickCount, forcedXDomain, axisScaleType, axisDisplayUnits, axisPrecision, ensureXDomain) {
55317 debug.assert(forcedTickCount === undefined, 'Cannot have stacked bar chart as combo chart.');
55318 var width = this.width;
55319 var valueDomain = visuals.StackedUtil.calcValueDomain(this.data.series, is100Pct);
55320 var valueDomainArr = [valueDomain.min, valueDomain.max];
55321 var combinedDomain = visuals.AxisHelper.combineDomain(forcedXDomain, valueDomainArr, ensureXDomain);
55322 var shouldClamp = visuals.AxisHelper.scaleShouldClamp(combinedDomain, valueDomainArr);
55323 var metadataColumn = this.data.valuesMetadata[0];
55324 var formatString = is100Pct ?
55325 this.graphicsContext.hostService.getLocalizedString('Percentage')
55326 : visuals.valueFormatter.getFormatString(metadataColumn, visuals.columnChartProps.general.formatString);
55327 this.xProps = visuals.AxisHelper.createAxis({
55328 pixelSpan: width,
55329 dataDomain: combinedDomain,
55330 metaDataColumn: metadataColumn,
55331 formatString: formatString,
55332 outerPadding: 0,
55333 isScalar: true,
55334 isVertical: false,
55335 forcedTickCount: forcedTickCount,
55336 useTickIntervalForDisplayUnits: true,
55337 isCategoryAxis: false,
55338 scaleType: axisScaleType,
55339 axisDisplayUnits: axisDisplayUnits,
55340 axisPrecision: axisPrecision,
55341 is100Pct: is100Pct,
55342 shouldClamp: shouldClamp,
55343 });
55344 this.xProps.axis.tickSize(-this.viewportHeight, 0);
55345 return this.xProps;
55346 };
55347 StackedBarChartStrategy.prototype.drawColumns = function (useAnimation) {
55348 var data = this.data;
55349 debug.assertValue(data, 'data should not be null or undefined');
55350 this.barsCenters = null; // invalidate the barsCenters so that will be calculated again
55351 var axisOptions = {
55352 columnWidth: this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio),
55353 xScale: this.xProps.scale,
55354 yScale: this.yProps.scale,
55355 isScalar: this.categoryLayout.isScalar,
55356 margin: this.margin,
55357 };
55358 var stackedBarLayout = this.layout = StackedBarChartStrategy.getLayout(data, axisOptions);
55359 var dataLabelSettings = data.labelSettings;
55360 var labelDataPoints = [];
55361 if (dataLabelSettings && dataLabelSettings.show) {
55362 labelDataPoints = this.createLabelDataPoints();
55363 }
55364 var result;
55365 var shapes;
55366 var series = visuals.ColumnUtil.drawSeries(data, this.graphicsContext.mainGraphicsContext, axisOptions);
55367 if (this.animator && useAnimation) {
55368 result = this.animator.animate({
55369 viewModel: data,
55370 series: series,
55371 layout: stackedBarLayout,
55372 itemCS: StackedBarChartStrategy.classes.item,
55373 interactivityService: this.interactivityService,
55374 mainGraphicsContext: this.graphicsContext.mainGraphicsContext,
55375 viewPort: { height: this.height, width: this.width },
55376 });
55377 shapes = result.shapes;
55378 }
55379 if (!this.animator || !useAnimation || result.failed) {
55380 shapes = visuals.ColumnUtil.drawDefaultShapes(data, series, stackedBarLayout, StackedBarChartStrategy.classes.item, !this.animator, this.interactivityService && this.interactivityService.hasSelection());
55381 }
55382 visuals.ColumnUtil.applyInteractivity(shapes, this.graphicsContext.onDragStart);
55383 return {
55384 eventGroup: this.graphicsContext.mainGraphicsContext,
55385 shapesSelection: shapes,
55386 viewport: { height: this.height, width: this.width },
55387 axisOptions: axisOptions,
55388 labelDataPoints: labelDataPoints,
55389 };
55390 };
55391 StackedBarChartStrategy.prototype.selectColumn = function (selectedColumnIndex, lastInteractiveSelectedColumnIndex) {
55392 visuals.ColumnUtil.setChosenColumnOpacity(this.graphicsContext.mainGraphicsContext, StackedBarChartStrategy.classes.item.selector, selectedColumnIndex, lastInteractiveSelectedColumnIndex);
55393 this.moveHandle(selectedColumnIndex);
55394 };
55395 StackedBarChartStrategy.prototype.getClosestColumnIndex = function (x, y) {
55396 return visuals.ColumnUtil.getClosestColumnIndex(y, this.getBarsCenters());
55397 };
55398 /**
55399 * Get the chart's columns centers (y value).
55400 */
55401 StackedBarChartStrategy.prototype.getBarsCenters = function () {
55402 var _this = this;
55403 if (!this.barsCenters) {
55404 var barWidth = this.categoryLayout.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio);
55405 // use the axis scale and first series data to get category centers
55406 if (this.data.series.length > 0) {
55407 var yScaleOffset_2 = 0;
55408 if (!this.categoryLayout.isScalar)
55409 yScaleOffset_2 = barWidth / 2;
55410 var firstSeries = this.data.series[0];
55411 this.barsCenters = firstSeries.data.map(function (d) { return _this.yProps.scale(_this.categoryLayout.isScalar ? d.categoryValue : d.categoryIndex) + yScaleOffset_2; });
55412 }
55413 }
55414 return this.barsCenters;
55415 };
55416 StackedBarChartStrategy.prototype.moveHandle = function (selectedColumnIndex) {
55417 var barCenters = this.getBarsCenters();
55418 var y = barCenters[selectedColumnIndex];
55419 var hoverLine = d3.select('.interactive-hover-line');
55420 if (!hoverLine.empty() && !this.columnSelectionLineHandle) {
55421 this.columnSelectionLineHandle = d3.select(hoverLine.node().parentNode);
55422 }
55423 if (!this.columnSelectionLineHandle) {
55424 var handle = this.columnSelectionLineHandle = this.graphicsContext.unclippedGraphicsContext.append('g');
55425 handle.append('line')
55426 .classed('interactive-hover-line', true)
55427 .attr({
55428 x1: 0,
55429 x2: this.width,
55430 y1: y,
55431 y2: y
55432 });
55433 handle.append('circle')
55434 .classed('drag-handle', true)
55435 .attr({
55436 cx: 0,
55437 cy: y,
55438 r: '6px',
55439 });
55440 }
55441 else {
55442 var handle = this.columnSelectionLineHandle;
55443 handle.select('line').attr({ y1: y, y2: y });
55444 handle.select('circle').attr({ cy: y });
55445 }
55446 };
55447 StackedBarChartStrategy.getLayout = function (data, axisOptions) {
55448 var columnWidth = axisOptions.columnWidth;
55449 var isScalar = axisOptions.isScalar;
55450 var xScale = axisOptions.xScale;
55451 var yScale = axisOptions.yScale;
55452 var yScaleOffset = 0;
55453 if (isScalar)
55454 yScaleOffset = columnWidth / 2;
55455 // d.position is the top right corner for bars - set in columnChart.converter
55456 // for positive values, this is the previous stack position + the new value,
55457 // for negative values it is just the previous stack position
55458 return {
55459 shapeLayout: {
55460 width: function (d) { return xScale(d.position) - xScale(d.position - d.valueAbsolute); },
55461 x: function (d) { return xScale(d.position - d.valueAbsolute); },
55462 y: function (d) { return yScale(isScalar ? d.categoryValue : d.categoryIndex) - yScaleOffset; },
55463 height: function (d) { return columnWidth; },
55464 },
55465 shapeLayoutWithoutHighlights: {
55466 width: function (d) { return xScale(d.originalPosition) - xScale(d.originalPosition - d.originalValueAbsolute); },
55467 x: function (d) { return xScale(d.originalPosition - d.originalValueAbsolute); },
55468 y: function (d) { return yScale(isScalar ? d.categoryValue : d.categoryIndex) - yScaleOffset; },
55469 height: function (d) { return columnWidth; },
55470 },
55471 zeroShapeLayout: {
55472 width: function (d) { return 0; },
55473 x: function (d) { return d.value >= 0 ? xScale(d.position - d.valueAbsolute) : xScale(d.position); },
55474 y: function (d) { return yScale(isScalar ? d.categoryValue : d.categoryIndex) - yScaleOffset; },
55475 height: function (d) { return columnWidth; },
55476 },
55477 };
55478 };
55479 StackedBarChartStrategy.prototype.createLabelDataPoints = function () {
55480 var labelDataPoints = [];
55481 var data = this.data;
55482 var series = data.series;
55483 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
55484 var shapeLayout = this.layout.shapeLayout;
55485 for (var _i = 0, series_5 = series; _i < series_5.length; _i++) {
55486 var currentSeries = series_5[_i];
55487 var labelSettings = currentSeries.labelSettings ? currentSeries.labelSettings : data.labelSettings;
55488 if (!labelSettings.show)
55489 continue;
55490 var axisFormatter = visuals.NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter(this.yProps.formatter, labelSettings);
55491 for (var _a = 0, _b = currentSeries.data; _a < _b.length; _a++) {
55492 var dataPoint = _b[_a];
55493 if ((this.interactivityService && this.interactivityService.hasSelection() && !dataPoint.selected) || (data.hasHighlights && !dataPoint.highlight) || dataPoint.value == null) {
55494 continue;
55495 }
55496 // Calculate label text
55497 var formatString = undefined;
55498 if (this.graphicsContext.is100Pct) {
55499 formatString = visuals.NewDataLabelUtils.hundredPercentFormat;
55500 }
55501 else {
55502 formatString = dataPoint.labelFormatString;
55503 }
55504 var formatter = formattersCache.getOrCreate(formatString, labelSettings, axisFormatter);
55505 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(dataPoint.value));
55506 // Calculate text size
55507 var properties = {
55508 text: text,
55509 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
55510 fontSize: PixelConverter.fromPoint(labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt),
55511 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
55512 };
55513 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
55514 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
55515 // Calculate parent rectangle
55516 var parentRect = {
55517 left: shapeLayout.x(dataPoint),
55518 top: shapeLayout.y(dataPoint),
55519 width: shapeLayout.width(dataPoint),
55520 height: shapeLayout.height(dataPoint),
55521 };
55522 labelDataPoints.push({
55523 isPreferred: true,
55524 text: text,
55525 textSize: {
55526 width: textWidth,
55527 height: textHeight,
55528 },
55529 outsideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, false, this.isComboChart),
55530 insideFill: visuals.ColumnChart.getLabelFill(labelSettings.labelColor, true, this.isComboChart),
55531 parentType: 1 /* Rectangle */,
55532 parentShape: {
55533 rect: parentRect,
55534 orientation: dataPoint.value >= 0 ? 3 /* HorizontalLeftBased */ : 4 /* HorizontalRightBased */,
55535 validPositions: visuals.ColumnChart.stackedValidLabelPositions,
55536 },
55537 identity: dataPoint.identity,
55538 fontSize: labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt,
55539 });
55540 }
55541 }
55542 return labelDataPoints;
55543 };
55544 StackedBarChartStrategy.classes = {
55545 item: {
55546 class: 'bar',
55547 selector: '.bar'
55548 },
55549 highlightItem: {
55550 class: 'highlightBar',
55551 selector: '.highlightBar'
55552 },
55553 };
55554 return StackedBarChartStrategy;
55555 }());
55556 visuals.StackedBarChartStrategy = StackedBarChartStrategy;
55557 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
55558})(powerbi || (powerbi = {}));
55559/*
55560 * Power BI Visualizations
55561 *
55562 * Copyright (c) Microsoft Corporation
55563 * All rights reserved.
55564 * MIT License
55565 *
55566 * Permission is hereby granted, free of charge, to any person obtaining a copy
55567 * of this software and associated documentation files (the ""Software""), to deal
55568 * in the Software without restriction, including without limitation the rights
55569 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55570 * copies of the Software, and to permit persons to whom the Software is
55571 * furnished to do so, subject to the following conditions:
55572 *
55573 * The above copyright notice and this permission notice shall be included in
55574 * all copies or substantial portions of the Software.
55575 *
55576 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55577 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55578 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55579 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55580 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55581 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55582 * THE SOFTWARE.
55583 */
55584var powerbi;
55585(function (powerbi) {
55586 var visuals;
55587 (function (visuals) {
55588 var samples;
55589 (function (samples) {
55590 var SelectionManager = visuals.utility.SelectionManager;
55591 var HelloIVisual = (function () {
55592 function HelloIVisual() {
55593 }
55594 HelloIVisual.converter = function (dataView) {
55595 var viewModel = {
55596 size: HelloIVisual.getSize(dataView),
55597 color: HelloIVisual.getFill(dataView).solid.color,
55598 text: HelloIVisual.DefaultText,
55599 toolTipInfo: [{
55600 displayName: 'Test',
55601 value: '1...2....3... can you see me? I am sending random strings to the tooltip',
55602 }],
55603 selector: visuals.SelectionId.createNull()
55604 };
55605 var table = dataView.table;
55606 if (!table)
55607 return viewModel;
55608 viewModel.text = table.rows[0][0];
55609 if (dataView.categorical) {
55610 viewModel.selector = dataView.categorical.categories[0].identity
55611 ? visuals.SelectionId.createWithId(dataView.categorical.categories[0].identity[0])
55612 : visuals.SelectionId.createNull();
55613 }
55614 return viewModel;
55615 };
55616 HelloIVisual.prototype.init = function (options) {
55617 this.root = d3.select(options.element.get(0))
55618 .append('svg')
55619 .classed('hello', true);
55620 this.svgText = this.root
55621 .append('text')
55622 .style('cursor', 'pointer')
55623 .style('stroke', 'green')
55624 .style('stroke-width', '0px')
55625 .attr('text-anchor', 'middle');
55626 this.selectiionManager = new SelectionManager({ hostServices: options.host });
55627 };
55628 HelloIVisual.prototype.update = function (options) {
55629 if (!options.dataViews && !options.dataViews[0])
55630 return;
55631 var dataView = this.dataView = options.dataViews[0];
55632 var viewport = options.viewport;
55633 var viewModel = HelloIVisual.converter(dataView);
55634 this.root.attr({
55635 'height': viewport.height,
55636 'width': viewport.width
55637 });
55638 var textProperties = {
55639 fontFamily: 'tahoma',
55640 fontSize: viewModel.size + 'px',
55641 text: viewModel.text
55642 };
55643 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(textProperties);
55644 var selectionManager = this.selectiionManager;
55645 this.svgText.style({
55646 'fill': viewModel.color,
55647 'font-size': textProperties.fontSize,
55648 'font-family': textProperties.fontFamily,
55649 }).attr({
55650 'y': viewport.height / 2 + textHeight / 3 + 'px',
55651 'x': viewport.width / 2,
55652 }).text(viewModel.text)
55653 .on('click', function () {
55654 var _this = this;
55655 selectionManager
55656 .select(viewModel.selector)
55657 .then(function (ids) { return d3.select(_this).style('stroke-width', ids.length > 0 ? '2px' : '0px'); });
55658 })
55659 .data([viewModel]);
55660 visuals.TooltipManager.addTooltip(this.svgText, function (tooltipEvent) { return tooltipEvent.data.toolTipInfo; });
55661 };
55662 HelloIVisual.getFill = function (dataView) {
55663 if (dataView) {
55664 var objects = dataView.metadata.objects;
55665 if (objects) {
55666 var general = objects['general'];
55667 if (general) {
55668 var fill = general['fill'];
55669 if (fill)
55670 return fill;
55671 }
55672 }
55673 }
55674 return { solid: { color: 'red' } };
55675 };
55676 HelloIVisual.getSize = function (dataView) {
55677 if (dataView) {
55678 var objects = dataView.metadata.objects;
55679 if (objects) {
55680 var general = objects['general'];
55681 if (general) {
55682 var size = general['size'];
55683 if (size)
55684 return size;
55685 }
55686 }
55687 }
55688 return 100;
55689 };
55690 HelloIVisual.prototype.enumerateObjectInstances = function (options) {
55691 var instances = [];
55692 var dataView = this.dataView;
55693 switch (options.objectName) {
55694 case 'general':
55695 var general = {
55696 objectName: 'general',
55697 displayName: 'General',
55698 selector: null,
55699 properties: {
55700 fill: HelloIVisual.getFill(dataView),
55701 size: HelloIVisual.getSize(dataView)
55702 }
55703 };
55704 instances.push(general);
55705 break;
55706 }
55707 return instances;
55708 };
55709 HelloIVisual.prototype.destroy = function () {
55710 this.root = null;
55711 };
55712 HelloIVisual.capabilities = {
55713 dataRoles: [{
55714 displayName: 'Values',
55715 name: 'Values',
55716 kind: powerbi.VisualDataRoleKind.GroupingOrMeasure
55717 }],
55718 dataViewMappings: [{
55719 table: {
55720 rows: {
55721 for: { in: 'Values' },
55722 dataReductionAlgorithm: { window: { count: 100 } }
55723 },
55724 rowCount: { preferred: { min: 1 } }
55725 },
55726 }],
55727 objects: {
55728 general: {
55729 displayName: powerbi.data.createDisplayNameGetter('Visual_General'),
55730 properties: {
55731 fill: {
55732 type: { fill: { solid: { color: true } } },
55733 displayName: 'Fill'
55734 },
55735 size: {
55736 type: { numeric: true },
55737 displayName: 'Size'
55738 }
55739 },
55740 }
55741 },
55742 };
55743 HelloIVisual.DefaultText = 'Invalid DV';
55744 return HelloIVisual;
55745 }());
55746 samples.HelloIVisual = HelloIVisual;
55747 })(samples = visuals.samples || (visuals.samples = {}));
55748 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
55749})(powerbi || (powerbi = {}));
55750/*
55751 * Power BI Visualizations
55752 *
55753 * Copyright (c) Microsoft Corporation
55754 * All rights reserved.
55755 * MIT License
55756 *
55757 * Permission is hereby granted, free of charge, to any person obtaining a copy
55758 * of this software and associated documentation files (the ""Software""), to deal
55759 * in the Software without restriction, including without limitation the rights
55760 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55761 * copies of the Software, and to permit persons to whom the Software is
55762 * furnished to do so, subject to the following conditions:
55763 *
55764 * The above copyright notice and this permission notice shall be included in
55765 * all copies or substantial portions of the Software.
55766 *
55767 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55768 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55769 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55770 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55771 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55772 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55773 * THE SOFTWARE.
55774 */
55775var powerbi;
55776(function (powerbi) {
55777 var visuals;
55778 (function (visuals) {
55779 /**
55780 * This module only supplies the capabilities for comboCharts.
55781 * Implementation is in cartesianChart and the various ICartesianVisual implementations.
55782 */
55783 var ComboChart;
55784 (function (ComboChart) {
55785 ComboChart.capabilities = visuals.comboChartCapabilities;
55786 /**
55787 * Handles the case of a column layer in a combo chart. In this case, the column layer is enumearated last.
55788 */
55789 function enumerateDataPoints(enumeration, options, layers) {
55790 if (!layers)
55791 return;
55792 var columnChartLayerIndex;
55793 var layersLength = layers.length;
55794 for (var layerIndex = 0; layerIndex < layersLength; layerIndex++) {
55795 var layer = layers[layerIndex];
55796 if (layer.enumerateObjectInstances) {
55797 if (layer instanceof visuals.ColumnChart) {
55798 columnChartLayerIndex = layerIndex;
55799 continue;
55800 }
55801 layer.enumerateObjectInstances(enumeration, options);
55802 }
55803 }
55804 if (columnChartLayerIndex !== undefined)
55805 layers[columnChartLayerIndex].enumerateObjectInstances(enumeration, options);
55806 }
55807 ComboChart.enumerateDataPoints = enumerateDataPoints;
55808 function customizeQuery(options) {
55809 // If there is a dynamic series but no values on the column data view mapping, remove the dynamic series
55810 var columnMapping = !_.isEmpty(options.dataViewMappings) && options.dataViewMappings[0];
55811 if (columnMapping) {
55812 var columnValuesMapping = columnMapping.categorical && columnMapping.categorical.values;
55813 var seriesSelect = columnValuesMapping.group && !_.isEmpty(columnValuesMapping.group.select) && columnValuesMapping.group.select[0];
55814 if (_.isEmpty(seriesSelect.for.in.items))
55815 columnValuesMapping.group.by.items = undefined;
55816 }
55817 if (columnMapping && columnMapping.categorical) {
55818 columnMapping.categorical.dataVolume = 4;
55819 }
55820 var lineMapping = options.dataViewMappings.length > 1 && options.dataViewMappings[1];
55821 if (lineMapping && lineMapping.categorical) {
55822 lineMapping.categorical.dataVolume = 4;
55823 }
55824 }
55825 ComboChart.customizeQuery = customizeQuery;
55826 function getSortableRoles(options) {
55827 if (options && options.dataViewMappings.length > 0) {
55828 var dataViewMapping = options.dataViewMappings[0];
55829 //TODO: column chart should be sortable by X if it has scalar axis
55830 // But currenly it doesn't support this. Return 'category' once
55831 // it is supported.
55832 if (!visuals.CartesianChart.detectScalarMapping(dataViewMapping))
55833 return ['Category', 'Y', 'Y2'];
55834 }
55835 return null;
55836 }
55837 ComboChart.getSortableRoles = getSortableRoles;
55838 function isComboChart(chartType) {
55839 return chartType === 10 /* ComboChart */
55840 || chartType === 13 /* LineClusteredColumnCombo */
55841 || chartType === 14 /* LineStackedColumnCombo */
55842 || chartType === 15 /* DataDotClusteredColumnCombo */
55843 || chartType === 16 /* DataDotStackedColumnCombo */;
55844 }
55845 ComboChart.isComboChart = isComboChart;
55846 })(ComboChart = visuals.ComboChart || (visuals.ComboChart = {}));
55847 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
55848})(powerbi || (powerbi = {}));
55849/*
55850 * Power BI Visualizations
55851 *
55852 * Copyright (c) Microsoft Corporation
55853 * All rights reserved.
55854 * MIT License
55855 *
55856 * Permission is hereby granted, free of charge, to any person obtaining a copy
55857 * of this software and associated documentation files (the ""Software""), to deal
55858 * in the Software without restriction, including without limitation the rights
55859 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55860 * copies of the Software, and to permit persons to whom the Software is
55861 * furnished to do so, subject to the following conditions:
55862 *
55863 * The above copyright notice and this permission notice shall be included in
55864 * all copies or substantial portions of the Software.
55865 *
55866 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55867 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55868 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55869 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55870 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55871 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55872 * THE SOFTWARE.
55873 */
55874var powerbi;
55875(function (powerbi) {
55876 var visuals;
55877 (function (visuals) {
55878 var ArrayExtensions = jsCommon.ArrayExtensions;
55879 var DataColorPalette = (function () {
55880 /**
55881 * Creates a DataColorPalette using the given theme, or the default theme.
55882 */
55883 function DataColorPalette(colors, sentimentcolors) {
55884 // Hardcoded values for Color Picker.
55885 this.basePickerColors = [
55886 { value: '#FFFFFF' },
55887 { value: '#000000' },
55888 { value: '#00B8AA' },
55889 { value: '#374649' },
55890 { value: '#FD625E' },
55891 { value: '#F2C811' },
55892 { value: '#5F6B6D' },
55893 { value: '#8AD4EB' },
55894 { value: '#FE9666' },
55895 { value: '#A66999' }
55896 ];
55897 // TODO: Default theme is currently hardcoded. Theme should eventually come from PV and be added as a parameter in the ctor.
55898 this.colors = colors || ThemeManager.getDefaultTheme();
55899 this.sentimentColors = sentimentcolors || ThemeManager.defaultSentimentColors;
55900 this.scales = {};
55901 }
55902 DataColorPalette.prototype.getColorScaleByKey = function (key) {
55903 var scale = this.scales[key];
55904 if (scale === undefined) {
55905 scale = this.createScale();
55906 this.scales[key] = scale;
55907 }
55908 return scale;
55909 };
55910 DataColorPalette.prototype.getNewColorScale = function () {
55911 return this.createScale();
55912 };
55913 DataColorPalette.prototype.getColorByIndex = function (index) {
55914 debug.assert(index >= 0 && index < this.colors.length, 'index is out of bounds');
55915 return this.colors[index];
55916 };
55917 DataColorPalette.prototype.getSentimentColors = function () {
55918 return this.sentimentColors;
55919 };
55920 DataColorPalette.prototype.getBasePickerColors = function () {
55921 return this.basePickerColors;
55922 };
55923 DataColorPalette.prototype.getAllColors = function () {
55924 return this.colors;
55925 };
55926 DataColorPalette.prototype.createScale = function () {
55927 return D3ColorScale.createFromColors(this.colors);
55928 };
55929 return DataColorPalette;
55930 }());
55931 visuals.DataColorPalette = DataColorPalette;
55932 var D3ColorScale = (function () {
55933 function D3ColorScale(scale) {
55934 this.scale = scale;
55935 }
55936 D3ColorScale.prototype.getColor = function (key) {
55937 return this.scale(key);
55938 };
55939 D3ColorScale.prototype.clearAndRotateScale = function () {
55940 var offset = this.scale.domain().length;
55941 var rotatedColors = ArrayExtensions.rotate(this.scale.range(), offset);
55942 this.scale = d3.scale.ordinal().range(rotatedColors);
55943 };
55944 D3ColorScale.prototype.clone = function () {
55945 return new D3ColorScale(this.scale.copy());
55946 };
55947 D3ColorScale.prototype.getDomain = function () {
55948 return this.scale.domain();
55949 };
55950 D3ColorScale.createFromColors = function (colors) {
55951 return new D3ColorScale(d3.scale.ordinal().range(colors));
55952 };
55953 return D3ColorScale;
55954 }());
55955 visuals.D3ColorScale = D3ColorScale;
55956 // TODO: When theming support is added, this should be changed into a fully fledged service. For now though we will
55957 var ThemeManager = (function () {
55958 function ThemeManager() {
55959 }
55960 ThemeManager.getDefaultTheme = function () {
55961 if (!ThemeManager.defaultTheme) {
55962 // Extend the list of available colors by cycling the base colors
55963 ThemeManager.defaultTheme = [];
55964 var baseColors = ThemeManager.defaultBaseColors;
55965 for (var i = 0; i < ThemeManager.colorSectorCount; ++i) {
55966 for (var j = 0, jlen = baseColors.length; j < jlen; ++j) {
55967 ThemeManager.defaultTheme.push({
55968 value: jsCommon.Color.rotate(baseColors[j].value, i / ThemeManager.colorSectorCount)
55969 });
55970 }
55971 }
55972 }
55973 return ThemeManager.defaultTheme;
55974 };
55975 ThemeManager.colorSectorCount = 12;
55976 // declare the Theme code as a private implementation detail inside the DataColorPalette so that the code stays hidden
55977 // until it's ready for wider use.
55978 ThemeManager.defaultBaseColors = [
55979 // First loop
55980 { value: '#01B8AA' },
55981 { value: '#374649' },
55982 { value: '#FD625E' },
55983 { value: '#F2C80F' },
55984 { value: '#5F6B6D' },
55985 { value: '#8AD4EB' },
55986 { value: '#FE9666' },
55987 { value: '#A66999' },
55988 { value: '#3599B8' },
55989 { value: '#DFBFBF' },
55990 // Second loop
55991 { value: '#4AC5BB' },
55992 { value: '#5F6B6D' },
55993 { value: '#FB8281' },
55994 { value: '#F4D25A' },
55995 { value: '#7F898A' },
55996 { value: '#A4DDEE' },
55997 { value: '#FDAB89' },
55998 { value: '#B687AC' },
55999 { value: '#28738A' },
56000 { value: '#A78F8F' },
56001 // Third loop
56002 { value: '#168980' },
56003 { value: '#293537' },
56004 { value: '#BB4A4A' },
56005 { value: '#B59525' },
56006 { value: '#475052' },
56007 { value: '#6A9FB0' },
56008 { value: '#BD7150' },
56009 { value: '#7B4F71' },
56010 { value: '#1B4D5C' },
56011 { value: '#706060' },
56012 // Fourth loop
56013 { value: '#0F5C55' },
56014 { value: '#1C2325' },
56015 { value: '#7D3231' },
56016 { value: '#796419' },
56017 { value: '#303637' },
56018 { value: '#476A75' },
56019 { value: '#7E4B36' },
56020 { value: '#52354C' },
56021 { value: '#0D262E' },
56022 { value: '#544848' },
56023 ];
56024 ThemeManager.defaultSentimentColors = [
56025 { value: '#C0433A' },
56026 { value: '#E8D62E' },
56027 { value: '#79C75B' },
56028 ];
56029 return ThemeManager;
56030 }());
56031 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
56032})(powerbi || (powerbi = {}));
56033/*
56034 * Power BI Visualizations
56035 *
56036 * Copyright (c) Microsoft Corporation
56037 * All rights reserved.
56038 * MIT License
56039 *
56040 * Permission is hereby granted, free of charge, to any person obtaining a copy
56041 * of this software and associated documentation files (the ""Software""), to deal
56042 * in the Software without restriction, including without limitation the rights
56043 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56044 * copies of the Software, and to permit persons to whom the Software is
56045 * furnished to do so, subject to the following conditions:
56046 *
56047 * The above copyright notice and this permission notice shall be included in
56048 * all copies or substantial portions of the Software.
56049 *
56050 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56051 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56052 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56053 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56054 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56055 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
56056 * THE SOFTWARE.
56057 */
56058/**
56059 * IMPORTANT: This chart is not currently enabled in the PBI system and is under development.
56060 */
56061var powerbi;
56062(function (powerbi) {
56063 var visuals;
56064 (function (visuals) {
56065 /**
56066 * The data dot chart shows a set of circles with the data value inside them.
56067 * The circles are regularly spaced similar to column charts.
56068 * The radius of all dots is the same across the chart.
56069 * This is most often combined with a column chart to create the 'chicken pox' chart.
56070 * If any of the data values do not fit within the circles, then the data values are hidden
56071 * and the y axis for the dots is displayed instead.
56072 * This chart only supports a single series of data.
56073 * This chart does not display a legend.
56074 */
56075 var DataDotChart = (function () {
56076 function DataDotChart(options) {
56077 this.isScrollable = options.isScrollable;
56078 this.interactivityService = options.interactivityService;
56079 }
56080 DataDotChart.prototype.init = function (options) {
56081 this.options = options;
56082 // Common properties
56083 this.svg = options.svg;
56084 this.svg.classed(DataDotChart.ClassName, true);
56085 this.mainGraphicsG = this.svg.append('g')
56086 .classed('dataDotChartMainGraphicsContext', true);
56087 this.mainGraphicsContext = this.mainGraphicsG.append('svg');
56088 this.currentViewport = options.viewport;
56089 this.hostService = options.host;
56090 this.cartesianVisualHost = options.cartesianHost;
56091 this.style = options.style;
56092 this.colors = this.style.colorPalette.dataColors;
56093 // Interactivity properties
56094 this.interactivity = options.interactivity;
56095 this.element = options.element;
56096 };
56097 DataDotChart.prototype.setData = function (dataViews) {
56098 this.data = {
56099 series: {
56100 data: []
56101 },
56102 hasHighlights: false,
56103 hasDynamicSeries: false,
56104 };
56105 if (dataViews.length > 0) {
56106 // I only handle a single data view
56107 var dataView = dataViews[0];
56108 if (dataView && dataView.categorical) {
56109 var dataViewCategorical = this.dataViewCategorical = dataView.categorical;
56110 var dvCategories = dataViewCategorical.categories;
56111 // I default to text unless there is a category type
56112 var categoryType = powerbi.ValueType.fromDescriptor({ text: true });
56113 if (dvCategories && dvCategories.length > 0 && dvCategories[0].source && dvCategories[0].source.type)
56114 categoryType = dvCategories[0].source.type;
56115 this.data = DataDotChart.converter(dataView, visuals.valueFormatter.format(null), this.interactivityService);
56116 }
56117 }
56118 };
56119 DataDotChart.prototype.setFilteredData = function (startIndex, endIndex) {
56120 var data = this.clippedData = powerbi.Prototype.inherit(this.data);
56121 if (data && data.series && data.series.data)
56122 data.series = { data: data.series.data.slice(startIndex, endIndex), xCol: data.series.xCol, yCol: data.series.yCol };
56123 return data;
56124 };
56125 DataDotChart.prototype.calculateAxesProperties = function (options) {
56126 var _this = this;
56127 this.currentViewport = options.viewport;
56128 this.margin = options.margin;
56129 var data = this.clippedData = this.data;
56130 var viewport = this.currentViewport;
56131 var margin = this.margin;
56132 var series = data ? data.series : null;
56133 var seriesArray = series && series.data && series.data.length > 0 ? [series] : [];
56134 var categoryCount = series && series.data ? series.data.length : 0;
56135 // If there are highlights, then the series is 2x in length and highlights are interwoven.
56136 if (data.hasHighlights) {
56137 categoryCount = categoryCount / 2;
56138 }
56139 var width = viewport.width - (margin.left + margin.right);
56140 var height = viewport.height - (margin.top + margin.bottom);
56141 var xMetaDataColumn;
56142 var yMetaDataColumn;
56143 if (DataDotChart.hasDataPoint(series)) {
56144 xMetaDataColumn = series.xCol;
56145 yMetaDataColumn = series.yCol;
56146 }
56147 var layout = visuals.CartesianChart.getLayout(null, {
56148 availableWidth: width,
56149 categoryCount: categoryCount,
56150 domain: null,
56151 isScalar: false,
56152 isScrollable: this.isScrollable,
56153 trimOrdinalDataOnOverflow: options.trimOrdinalDataOnOverflow
56154 });
56155 var outerPadding = layout.categoryThickness * visuals.CartesianChart.OuterPaddingRatio;
56156 // clip data that won't fit
56157 if (!this.isScrollable) {
56158 this.clippedData = DataDotChart.createClippedDataIfOverflowed(data, layout.categoryCount);
56159 }
56160 var yDomain = visuals.AxisHelper.createValueDomain(seriesArray, /*includeZero:*/ true) || visuals.emptyDomain;
56161 var combinedDomain = visuals.AxisHelper.combineDomain(options.forcedYDomain, yDomain, options.ensureYDomain);
56162 this.yAxisProperties = visuals.AxisHelper.createAxis({
56163 pixelSpan: height,
56164 dataDomain: combinedDomain,
56165 metaDataColumn: yMetaDataColumn,
56166 formatString: visuals.valueFormatter.getFormatString(yMetaDataColumn, DataDotChart.formatStringProp),
56167 outerPadding: 0,
56168 isScalar: true,
56169 isVertical: true,
56170 forcedTickCount: options.forcedTickCount,
56171 useTickIntervalForDisplayUnits: true,
56172 isCategoryAxis: false
56173 });
56174 var axisType = this.xAxisProperties ? this.xAxisProperties.axisType : powerbi.ValueType.fromDescriptor({ text: true });
56175 var xDomain = visuals.AxisHelper.createDomain(seriesArray, axisType, /*isScalar:*/ false, options.forcedXDomain, options.ensureXDomain);
56176 this.xAxisProperties = visuals.AxisHelper.createAxis({
56177 pixelSpan: width,
56178 dataDomain: xDomain,
56179 metaDataColumn: xMetaDataColumn,
56180 formatString: visuals.valueFormatter.getFormatString(xMetaDataColumn, DataDotChart.formatStringProp),
56181 outerPadding: outerPadding,
56182 isScalar: false,
56183 isVertical: false,
56184 forcedTickCount: options.forcedTickCount,
56185 useTickIntervalForDisplayUnits: true,
56186 categoryThickness: layout.categoryThickness,
56187 getValueFn: function (index, type) { return _this.lookupXValue(index, type); },
56188 isCategoryAxis: true
56189 });
56190 return [this.xAxisProperties, this.yAxisProperties];
56191 };
56192 DataDotChart.createClippedDataIfOverflowed = function (data, categoryCount) {
56193 // If there are highlights, then the series is 2x in length and highlights are interwoven.
56194 var requiredLength = data.hasHighlights ? Math.min(data.series.data.length, categoryCount * 2) : Math.min(data.series.data.length, categoryCount);
56195 if (requiredLength >= data.series.data.length) {
56196 return data;
56197 }
56198 var clipped = powerbi.Prototype.inherit(data);
56199 clipped.series = powerbi.Prototype.inherit(data.series); // This prevents clipped and data from sharing the series object
56200 clipped.series.data = clipped.series.data.slice(0, requiredLength);
56201 return clipped;
56202 };
56203 DataDotChart.hasDataPoint = function (series) {
56204 return (series && series.data && series.data.length > 0);
56205 };
56206 DataDotChart.prototype.lookupXValue = function (index, type) {
56207 var data = this.data;
56208 var isDateTime = visuals.AxisHelper.isDateTime(type);
56209 if (isDateTime)
56210 return new Date(index);
56211 if (data && data.series) {
56212 var seriesData = data.series.data;
56213 if (seriesData) {
56214 var dataAtIndex = seriesData[index];
56215 if (dataAtIndex) {
56216 return dataAtIndex.categoryValue;
56217 }
56218 }
56219 }
56220 return index;
56221 };
56222 DataDotChart.prototype.overrideXScale = function (xProperties) {
56223 this.xAxisProperties = xProperties;
56224 };
56225 DataDotChart.prototype.render = function (suppressAnimations) {
56226 var _this = this;
56227 if (!this.clippedData)
56228 return;
56229 var data = this.clippedData;
56230 var dataPoints = data.series.data;
56231 var hasHighlights = data.hasHighlights;
56232 var margin = this.margin;
56233 var viewport = this.currentViewport;
56234 var width = viewport.width - (margin.left + margin.right);
56235 var height = viewport.height - (margin.top + margin.bottom);
56236 var xScale = this.xAxisProperties.scale;
56237 var yScale = this.yAxisProperties.scale;
56238 var dotWidth = this.xAxisProperties.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio);
56239 var dotRadius = dotWidth / 2;
56240 var dotColor = this.cartesianVisualHost.getSharedColors().getNewColorScale().getColor(DataDotChart.DotColorKey);
56241 var hasSelection = this.interactivityService ? this.interactivityService.hasSelection() : false;
56242 this.mainGraphicsContext.attr('width', width)
56243 .attr('height', height);
56244 var dots = this.mainGraphicsContext.selectAll(DataDotChart.DotClassSelector).data(dataPoints, function (d) { return d.identity.getKey(); });
56245 dots.enter()
56246 .append('circle')
56247 .classed(DataDotChart.DotClassName, true);
56248 dots
56249 .style({ 'fill': dotColor.value })
56250 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, hasHighlights); })
56251 .classed('null-value', function (d) { return d.value === null; })
56252 .attr({
56253 r: function (d) { return dotRadius; },
56254 cx: function (d) { return xScale(d.categoryIndex) + dotRadius; },
56255 cy: function (d) { return yScale(d.value); }
56256 });
56257 dots.exit().remove();
56258 var dotLabels = this.mainGraphicsContext.selectAll(DataDotChart.DotLabelClassSelector).data(dataPoints, function (d) { return d.identity.getKey(); });
56259 dotLabels.enter()
56260 .append('text')
56261 .classed(DataDotChart.DotLabelClassName, true)
56262 .attr({
56263 'text-anchor': DataDotChart.DotLabelTextAnchor,
56264 dy: DataDotChart.DotLabelVerticalOffset
56265 });
56266 dotLabels
56267 .classed('null-value', function (d) { return d.value === null; })
56268 .classed('overflowed', false)
56269 .attr({
56270 x: function (d) { return xScale(d.categoryIndex) + dotRadius; },
56271 y: function (d) { return yScale(d.value); }
56272 })
56273 .text(function (d) { return _this.yAxisProperties.formatter.format(d.value); });
56274 var overflowed = false;
56275 dotLabels
56276 .each(function () {
56277 // jQuery fails to properly inspect SVG class elements, the $('<div>') notation works around it.
56278 if (!overflowed && !$("<div>").addClass($(this).attr("class")).hasClass("null-value")) {
56279 var width_1 = powerbi.TextMeasurementService.measureSvgTextElementWidth(this);
56280 if (width_1 > dotWidth) {
56281 dotLabels.classed('overflowed', true);
56282 overflowed = true;
56283 }
56284 }
56285 });
56286 dotLabels.exit().remove();
56287 var behaviorOptions = undefined;
56288 if (this.interactivityService) {
56289 behaviorOptions = {
56290 dots: dots,
56291 dotLabels: dotLabels,
56292 datapoints: dataPoints
56293 };
56294 }
56295 // This should always be the last line in the render code.
56296 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
56297 return { dataPoints: dataPoints, behaviorOptions: behaviorOptions, labelDataPoints: [], labelsAreNumeric: true };
56298 };
56299 DataDotChart.prototype.calculateLegend = function () {
56300 return this.createLegendDataPoints(0); // start with index 0
56301 };
56302 DataDotChart.prototype.hasLegend = function () {
56303 return this.data && this.data.hasDynamicSeries;
56304 };
56305 DataDotChart.prototype.createLegendDataPoints = function (columnIndex) {
56306 var data = this.data;
56307 if (!data)
56308 return null;
56309 var series = data.series;
56310 var seriesData = series.data;
56311 var legendDataPoints = [];
56312 var category;
56313 var axisType = this.xAxisProperties ? this.xAxisProperties.axisType : powerbi.ValueType.fromDescriptor({ text: true });
56314 // Category will be the same for all series. This is an optimization.
56315 if (data.series && data.series.data) {
56316 var firstDataPoint = data.series.data[0];
56317 category = firstDataPoint && this.lookupXValue(firstDataPoint.categoryValue, axisType);
56318 }
56319 // Create a legend data point for the specified column
56320 if (series.yCol) {
56321 var formatStringProp = DataDotChart.formatStringProp;
56322 var lineDataPoint = seriesData[columnIndex];
56323 var measure = lineDataPoint && lineDataPoint.value;
56324 var label = visuals.converterHelper.getFormattedLegendLabel(series.yCol, this.dataViewCategorical.values, formatStringProp);
56325 var dotColor = this.cartesianVisualHost.getSharedColors().getNewColorScale().getColor(DataDotChart.DotColorKey);
56326 var dataViewCategoricalValues = this.dataViewCategorical.values;
56327 var identity = dataViewCategoricalValues && dataViewCategoricalValues.length > columnIndex ?
56328 visuals.SelectionId.createWithIdAndMeasure(dataViewCategoricalValues[columnIndex].identity, dataViewCategoricalValues[columnIndex].source.queryName) :
56329 visuals.SelectionId.createWithMeasure(dataViewCategoricalValues.source.queryName);
56330 legendDataPoints.push({
56331 color: dotColor.value,
56332 icon: visuals.LegendIcon.Line,
56333 label: label,
56334 category: visuals.valueFormatter.format(category, visuals.valueFormatter.getFormatString(series.xCol, formatStringProp)),
56335 measure: visuals.valueFormatter.format(measure, visuals.valueFormatter.getFormatString(series.yCol, formatStringProp)),
56336 identity: identity,
56337 selected: false
56338 });
56339 }
56340 return { dataPoints: legendDataPoints };
56341 };
56342 DataDotChart.prototype.onClearSelection = function () {
56343 if (this.interactivityService)
56344 this.interactivityService.clearSelection();
56345 // cartesianChart handles calling render again.
56346 };
56347 DataDotChart.converter = function (dataView, blankCategoryValue, interactivityService) {
56348 var categorical = dataView.categorical;
56349 var category = categorical.categories && categorical.categories.length > 0
56350 ? categorical.categories[0]
56351 : {
56352 source: undefined,
56353 values: [blankCategoryValue],
56354 identity: undefined
56355 };
56356 var categoryType = visuals.AxisHelper.getCategoryValueType(category.source);
56357 var isDateTime = visuals.AxisHelper.isDateTime(categoryType);
56358 var categoryValues = category.values;
56359 // I only handle a single series
56360 if (!_.isEmpty(categorical.values)) {
56361 var measure = categorical.values[0];
56362 var hasHighlights = !!measure.highlights;
56363 var dataPoints = [];
56364 for (var categoryIndex = 0, len = measure.values.length; categoryIndex < len; categoryIndex++) {
56365 debug.assert(!category.identity || categoryIndex < category.identity.length, 'Category identities is smaller than category values.');
56366 // I create the identity from the category. If there is no category, then I use the measure name to create identity
56367 var identity = category.identity ?
56368 visuals.SelectionId.createWithIdAndMeasure(category.identity[categoryIndex], measure.source.queryName) :
56369 visuals.SelectionId.createWithMeasure(measure.source.queryName);
56370 var categoryValue = categoryValues[categoryIndex];
56371 // ignore variant measures
56372 if (isDateTime && categoryValue != null && !(categoryValue instanceof Date))
56373 continue;
56374 dataPoints.push({
56375 categoryValue: isDateTime && categoryValue ? categoryValue.getTime() : categoryValue,
56376 value: measure.values[categoryIndex],
56377 categoryIndex: categoryIndex,
56378 seriesIndex: 0,
56379 selected: false,
56380 identity: identity,
56381 highlight: false
56382 });
56383 if (hasHighlights) {
56384 var highlightIdentity = visuals.SelectionId.createWithHighlight(identity);
56385 var highlightValue = measure.highlights[categoryIndex];
56386 dataPoints.push({
56387 categoryValue: isDateTime && categoryValue ? categoryValue.getTime() : categoryValue,
56388 value: highlightValue,
56389 categoryIndex: categoryIndex,
56390 seriesIndex: 0,
56391 selected: false,
56392 identity: highlightIdentity,
56393 highlight: true
56394 });
56395 }
56396 }
56397 if (interactivityService)
56398 interactivityService.applySelectionStateToData(dataPoints);
56399 return {
56400 series: {
56401 xCol: category.source,
56402 yCol: measure.source,
56403 data: dataPoints
56404 },
56405 hasHighlights: hasHighlights,
56406 hasDynamicSeries: true,
56407 };
56408 }
56409 return {
56410 series: {
56411 data: []
56412 },
56413 hasHighlights: false,
56414 hasDynamicSeries: false,
56415 };
56416 };
56417 DataDotChart.formatStringProp = { objectName: 'general', propertyName: 'formatString' };
56418 DataDotChart.ClassName = 'dataDotChart';
56419 DataDotChart.DotClassName = 'dot';
56420 DataDotChart.DotClassSelector = '.dot';
56421 DataDotChart.DotColorKey = 'dataDot';
56422 DataDotChart.DotLabelClassName = 'label';
56423 DataDotChart.DotLabelClassSelector = '.label';
56424 DataDotChart.DotLabelVerticalOffset = '0.4em';
56425 DataDotChart.DotLabelTextAnchor = 'middle';
56426 return DataDotChart;
56427 }());
56428 visuals.DataDotChart = DataDotChart;
56429 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
56430})(powerbi || (powerbi = {}));
56431/*
56432 * Power BI Visualizations
56433 *
56434 * Copyright (c) Microsoft Corporation
56435 * All rights reserved.
56436 * MIT License
56437 *
56438 * Permission is hereby granted, free of charge, to any person obtaining a copy
56439 * of this software and associated documentation files (the ""Software""), to deal
56440 * in the Software without restriction, including without limitation the rights
56441 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56442 * copies of the Software, and to permit persons to whom the Software is
56443 * furnished to do so, subject to the following conditions:
56444 *
56445 * The above copyright notice and this permission notice shall be included in
56446 * all copies or substantial portions of the Software.
56447 *
56448 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56449 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56450 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56451 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56452 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56453 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
56454 * THE SOFTWARE.
56455 */
56456var powerbi;
56457(function (powerbi) {
56458 var visuals;
56459 (function (visuals) {
56460 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
56461 var PixelConverter = jsCommon.PixelConverter;
56462 var DataRoleHelper = powerbi.data.DataRoleHelper;
56463 /**
56464 * Renders a funnel chart.
56465 */
56466 var FunnelChart = (function () {
56467 function FunnelChart(options) {
56468 this.labelPositionObjects = [visuals.labelPosition.outsideEnd, visuals.labelPosition.insideCenter];
56469 if (options) {
56470 this.tooltipsEnabled = options.tooltipsEnabled;
56471 if (options.funnelSmallViewPortProperties) {
56472 this.funnelSmallViewPortProperties = options.funnelSmallViewPortProperties;
56473 }
56474 if (options.animator) {
56475 this.animator = options.animator;
56476 }
56477 if (options.behavior) {
56478 this.behavior = options.behavior;
56479 }
56480 }
56481 }
56482 FunnelChart.isValidValueColumn = function (valueColumn) {
56483 debug.assertValue(valueColumn, 'valueColumn');
56484 return DataRoleHelper.hasRole(valueColumn.source, 'Y');
56485 };
56486 FunnelChart.getFirstValidValueColumn = function (values) {
56487 for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
56488 var valueColumn = values_1[_i];
56489 if (!FunnelChart.isValidValueColumn(valueColumn))
56490 continue;
56491 return valueColumn;
56492 }
56493 return undefined;
56494 };
56495 FunnelChart.converter = function (dataView, colors, hostServices, defaultDataPointColor, tooltipsEnabled) {
56496 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
56497 var slices = [];
56498 var formatStringProp = visuals.funnelChartProps.general.formatString;
56499 var categorical = dataView.categorical;
56500 var categories = categorical.categories || [];
56501 var values = categorical.values;
56502 var valueMetaData = [];
56503 if (values) {
56504 valueMetaData = _.map(values, function (v) { return v.source; });
56505 }
56506 var hasHighlights = values && values.length > 0 && values[0] && !!values[0].highlights;
56507 var highlightsOverflow = false;
56508 var hasNegativeValues = false;
56509 var allValuesAreNegative = false;
56510 var categoryLabels = [];
56511 var dataLabelsSettings = visuals.dataLabelUtils.getDefaultFunnelLabelSettings();
56512 var percentBarLabelSettings = visuals.dataLabelUtils.getDefaultLabelSettings(true);
56513 var colorHelper = new visuals.ColorHelper(colors, visuals.funnelChartProps.dataPoint.fill, defaultDataPointColor);
56514 var firstValue;
56515 var firstHighlight;
56516 var previousValue;
56517 var previousHighlight;
56518 var gradientValueColumn = visuals.GradientUtils.getGradientValueColumn(categorical);
56519 if (dataView && dataView.metadata && dataView.metadata.objects) {
56520 var labelsObj = dataView.metadata.objects['labels'];
56521 if (labelsObj)
56522 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelsObj, dataLabelsSettings);
56523 var percentLabelsObj = dataView.metadata.objects['percentBarLabel'];
56524 if (percentLabelsObj)
56525 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(percentLabelsObj, percentBarLabelSettings);
56526 }
56527 // Always take the first valid value field
56528 var firstValueColumn = !_.isEmpty(values) && FunnelChart.getFirstValidValueColumn(values);
56529 // If we don't have a valid value column, just return
56530 if (!firstValueColumn)
56531 return {
56532 slices: slices,
56533 categoryLabels: categoryLabels,
56534 valuesMetadata: valueMetaData,
56535 hasHighlights: hasHighlights,
56536 highlightsOverflow: highlightsOverflow,
56537 canShowDataLabels: true,
56538 dataLabelsSettings: dataLabelsSettings,
56539 hasNegativeValues: hasNegativeValues,
56540 allValuesAreNegative: allValuesAreNegative,
56541 percentBarLabelSettings: percentBarLabelSettings,
56542 };
56543 // Calculate the first value for percent tooltip values
56544 firstValue = firstValueColumn.values[0];
56545 if (hasHighlights) {
56546 firstHighlight = firstValueColumn.highlights[0];
56547 }
56548 var pctFormatString = visuals.valueFormatter.getLocalizedString('Percentage');
56549 if (categories.length === 1) {
56550 // Single Category, Value and (optional) Gradient
56551 var category = categories[0];
56552 var categoryValues = category.values;
56553 for (var i = 0, ilen = categoryValues.length; i < ilen; i++) {
56554 var measureName = firstValueColumn.source.queryName;
56555 var identity = visuals.SelectionIdBuilder.builder()
56556 .withCategory(category, i)
56557 .withMeasure(measureName)
56558 .createSelectionId();
56559 var value = firstValueColumn.values[i];
56560 var formattedCategoryValue = visuals.converterHelper.formatFromMetadataColumn(categoryValues[i], category.source, formatStringProp);
56561 var tooltipInfo = void 0;
56562 if (tooltipsEnabled) {
56563 tooltipInfo = [];
56564 tooltipInfo.push({
56565 displayName: category.source.displayName,
56566 value: formattedCategoryValue,
56567 });
56568 if (value != null) {
56569 tooltipInfo.push({
56570 displayName: firstValueColumn.source.displayName,
56571 value: visuals.converterHelper.formatFromMetadataColumn(value, firstValueColumn.source, formatStringProp),
56572 });
56573 }
56574 var highlightValue = void 0;
56575 if (hasHighlights) {
56576 highlightValue = firstValueColumn.highlights[i];
56577 if (highlightValue != null) {
56578 tooltipInfo.push({
56579 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
56580 value: visuals.converterHelper.formatFromMetadataColumn(highlightValue, firstValueColumn.source, formatStringProp),
56581 });
56582 }
56583 }
56584 var gradientColumnMetadata = gradientValueColumn ? gradientValueColumn.source : undefined;
56585 if (gradientColumnMetadata && gradientColumnMetadata !== firstValueColumn.source && gradientValueColumn.values[i] != null) {
56586 tooltipInfo.push({
56587 displayName: gradientColumnMetadata.displayName,
56588 value: visuals.converterHelper.formatFromMetadataColumn(gradientValueColumn.values[i], gradientColumnMetadata, formatStringProp),
56589 });
56590 }
56591 if (hasHighlights) {
56592 FunnelChart.addFunnelPercentsToTooltip(pctFormatString, tooltipInfo, hostServices, firstHighlight ? highlightValue / firstHighlight : null, previousHighlight ? highlightValue / previousHighlight : null, true);
56593 }
56594 else {
56595 FunnelChart.addFunnelPercentsToTooltip(pctFormatString, tooltipInfo, hostServices, firstValue ? value / firstValue : null, previousValue ? value / previousValue : null);
56596 }
56597 }
56598 // Same color for all bars
56599 var color = colorHelper.getColorForMeasure(category.objects && category.objects[i], '');
56600 slices.push({
56601 label: formattedCategoryValue,
56602 value: value,
56603 originalValue: value,
56604 categoryOrMeasureIndex: i,
56605 identity: identity,
56606 selected: false,
56607 key: identity.getKey(),
56608 tooltipInfo: tooltipInfo,
56609 color: color,
56610 labelFill: dataLabelsSettings.labelColor,
56611 });
56612 if (hasHighlights) {
56613 var highlightIdentity = visuals.SelectionId.createWithHighlight(identity);
56614 var highlightValue = firstValueColumn.highlights[i];
56615 slices.push({
56616 label: formattedCategoryValue,
56617 value: value,
56618 originalValue: value,
56619 categoryOrMeasureIndex: i,
56620 identity: highlightIdentity,
56621 selected: false,
56622 key: highlightIdentity.getKey(),
56623 highlight: true,
56624 highlightValue: highlightValue,
56625 originalHighlightValue: highlightValue,
56626 tooltipInfo: tooltipInfo,
56627 color: color,
56628 });
56629 previousHighlight = highlightValue;
56630 }
56631 previousValue = value;
56632 }
56633 }
56634 else if (valueMetaData.length > 0 && values && values.length > 0) {
56635 // Multi-measures
56636 for (var i = 0, len = values.length; i < len; i++) {
56637 var valueColumn = values[i];
56638 if (!FunnelChart.isValidValueColumn(valueColumn))
56639 continue;
56640 var value = valueColumn.values[0];
56641 var identity = visuals.SelectionId.createWithMeasure(valueColumn.source.queryName);
56642 var tooltipInfo = void 0;
56643 // Same color for all bars
56644 var color = colorHelper.getColorForMeasure(valueColumn.source.objects, '');
56645 if (tooltipsEnabled) {
56646 tooltipInfo = [];
56647 if (value != null) {
56648 tooltipInfo.push({
56649 displayName: valueColumn.source.displayName,
56650 value: visuals.converterHelper.formatFromMetadataColumn(value, valueColumn.source, formatStringProp),
56651 });
56652 }
56653 if (hasHighlights) {
56654 var highlightValue = valueColumn.highlights[0];
56655 if (highlightValue != null) {
56656 tooltipInfo.push({
56657 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
56658 value: visuals.converterHelper.formatFromMetadataColumn(highlightValue, valueColumn.source, formatStringProp),
56659 });
56660 }
56661 FunnelChart.addFunnelPercentsToTooltip(pctFormatString, tooltipInfo, hostServices, firstHighlight ? highlightValue / firstHighlight : null, previousHighlight ? highlightValue / previousHighlight : null, true);
56662 }
56663 else {
56664 FunnelChart.addFunnelPercentsToTooltip(pctFormatString, tooltipInfo, hostServices, firstValue ? value / firstValue : null, previousValue ? value / previousValue : null);
56665 }
56666 }
56667 slices.push({
56668 label: valueMetaData[i].displayName,
56669 value: value,
56670 originalValue: value,
56671 categoryOrMeasureIndex: i,
56672 identity: identity,
56673 selected: false,
56674 key: identity.getKey(),
56675 tooltipInfo: tooltipInfo,
56676 color: color,
56677 labelFill: dataLabelsSettings.labelColor,
56678 });
56679 if (hasHighlights) {
56680 var highlightIdentity = visuals.SelectionId.createWithHighlight(identity);
56681 var highlight = valueColumn.highlights[0];
56682 slices.push({
56683 label: valueMetaData[i].displayName,
56684 value: value,
56685 originalValue: value,
56686 categoryOrMeasureIndex: i,
56687 identity: highlightIdentity,
56688 key: highlightIdentity.getKey(),
56689 selected: false,
56690 highlight: true,
56691 originalHighlightValue: highlight,
56692 highlightValue: highlight,
56693 tooltipInfo: tooltipInfo,
56694 color: color,
56695 });
56696 previousHighlight = highlight;
56697 }
56698 previousValue = value;
56699 }
56700 }
56701 for (var i = 0; i < slices.length; i += hasHighlights ? 2 : 1) {
56702 var slice = slices[i];
56703 categoryLabels.push(slice.label);
56704 }
56705 // Calculate negative value warning flags
56706 allValuesAreNegative = slices.length > 0 && _.every(slices, function (slice) { return (slice.highlight ? slice.highlightValue <= 0 : true) && slice.value < 0; });
56707 for (var _i = 0, slices_1 = slices; _i < slices_1.length; _i++) {
56708 var slice = slices_1[_i];
56709 if (allValuesAreNegative) {
56710 slice.value = Math.abs(slice.value);
56711 if (slice.highlight)
56712 slice.highlightValue = Math.abs(slice.highlightValue);
56713 }
56714 else {
56715 var value = slice.value;
56716 var isValueNegative = value < 0;
56717 if (isValueNegative)
56718 slice.value = 0;
56719 var isHighlightValueNegative = false;
56720 if (slice.highlight) {
56721 var highlightValue = slice.highlightValue;
56722 isHighlightValueNegative = highlightValue < 0;
56723 slice.highlightValue = isHighlightValueNegative ? 0 : highlightValue;
56724 }
56725 if (!hasNegativeValues)
56726 hasNegativeValues = isValueNegative || isHighlightValueNegative;
56727 }
56728 if (slice.highlightValue > slice.value) {
56729 highlightsOverflow = true;
56730 }
56731 }
56732 return {
56733 slices: slices,
56734 categoryLabels: categoryLabels,
56735 valuesMetadata: valueMetaData,
56736 hasHighlights: hasHighlights,
56737 highlightsOverflow: highlightsOverflow,
56738 canShowDataLabels: true,
56739 dataLabelsSettings: dataLabelsSettings,
56740 hasNegativeValues: hasNegativeValues,
56741 allValuesAreNegative: allValuesAreNegative,
56742 percentBarLabelSettings: percentBarLabelSettings,
56743 };
56744 };
56745 FunnelChart.prototype.enumerateObjectInstances = function (options) {
56746 var enumeration = new visuals.ObjectEnumerationBuilder();
56747 switch (options.objectName) {
56748 case 'dataPoint':
56749 var dataViewCat = this.dataViews && this.dataViews.length > 0 && this.dataViews[0] && this.dataViews[0].categorical;
56750 var hasGradientRole = visuals.GradientUtils.hasGradientRole(dataViewCat);
56751 if (!hasGradientRole) {
56752 this.enumerateDataPoints(enumeration);
56753 }
56754 break;
56755 case 'labels':
56756 var labelSettingsOptions = FunnelChart.getLabelSettingsOptions(enumeration, this.data.dataLabelsSettings, true, this.labelPositionObjects);
56757 visuals.dataLabelUtils.enumerateDataLabels(labelSettingsOptions);
56758 break;
56759 case 'percentBarLabel':
56760 var percentLabelSettingOptions = FunnelChart.getLabelSettingsOptions(enumeration, this.data.percentBarLabelSettings, false);
56761 visuals.dataLabelUtils.enumerateDataLabels(percentLabelSettingOptions);
56762 break;
56763 }
56764 return enumeration.complete();
56765 };
56766 FunnelChart.getLabelSettingsOptions = function (enumeration, labelSettings, isDataLabels, positionObject) {
56767 return {
56768 enumeration: enumeration,
56769 dataLabelsSettings: labelSettings,
56770 show: true,
56771 displayUnits: isDataLabels,
56772 precision: isDataLabels,
56773 position: isDataLabels,
56774 positionObject: positionObject,
56775 fontSize: true,
56776 };
56777 };
56778 FunnelChart.prototype.enumerateDataPoints = function (enumeration) {
56779 var data = this.data;
56780 if (!data)
56781 return;
56782 var slices = data.slices;
56783 enumeration.pushInstance({
56784 objectName: 'dataPoint',
56785 selector: null,
56786 properties: {
56787 defaultColor: { solid: { color: this.defaultDataPointColor || this.colors.getColorByIndex(0).value } }
56788 },
56789 });
56790 for (var i = 0; i < slices.length; i++) {
56791 var slice = slices[i];
56792 if (slice.highlight)
56793 continue;
56794 var color = slice.color;
56795 var selector = slice.identity.getSelector();
56796 var isSingleSeries = !!selector.data;
56797 enumeration.pushInstance({
56798 objectName: 'dataPoint',
56799 displayName: slice.label,
56800 selector: visuals.ColorHelper.normalizeSelector(selector, isSingleSeries),
56801 properties: {
56802 fill: { solid: { color: color } }
56803 },
56804 });
56805 }
56806 };
56807 FunnelChart.prototype.init = function (options) {
56808 this.options = options;
56809 var element = options.element;
56810 var svg = this.svg = d3.select(element.get(0))
56811 .append('svg')
56812 .classed(FunnelChart.VisualClassName, true);
56813 if (this.behavior)
56814 this.clearCatcher = visuals.appendClearCatcher(this.svg);
56815 this.currentViewport = options.viewport;
56816 this.margin = {
56817 left: 5,
56818 right: 5,
56819 top: 0,
56820 bottom: 0
56821 };
56822 var style = options.style;
56823 this.colors = style.colorPalette.dataColors;
56824 this.hostServices = options.host;
56825 if (this.behavior) {
56826 this.interactivityService = visuals.createInteractivityService(this.hostServices);
56827 }
56828 this.percentGraphicsContext = svg.append('g').classed(FunnelChart.Selectors.percentBar.root.class, true);
56829 this.funnelGraphicsContext = svg.append('g');
56830 this.axisGraphicsContext = svg.append('g');
56831 this.updateViewportProperties();
56832 };
56833 FunnelChart.prototype.updateViewportProperties = function () {
56834 var viewport = this.currentViewport;
56835 this.svg.attr('width', viewport.width)
56836 .attr('height', viewport.height);
56837 };
56838 FunnelChart.prototype.update = function (options) {
56839 debug.assertValue(options, 'options');
56840 this.data = {
56841 slices: [],
56842 categoryLabels: [],
56843 valuesMetadata: [],
56844 hasHighlights: false,
56845 highlightsOverflow: false,
56846 canShowDataLabels: true,
56847 dataLabelsSettings: visuals.dataLabelUtils.getDefaultFunnelLabelSettings(),
56848 hasNegativeValues: false,
56849 allValuesAreNegative: false,
56850 percentBarLabelSettings: visuals.dataLabelUtils.getDefaultLabelSettings(true),
56851 };
56852 var dataViews = this.dataViews = options.dataViews;
56853 this.currentViewport = options.viewport;
56854 if (dataViews && dataViews.length > 0) {
56855 var dataView = dataViews[0];
56856 if (dataView.metadata && dataView.metadata.objects) {
56857 var defaultColor = powerbi.DataViewObjects.getFillColor(dataView.metadata.objects, visuals.funnelChartProps.dataPoint.defaultColor);
56858 if (defaultColor)
56859 this.defaultDataPointColor = defaultColor;
56860 }
56861 if (dataView.categorical) {
56862 this.data = FunnelChart.converter(dataView, this.colors, this.hostServices, this.defaultDataPointColor, this.tooltipsEnabled);
56863 if (this.interactivityService) {
56864 this.interactivityService.applySelectionStateToData(this.data.slices);
56865 }
56866 }
56867 var warnings = visuals.getInvalidValueWarnings(dataViews, false /*supportsNaN*/, false /*supportsNegativeInfinity*/, false /*supportsPositiveInfinity*/);
56868 if (this.data.allValuesAreNegative) {
56869 warnings.unshift(new visuals.AllNegativeValuesWarning());
56870 }
56871 else if (this.data.hasNegativeValues) {
56872 warnings.unshift(new visuals.NegativeValuesNotSupportedWarning());
56873 }
56874 this.hostServices.setWarnings(warnings);
56875 }
56876 this.updateViewportProperties();
56877 this.updateInternal(options.suppressAnimations);
56878 };
56879 // TODO: Remove onDataChanged & onResizing once all visuals have implemented update.
56880 FunnelChart.prototype.onDataChanged = function (options) {
56881 this.update({
56882 dataViews: options.dataViews,
56883 suppressAnimations: options.suppressAnimations,
56884 viewport: this.currentViewport
56885 });
56886 };
56887 // TODO: Remove onDataChanged & onResizing once all visuals have implemented update.
56888 FunnelChart.prototype.onResizing = function (viewport) {
56889 this.currentViewport = viewport;
56890 this.update({
56891 dataViews: this.dataViews,
56892 suppressAnimations: true,
56893 viewport: this.currentViewport
56894 });
56895 };
56896 FunnelChart.prototype.getMaxLabelLength = function (labels, properties) {
56897 var max = 0;
56898 var textMeasurer = powerbi.TextMeasurementService.measureSvgTextWidth;
56899 for (var i = 0, len = labels.length; i < len; i++) {
56900 properties.text = labels[i];
56901 max = Math.max(max, textMeasurer(properties));
56902 }
56903 return max + FunnelChart.LabelFunnelPadding;
56904 };
56905 FunnelChart.prototype.updateInternal = function (suppressAnimations) {
56906 if (this.data == null)
56907 return;
56908 var data = this.data;
56909 var slices = data.slices;
56910 var slicesWithoutHighlights = slices.filter(function (d) { return !d.highlight; });
56911 var isHidingPercentBars = this.isHidingPercentBars();
56912 var axisOptions = this.setUpAxis();
56913 var margin = axisOptions.margin;
56914 var funnelContext = this.funnelGraphicsContext.attr('transform', visuals.SVGUtil.translate(margin.left, margin.top));
56915 this.percentGraphicsContext.attr('transform', visuals.SVGUtil.translate(margin.left, margin.top));
56916 this.svg.style('font-family', visuals.dataLabelUtils.StandardFontFamily);
56917 var layout = FunnelChart.getLayout(data, axisOptions);
56918 var labelLayout = visuals.dataLabelUtils.getFunnelChartLabelLayout(data, axisOptions, FunnelChart.InnerTextMinimumPadding, data.dataLabelsSettings, this.currentViewport);
56919 var result;
56920 var shapes;
56921 var dataLabels;
56922 if (this.animator && !suppressAnimations) {
56923 var animationOptions = {
56924 viewModel: data,
56925 interactivityService: this.interactivityService,
56926 layout: layout,
56927 axisGraphicsContext: this.axisGraphicsContext,
56928 shapeGraphicsContext: funnelContext,
56929 percentGraphicsContext: this.percentGraphicsContext,
56930 labelGraphicsContext: this.svg,
56931 axisOptions: axisOptions,
56932 slicesWithoutHighlights: slicesWithoutHighlights,
56933 labelLayout: labelLayout,
56934 isHidingPercentBars: isHidingPercentBars,
56935 visualInitOptions: this.options,
56936 };
56937 result = this.animator.animate(animationOptions);
56938 shapes = result.shapes;
56939 dataLabels = result.dataLabels;
56940 }
56941 if (!this.animator || suppressAnimations || result.failed) {
56942 FunnelChart.drawDefaultAxis(this.axisGraphicsContext, axisOptions, isHidingPercentBars);
56943 shapes = FunnelChart.drawDefaultShapes(data, slices, funnelContext, layout, this.interactivityService && this.interactivityService.hasSelection());
56944 FunnelChart.drawPercentBars(data, this.percentGraphicsContext, layout, isHidingPercentBars);
56945 if (data.dataLabelsSettings.show && data.canShowDataLabels) {
56946 dataLabels = visuals.dataLabelUtils.drawDefaultLabelsForFunnelChart(data.slices, this.svg, labelLayout);
56947 }
56948 else {
56949 visuals.dataLabelUtils.cleanDataLabels(this.svg);
56950 }
56951 }
56952 if (this.interactivityService) {
56953 var interactors = FunnelChart.drawInteractorShapes(slices, funnelContext, layout);
56954 var behaviorOptions = {
56955 bars: shapes,
56956 interactors: interactors,
56957 clearCatcher: this.clearCatcher,
56958 hasHighlights: data.hasHighlights,
56959 };
56960 this.interactivityService.bind(slices, this.behavior, behaviorOptions);
56961 if (this.tooltipsEnabled) {
56962 visuals.TooltipManager.addTooltip(interactors, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
56963 }
56964 }
56965 if (this.tooltipsEnabled) {
56966 visuals.TooltipManager.addTooltip(shapes, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
56967 }
56968 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
56969 };
56970 FunnelChart.prototype.getUsableVerticalSpace = function () {
56971 var categoryLabels = this.data.categoryLabels;
56972 var margin = this.margin;
56973 var verticalSpace = this.currentViewport.height - (margin.top + margin.bottom);
56974 return verticalSpace - (FunnelChart.MinBarThickness * categoryLabels.length);
56975 };
56976 FunnelChart.prototype.isHidingPercentBars = function () {
56977 var data = this.data;
56978 if (data.percentBarLabelSettings.show) {
56979 var percentBarTextHeight = this.getPercentBarTextHeight();
56980 var verticalSpace = this.getUsableVerticalSpace() - (2 * FunnelChart.MinBarThickness * FunnelChart.PercentBarToBarRatio) - (2 * percentBarTextHeight);
56981 return verticalSpace <= 0;
56982 }
56983 return true;
56984 };
56985 FunnelChart.prototype.isSparklines = function () {
56986 return this.getUsableVerticalSpace() <= 0;
56987 };
56988 FunnelChart.prototype.setUpAxis = function () {
56989 var data = this.data;
56990 var slices = data.slices;
56991 var categoryLabels = data.categoryLabels;
56992 var viewport = this.currentViewport;
56993 var margin = this.margin;
56994 var isSparklines = this.isSparklines();
56995 var isHidingPercentBars = this.isHidingPercentBars();
56996 var percentBarTextHeight = isHidingPercentBars ? 0 : this.getPercentBarTextHeight();
56997 var verticalRange = viewport.height - (margin.top + margin.bottom) - (2 * percentBarTextHeight);
56998 var maxMarginFactor = FunnelChart.MaxMarginFactor;
56999 if (categoryLabels.length > 0 && isSparklines) {
57000 categoryLabels = [];
57001 data.canShowDataLabels = false;
57002 }
57003 else if (this.showCategoryLabels()) {
57004 var textProperties = FunnelChart.getTextProperties();
57005 // Get the amount of space needed for the labels, then add the minimum level of padding for the axis.
57006 var longestLabelLength = this.getMaxLabelLength(categoryLabels, textProperties);
57007 var maxLabelLength = viewport.width * maxMarginFactor;
57008 var labelLength = Math.min(longestLabelLength, maxLabelLength);
57009 margin.left = labelLength + FunnelChart.YAxisPadding;
57010 }
57011 else {
57012 categoryLabels = [];
57013 }
57014 var horizontalRange = viewport.width - (margin.left + margin.right);
57015 var barToSpaceRatio = FunnelChart.BarToSpaceRatio;
57016 var maxScore = d3.max(slices.map(function (d) { return d.value; }));
57017 if (data.hasHighlights) {
57018 var maxHighlight = d3.max(slices.map(function (d) { return d.highlightValue; }));
57019 maxScore = d3.max([maxScore, maxHighlight]);
57020 }
57021 var minScore = 0;
57022 var rangeStart = 0;
57023 var rangeEnd = verticalRange;
57024 var delta;
57025 if (isHidingPercentBars)
57026 delta = verticalRange - (categoryLabels.length * FunnelChart.MaxBarHeight);
57027 else
57028 delta = verticalRange - (categoryLabels.length * FunnelChart.MaxBarHeight) - (2 * FunnelChart.MaxBarHeight * FunnelChart.PercentBarToBarRatio);
57029 if (categoryLabels.length > 0 && delta > 0) {
57030 rangeStart = Math.ceil(delta / 2);
57031 rangeEnd = Math.ceil(verticalRange - delta / 2);
57032 }
57033 // Offset funnel axis start and end by percent bar text height
57034 if (!isHidingPercentBars) {
57035 rangeStart += percentBarTextHeight;
57036 rangeEnd += percentBarTextHeight;
57037 }
57038 var valueScale = d3.scale.linear()
57039 .domain([minScore, maxScore])
57040 .range([horizontalRange, 0]);
57041 var categoryScale = d3.scale.ordinal()
57042 .domain(d3.range(0, data.categoryLabels.length))
57043 .rangeBands([rangeStart, rangeEnd], barToSpaceRatio, isHidingPercentBars ? barToSpaceRatio : FunnelChart.PercentBarToBarRatio);
57044 return {
57045 margin: margin,
57046 valueScale: valueScale,
57047 categoryScale: categoryScale,
57048 maxScore: maxScore,
57049 maxWidth: horizontalRange,
57050 rangeStart: rangeStart,
57051 rangeEnd: rangeEnd,
57052 barToSpaceRatio: barToSpaceRatio,
57053 categoryLabels: categoryLabels,
57054 };
57055 };
57056 FunnelChart.prototype.getPercentBarTextHeight = function () {
57057 var percentBarTextProperties = FunnelChart.getTextProperties(this.data.percentBarLabelSettings.fontSize);
57058 return powerbi.TextMeasurementService.estimateSvgTextHeight(percentBarTextProperties);
57059 };
57060 FunnelChart.prototype.onClearSelection = function () {
57061 if (this.interactivityService)
57062 this.interactivityService.clearSelection();
57063 };
57064 FunnelChart.getLayout = function (data, axisOptions) {
57065 var highlightsOverflow = data.highlightsOverflow;
57066 var categoryScale = axisOptions.categoryScale;
57067 var valueScale = axisOptions.valueScale;
57068 var maxScore = axisOptions.maxScore;
57069 var columnHeight = categoryScale.rangeBand();
57070 var percentBarTickHeight = Math.ceil(columnHeight / 2);
57071 var overFlowHighlightColumnWidth = columnHeight * FunnelChart.OverflowingHighlightWidthRatio;
57072 var overFlowHighlightOffset = overFlowHighlightColumnWidth / 2;
57073 var lastCategoryIndex = axisOptions.categoryLabels.length - 1;
57074 var horizontalDistance = Math.abs(valueScale(maxScore) - valueScale(0));
57075 var emptyHorizontalSpace = function (value) { return (horizontalDistance - Math.abs(valueScale(value) - valueScale(0))) / 2; };
57076 var getMinimumShapeSize = function (value) { return Math.max(FunnelChart.MinimumInteractorSize, Math.abs(valueScale(value) - valueScale(0))); };
57077 var percentBarFontSize = PixelConverter.fromPoint(data.percentBarLabelSettings.fontSize);
57078 var percentBarTextProperties = FunnelChart.getTextProperties(data.percentBarLabelSettings.fontSize);
57079 var baselineDelta = powerbi.TextMeasurementService.estimateSvgTextBaselineDelta(percentBarTextProperties);
57080 var percentBarYOffset = powerbi.TextMeasurementService.estimateSvgTextHeight(percentBarTextProperties) - baselineDelta;
57081 return {
57082 percentBarLayout: {
57083 mainLine: {
57084 x2: function (d) { return Math.abs(valueScale(d.value) - valueScale(0)); },
57085 transform: function (d) {
57086 var xOffset = valueScale(d.value) - emptyHorizontalSpace(d.value);
57087 var yOffset = d.isTop
57088 ? categoryScale(0) - percentBarTickHeight
57089 : categoryScale(lastCategoryIndex) + columnHeight + percentBarTickHeight;
57090 return visuals.SVGUtil.translate(xOffset, yOffset);
57091 },
57092 },
57093 leftTick: {
57094 y2: function (d) { return percentBarTickHeight; },
57095 transform: function (d) {
57096 var xOffset = valueScale(d.value) - emptyHorizontalSpace(d.value);
57097 var yOffset = d.isTop
57098 ? categoryScale(0) - percentBarTickHeight - (percentBarTickHeight / 2)
57099 : categoryScale(lastCategoryIndex) + columnHeight + percentBarTickHeight - (percentBarTickHeight / 2);
57100 return visuals.SVGUtil.translate(xOffset, yOffset);
57101 },
57102 },
57103 rightTick: {
57104 y2: function (d) { return percentBarTickHeight; },
57105 transform: function (d) {
57106 var columnOffset = valueScale(d.value) - emptyHorizontalSpace(d.value);
57107 var columnWidth = Math.abs(valueScale(d.value) - valueScale(0));
57108 var xOffset = columnOffset + columnWidth;
57109 var yOffset = d.isTop
57110 ? categoryScale(0) - percentBarTickHeight - (percentBarTickHeight / 2)
57111 : categoryScale(lastCategoryIndex) + columnHeight + percentBarTickHeight - (percentBarTickHeight / 2);
57112 return visuals.SVGUtil.translate(xOffset, yOffset);
57113 },
57114 },
57115 text: {
57116 x: function (d) { return Math.ceil((Math.abs(valueScale(maxScore) - valueScale(0)) / 2)); },
57117 y: function (d) {
57118 return d.isTop
57119 ? -percentBarTickHeight / 2 - baselineDelta
57120 : percentBarYOffset + (percentBarTickHeight / 2);
57121 },
57122 style: function () { return ("font-size: " + percentBarFontSize + ";"); },
57123 transform: function (d) {
57124 var xOffset = d.isTop
57125 ? categoryScale(0) - percentBarTickHeight
57126 : categoryScale(lastCategoryIndex) + columnHeight + percentBarTickHeight;
57127 return visuals.SVGUtil.translate(0, xOffset);
57128 },
57129 fill: data.percentBarLabelSettings.labelColor,
57130 maxWidth: horizontalDistance,
57131 },
57132 },
57133 shapeLayout: {
57134 height: (function (d) { return d.highlight && highlightsOverflow ? overFlowHighlightColumnWidth : columnHeight; }),
57135 width: function (d) {
57136 return Math.abs(valueScale(FunnelChart.getFunnelSliceValue(d)) - valueScale(0));
57137 },
57138 y: function (d) {
57139 return categoryScale(d.categoryOrMeasureIndex) + (d.highlight && highlightsOverflow ? overFlowHighlightOffset : 0);
57140 },
57141 x: function (d) {
57142 var value = FunnelChart.getFunnelSliceValue(d);
57143 return valueScale(value) - emptyHorizontalSpace(value);
57144 },
57145 },
57146 shapeLayoutWithoutHighlights: {
57147 height: (function (d) { return columnHeight; }),
57148 width: function (d) {
57149 return Math.abs(valueScale(d.value) - valueScale(0));
57150 },
57151 y: function (d) {
57152 return categoryScale(d.categoryOrMeasureIndex) + (0);
57153 },
57154 x: function (d) {
57155 return valueScale(d.value) - emptyHorizontalSpace(d.value);
57156 },
57157 },
57158 zeroShapeLayout: {
57159 height: (function (d) { return d.highlight && highlightsOverflow ? overFlowHighlightColumnWidth : columnHeight; }),
57160 width: function (d) { return 0; },
57161 y: function (d) {
57162 return categoryScale(d.categoryOrMeasureIndex) + (d.highlight && highlightsOverflow ? overFlowHighlightOffset : 0);
57163 },
57164 x: function (d) {
57165 return valueScale((valueScale.domain()[0] + valueScale.domain()[1]) / 2);
57166 },
57167 },
57168 interactorLayout: {
57169 height: (function (d) { return d.highlight && highlightsOverflow ? overFlowHighlightColumnWidth : columnHeight; }),
57170 width: function (d) { return getMinimumShapeSize(FunnelChart.getFunnelSliceValue(d)); },
57171 y: function (d) {
57172 return categoryScale(d.categoryOrMeasureIndex) + (d.highlight && highlightsOverflow ? overFlowHighlightOffset : 0);
57173 },
57174 x: function (d) {
57175 var size = getMinimumShapeSize(FunnelChart.getFunnelSliceValue(d));
57176 return (horizontalDistance - size) / 2;
57177 },
57178 },
57179 };
57180 };
57181 FunnelChart.drawDefaultAxis = function (graphicsContext, axisOptions, isHidingPercentBars) {
57182 //Generate ordinal domain
57183 var indices = d3.range(0, axisOptions.categoryLabels.length);
57184 var xScaleForAxis = d3.scale.ordinal()
57185 .domain(indices)
57186 .rangeBands([axisOptions.rangeStart, axisOptions.rangeEnd], axisOptions.barToSpaceRatio, isHidingPercentBars ? axisOptions.barToSpaceRatio : FunnelChart.PercentBarToBarRatio);
57187 var xAxis = d3.svg.axis()
57188 .scale(xScaleForAxis)
57189 .orient("right")
57190 .tickPadding(FunnelChart.TickPadding)
57191 .innerTickSize(FunnelChart.InnerTickSize)
57192 .ticks(indices.length)
57193 .tickValues(indices)
57194 .tickFormat(function (i) { return axisOptions.categoryLabels[i]; }); //To output the category label
57195 graphicsContext.attr('class', 'axis hideLinesOnAxis')
57196 .attr('transform', visuals.SVGUtil.translate(0, axisOptions.margin.top))
57197 .call(xAxis);
57198 graphicsContext.selectAll('.tick')
57199 .call(visuals.tooltipUtils.tooltipUpdate, axisOptions.categoryLabels);
57200 // Subtract the padding from the margin since we can't have text there. Then shorten the labels if necessary.
57201 var leftRightMarginLimit = axisOptions.margin.left - FunnelChart.LabelFunnelPadding;
57202 graphicsContext.selectAll('.tick text')
57203 .call(visuals.AxisHelper.LabelLayoutStrategy.clip, leftRightMarginLimit, powerbi.TextMeasurementService.svgEllipsis);
57204 };
57205 FunnelChart.drawDefaultShapes = function (data, slices, graphicsContext, layout, hasSelection) {
57206 var hasHighlights = data.hasHighlights;
57207 var columns = graphicsContext.selectAll(FunnelChart.Selectors.funnel.bars.selector).data(slices, function (d) { return d.key; });
57208 columns.enter()
57209 .append('rect')
57210 .attr("class", function (d) { return d.highlight ? FunnelChart.FunnelBarHighlightClass : FunnelChart.Selectors.funnel.bars.class; });
57211 columns
57212 .style("fill", function (d) {
57213 return d.color;
57214 })
57215 .style("fill-opacity", function (d) { return function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, hasHighlights); }; })
57216 .attr(layout.shapeLayout);
57217 columns.exit().remove();
57218 return columns;
57219 };
57220 FunnelChart.getFunnelSliceValue = function (slice, asOriginal) {
57221 if (asOriginal === void 0) { asOriginal = false; }
57222 if (asOriginal)
57223 return slice.highlight ? slice.originalHighlightValue : slice.originalValue;
57224 else
57225 return slice.highlight ? slice.highlightValue : slice.value;
57226 };
57227 FunnelChart.drawInteractorShapes = function (slices, graphicsContext, layout) {
57228 // Draw invsible ineractors for just data points which are below threshold
57229 var interactorsData = slices.filter(function (d) {
57230 return !d.highlight && layout.interactorLayout.width(d) === FunnelChart.MinimumInteractorSize;
57231 });
57232 var columns = graphicsContext.selectAll(FunnelChart.Selectors.funnel.interactors.selector).data(interactorsData, function (d) { return d.key; });
57233 columns.enter()
57234 .append('rect')
57235 .attr("class", FunnelChart.Selectors.funnel.interactors.class);
57236 columns
57237 .style("fill-opacity", 0)
57238 .attr(layout.interactorLayout);
57239 columns.exit().remove();
57240 return columns;
57241 };
57242 FunnelChart.drawPercentBarComponents = function (graphicsContext, data, layout, percentLabelSettings) {
57243 // Main line
57244 var mainLine = graphicsContext.selectAll(FunnelChart.Selectors.percentBar.mainLine.selector).data(data);
57245 mainLine.exit().remove();
57246 mainLine.enter()
57247 .append('line')
57248 .classed(FunnelChart.Selectors.percentBar.mainLine.class, true);
57249 mainLine
57250 .attr(layout.percentBarLayout.mainLine);
57251 // Left tick
57252 var leftTick = graphicsContext.selectAll(FunnelChart.Selectors.percentBar.leftTick.selector).data(data);
57253 leftTick.exit().remove();
57254 leftTick.enter()
57255 .append('line')
57256 .classed(FunnelChart.Selectors.percentBar.leftTick.class, true);
57257 leftTick
57258 .attr(layout.percentBarLayout.leftTick);
57259 // Right tick
57260 var rightTick = graphicsContext.selectAll(FunnelChart.Selectors.percentBar.rightTick.selector).data(data);
57261 rightTick.exit().remove();
57262 rightTick.enter()
57263 .append('line')
57264 .classed(FunnelChart.Selectors.percentBar.rightTick.class, true);
57265 rightTick
57266 .attr(layout.percentBarLayout.rightTick);
57267 // Text
57268 var text = graphicsContext.selectAll(FunnelChart.Selectors.percentBar.text.selector).data(data);
57269 var localizedString = visuals.valueFormatter.getLocalizedString("Percentage1");
57270 text.exit().remove();
57271 text.enter().append('text').classed(FunnelChart.Selectors.percentBar.text.class, true);
57272 text
57273 .attr(layout.percentBarLayout.text)
57274 .text(function (fp) {
57275 return visuals.dataLabelUtils.getLabelFormattedText({
57276 label: fp.percent,
57277 format: localizedString,
57278 fontSize: percentLabelSettings.fontSize,
57279 maxWidth: layout.percentBarLayout.text.maxWidth,
57280 });
57281 })
57282 .append('title').text(function (d) { return powerbi.formattingService.formatValue(d.percent, localizedString); });
57283 };
57284 FunnelChart.drawPercentBars = function (data, graphicsContext, layout, isHidingPercentBars) {
57285 if (isHidingPercentBars || !data.slices || (data.hasHighlights ? data.slices.length / 2 : data.slices.length) < 2) {
57286 FunnelChart.drawPercentBarComponents(graphicsContext, [], layout, data.percentBarLabelSettings);
57287 return;
57288 }
57289 var slices = [data.slices[data.hasHighlights ? 1 : 0], data.slices[data.slices.length - 1]];
57290 var baseline = FunnelChart.getFunnelSliceValue(slices[0]);
57291 if (baseline <= 0) {
57292 FunnelChart.drawPercentBarComponents(graphicsContext, [], layout, data.percentBarLabelSettings);
57293 return;
57294 }
57295 var percentData = [
57296 {
57297 value: FunnelChart.getFunnelSliceValue(slices[0]),
57298 percent: 1,
57299 isTop: true,
57300 },
57301 {
57302 value: FunnelChart.getFunnelSliceValue(slices[1]),
57303 percent: FunnelChart.getFunnelSliceValue(slices[1]) / baseline,
57304 isTop: false,
57305 },
57306 ];
57307 FunnelChart.drawPercentBarComponents(graphicsContext, percentData, layout, data.percentBarLabelSettings);
57308 };
57309 FunnelChart.prototype.showCategoryLabels = function () {
57310 if (this.funnelSmallViewPortProperties) {
57311 if ((this.funnelSmallViewPortProperties.hideFunnelCategoryLabelsOnSmallViewPort) && (this.currentViewport.height < this.funnelSmallViewPortProperties.minHeightFunnelCategoryLabelsVisible)) {
57312 return false;
57313 }
57314 }
57315 return true;
57316 };
57317 FunnelChart.addFunnelPercentsToTooltip = function (pctFormatString, tooltipInfo, hostServices, percentOfFirst, percentOfPrevious, highlight) {
57318 if (percentOfFirst != null) {
57319 tooltipInfo.push({
57320 displayName: hostServices.getLocalizedString("Funnel_PercentOfFirst" + (highlight ? "_Highlight" : "")),
57321 value: visuals.valueFormatter.format(percentOfFirst, pctFormatString),
57322 });
57323 }
57324 if (percentOfPrevious != null) {
57325 tooltipInfo.push({
57326 displayName: hostServices.getLocalizedString("Funnel_PercentOfPrevious" + (highlight ? "_Highlight" : "")),
57327 value: visuals.valueFormatter.format(percentOfPrevious, pctFormatString),
57328 });
57329 }
57330 };
57331 FunnelChart.getTextProperties = function (fontSize) {
57332 return {
57333 fontSize: PixelConverter.fromPoint(fontSize || visuals.dataLabelUtils.DefaultFontSizeInPt),
57334 fontFamily: FunnelChart.DefaultFontFamily,
57335 };
57336 };
57337 FunnelChart.DefaultBarOpacity = 1;
57338 FunnelChart.DimmedBarOpacity = 0.4;
57339 FunnelChart.PercentBarToBarRatio = 0.75;
57340 FunnelChart.TickPadding = 0;
57341 FunnelChart.InnerTickSize = 0;
57342 FunnelChart.MinimumInteractorSize = 15;
57343 FunnelChart.InnerTextClassName = 'labelSeries';
57344 FunnelChart.Selectors = {
57345 funnel: {
57346 bars: createClassAndSelector('funnelBar'),
57347 highlights: createClassAndSelector('highlight'),
57348 interactors: createClassAndSelector('funnelBarInteractor'),
57349 },
57350 percentBar: {
57351 root: createClassAndSelector('percentBars'),
57352 mainLine: createClassAndSelector('mainLine'),
57353 leftTick: createClassAndSelector('leftTick'),
57354 rightTick: createClassAndSelector('rightTick'),
57355 text: createClassAndSelector('value'),
57356 },
57357 };
57358 FunnelChart.FunnelBarHighlightClass = [FunnelChart.Selectors.funnel.bars.class, FunnelChart.Selectors.funnel.highlights.class].join(' ');
57359 FunnelChart.YAxisPadding = 10;
57360 FunnelChart.VisualClassName = 'funnelChart';
57361 FunnelChart.DefaultFontFamily = 'wf_standard-font';
57362 FunnelChart.BarToSpaceRatio = 0.1;
57363 FunnelChart.MaxBarHeight = 40;
57364 FunnelChart.MinBarThickness = 12;
57365 FunnelChart.LabelFunnelPadding = 6;
57366 FunnelChart.InnerTextMinimumPadding = 10;
57367 FunnelChart.OverflowingHighlightWidthRatio = 0.5;
57368 FunnelChart.MaxMarginFactor = 0.25;
57369 return FunnelChart;
57370 }());
57371 visuals.FunnelChart = FunnelChart;
57372 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
57373})(powerbi || (powerbi = {}));
57374/*
57375 * Power BI Visualizations
57376 *
57377 * Copyright (c) Microsoft Corporation
57378 * All rights reserved.
57379 * MIT License
57380 *
57381 * Permission is hereby granted, free of charge, to any person obtaining a copy
57382 * of this software and associated documentation files (the ""Software""), to deal
57383 * in the Software without restriction, including without limitation the rights
57384 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
57385 * copies of the Software, and to permit persons to whom the Software is
57386 * furnished to do so, subject to the following conditions:
57387 *
57388 * The above copyright notice and this permission notice shall be included in
57389 * all copies or substantial portions of the Software.
57390 *
57391 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
57392 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57393 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57394 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57395 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57396 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
57397 * THE SOFTWARE.
57398 */
57399var powerbi;
57400(function (powerbi) {
57401 var visuals;
57402 (function (visuals) {
57403 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
57404 var PixelConverter = jsCommon.PixelConverter;
57405 var DataRoleHelper = powerbi.data.DataRoleHelper;
57406 /**
57407 * Renders a number that can be animate change in value.
57408 */
57409 var Gauge = (function () {
57410 function Gauge(options) {
57411 this.lastAngle = -Math.PI / 2;
57412 if (options) {
57413 if (options.gaugeSmallViewPortProperties) {
57414 this.gaugeSmallViewPortProperties = options.gaugeSmallViewPortProperties;
57415 }
57416 this.animator = options.animator;
57417 this.tooltipsEnabled = options.tooltipsEnabled;
57418 }
57419 }
57420 Gauge.prototype.enumerateObjectInstances = function (options) {
57421 var enumeration = new visuals.ObjectEnumerationBuilder();
57422 switch (options.objectName) {
57423 case 'axis':
57424 this.enumerateAxis(enumeration);
57425 break;
57426 case 'labels': {
57427 var labelSettings = this.data ? this.data.dataLabelsSettings : visuals.dataLabelUtils.getDefaultGaugeLabelSettings();
57428 visuals.dataLabelUtils.enumerateDataLabels(this.getDataLabelSettingsOptions(enumeration, labelSettings));
57429 break;
57430 }
57431 case 'calloutValue': {
57432 var labelSettings = this.data ? this.data.calloutValueLabelsSettings : visuals.dataLabelUtils.getDefaultGaugeLabelSettings();
57433 visuals.dataLabelUtils.enumerateDataLabels(this.getDataLabelSettingsOptions(enumeration, labelSettings));
57434 break;
57435 }
57436 case 'dataPoint': {
57437 this.enumerateDataPoint(enumeration);
57438 break;
57439 }
57440 }
57441 return enumeration.complete();
57442 };
57443 Gauge.prototype.getDataLabelSettingsOptions = function (enumeration, labelSettings) {
57444 return {
57445 dataLabelsSettings: labelSettings,
57446 show: true,
57447 precision: true,
57448 displayUnits: true,
57449 fontSize: true,
57450 enumeration: enumeration,
57451 };
57452 };
57453 Gauge.prototype.enumerateAxis = function (enumeration) {
57454 var dataView = this.dataViews[0];
57455 if (dataView && dataView.metadata) {
57456 var properties = Gauge.getGaugeObjectsProperties(dataView);
57457 enumeration.pushInstance({
57458 selector: null,
57459 objectName: 'axis',
57460 properties: properties,
57461 });
57462 }
57463 };
57464 Gauge.prototype.enumerateDataPoint = function (enumeration) {
57465 var dataPointSettings = this.data ? this.data.dataPointSettings : Gauge.DefaultDataPointSettings;
57466 var properties = {};
57467 properties.fill = { solid: { color: dataPointSettings.fillColor } };
57468 if (dataPointSettings.targetColor != null) {
57469 properties.target = { solid: { color: dataPointSettings.targetColor } };
57470 }
57471 enumeration.pushInstance({
57472 selector: null,
57473 objectName: visuals.gaugeProps.dataPoint.target.objectName,
57474 properties: properties
57475 });
57476 };
57477 Gauge.getGaugeObjectsProperties = function (dataView) {
57478 var properties = {};
57479 var objects = dataView.metadata.objects;
57480 var hasAxisObject = !!objects && !!objects.axis;
57481 if (!DataRoleHelper.hasRoleInDataView(dataView, visuals.gaugeRoleNames.minValue))
57482 properties.min = hasAxisObject ? objects.axis.min : undefined;
57483 if (!DataRoleHelper.hasRoleInDataView(dataView, visuals.gaugeRoleNames.maxValue))
57484 properties.max = hasAxisObject ? objects.axis.max : undefined;
57485 if (!DataRoleHelper.hasRoleInDataView(dataView, visuals.gaugeRoleNames.targetValue))
57486 properties.target = hasAxisObject ? objects.axis.target : undefined;
57487 return properties;
57488 };
57489 Gauge.prototype.init = function (options) {
57490 this.element = options.element;
57491 this.currentViewport = options.viewport;
57492 this.style = options.style;
57493 this.options = options;
57494 this.settings = Gauge.DefaultStyleProperties;
57495 this.targetSettings = Gauge.DefaultTargetSettings;
57496 this.setMargins();
57497 this.color = d3.scale.ordinal().range(this.style.colorPalette.dataColors.getSentimentColors().map(function (color) { return color.value; }));
57498 this.hostService = options.host;
57499 var svg = this.svg = d3.select(this.element.get(0)).append('svg');
57500 svg.classed(Gauge.VisualClassName, true);
57501 var mainGraphicsContext = this.mainGraphicsContext = svg.append('g');
57502 mainGraphicsContext.attr('class', Gauge.MainGaugeGroupClassName);
57503 this.initKpiBands();
57504 var backgroundArc = this.backgroundArc = d3.svg.arc()
57505 .innerRadius(0)
57506 .outerRadius(0)
57507 .startAngle(-Math.PI / 2)
57508 .endAngle(Math.PI / 2);
57509 var foregroundArc = this.foregroundArc = d3.svg.arc()
57510 .innerRadius(0)
57511 .outerRadius(0)
57512 .startAngle(-Math.PI / 2);
57513 this.backgroundArcPath = mainGraphicsContext.append('path')
57514 .classed('backgroundArc', true)
57515 .attr('d', backgroundArc);
57516 this.foregroundArcPath = mainGraphicsContext.append('path')
57517 .datum({ endAngle: -Math.PI / 2 })
57518 .classed('foregroundArc', true)
57519 .attr('d', foregroundArc);
57520 var g = this.animatedNumberGrapicsContext = svg.append('g');
57521 this.animatedNumber = new visuals.AnimatedNumber(g);
57522 this.animatedNumber.init(options);
57523 var gaugeDrawingOptions = this.gaugeVisualProperties = this.getGaugeVisualProperties();
57524 var animatedNumberProperties = this.getAnimatedNumberProperties(gaugeDrawingOptions.radius, gaugeDrawingOptions.innerRadiusFactor, gaugeDrawingOptions.top, gaugeDrawingOptions.left);
57525 this.animatedNumberGrapicsContext.attr('transform', animatedNumberProperties.transformString);
57526 this.animatedNumber.onResizing(animatedNumberProperties.viewport);
57527 };
57528 Gauge.prototype.update = function (options) {
57529 debug.assertValue(options, 'options');
57530 this.currentViewport = options.viewport;
57531 var dataViews = this.dataViews = options.dataViews;
57532 if (!dataViews || !dataViews[0]) {
57533 return;
57534 }
57535 this.data = Gauge.converter(dataViews[0], this.tooltipsEnabled);
57536 this.targetSettings = this.data.targetSettings;
57537 if (dataViews[0])
57538 dataViews[0].single = { value: this.data.total };
57539 // Only show the target label if:
57540 // 1. There is a target
57541 // 2. The viewport width is big enough for a target
57542 // 3. We're showing label text for side numbers
57543 // 4. Data label settings specify to show
57544 this.showTargetLabel = this.targetSettings.target != null
57545 && (this.currentViewport.width > Gauge.MinWidthForTargetLabel || !this.showMinMaxLabelsOnBottom())
57546 && this.showSideNumbersLabelText()
57547 && this.data.dataLabelsSettings.show;
57548 this.setMargins();
57549 this.gaugeVisualProperties = this.getGaugeVisualProperties();
57550 this.drawViewPort(this.gaugeVisualProperties);
57551 this.updateInternal(options.suppressAnimations);
57552 this.updateCalloutValue(options.suppressAnimations);
57553 var warnings = visuals.getInvalidValueWarnings(dataViews, false /*supportsNaN*/, false /*supportsNegativeInfinity*/, false /*supportsPositiveInfinity*/);
57554 this.hostService.setWarnings(warnings);
57555 };
57556 Gauge.prototype.updateCalloutValue = function (suppressAnimations) {
57557 if (this.data.calloutValueLabelsSettings.show) {
57558 var animatedNumberProperties = this.getAnimatedNumberProperties(this.gaugeVisualProperties.radius, this.gaugeVisualProperties.innerRadiusFactor, this.gaugeVisualProperties.top, this.gaugeVisualProperties.left);
57559 this.animatedNumberGrapicsContext.attr('transform', animatedNumberProperties.transformString);
57560 this.animatedNumber.setTextColor(this.data.calloutValueLabelsSettings.labelColor);
57561 var calloutValue = this.data ? this.data.total : null;
57562 var formatter = this.getFormatter(this.data.calloutValueLabelsSettings, calloutValue);
57563 this.animatedNumber.setFormatter(formatter);
57564 this.animatedNumber.update({
57565 viewport: animatedNumberProperties.viewport,
57566 dataViews: this.dataViews,
57567 suppressAnimations: suppressAnimations,
57568 });
57569 this.animatedNumberGrapicsContext.selectAll('title').remove();
57570 this.animatedNumberGrapicsContext.append('title').text([formatter.format(calloutValue)]);
57571 }
57572 else {
57573 this.animatedNumber.clear();
57574 this.animatedNumberGrapicsContext.selectAll('title').remove();
57575 }
57576 };
57577 Gauge.prototype.onDataChanged = function (options) {
57578 // TODO: Remove onDataChanged & onResizing once all visuals have implemented update.
57579 this.update({
57580 dataViews: options.dataViews,
57581 suppressAnimations: options.suppressAnimations,
57582 viewport: this.currentViewport
57583 });
57584 };
57585 Gauge.prototype.onResizing = function (viewport) {
57586 // TODO: Remove onDataChanged & onResizing once all visuals have implemented update.
57587 this.update({
57588 dataViews: this.dataViews,
57589 suppressAnimations: true,
57590 viewMode: 0 /* View */,
57591 viewport: viewport
57592 });
57593 };
57594 Gauge.getValidSettings = function (targetData) {
57595 var maxVal = (targetData.max === Gauge.MAX_VALUE) ? Gauge.DEFAULT_MAX : targetData.max;
57596 var minVal = (targetData.min === Gauge.MIN_VALUE) ? Gauge.DEFAULT_MIN : targetData.min;
57597 var targetVal = targetData.target;
57598 return {
57599 min: minVal,
57600 max: maxVal,
57601 target: targetVal
57602 };
57603 };
57604 Gauge.getGaugeData = function (dataView) {
57605 var settings = {
57606 max: Gauge.MAX_VALUE,
57607 min: Gauge.MIN_VALUE,
57608 target: undefined,
57609 total: 0,
57610 tooltipItems: []
57611 };
57612 if (dataView && dataView.categorical && dataView.categorical.values && dataView.metadata && dataView.metadata.columns) {
57613 var values = dataView.categorical.values;
57614 var metadataColumns = dataView.metadata.columns;
57615 debug.assert(metadataColumns.length >= values.length, 'length');
57616 for (var i = 0; i < values.length; i++) {
57617 var col = metadataColumns[i], value = values[i].values[0] || 0;
57618 if (col && col.roles) {
57619 if (col.roles[visuals.gaugeRoleNames.y]) {
57620 settings.total = value;
57621 if (value)
57622 settings.tooltipItems.push({ displayName: values[i].source.displayName, value: visuals.converterHelper.formatFromMetadataColumn(value, values[i].source, Gauge.formatStringProp) });
57623 }
57624 else if (col.roles[visuals.gaugeRoleNames.minValue]) {
57625 settings.min = value;
57626 }
57627 else if (col.roles[visuals.gaugeRoleNames.maxValue]) {
57628 settings.max = value;
57629 }
57630 else if (col.roles[visuals.gaugeRoleNames.targetValue]) {
57631 settings.target = value;
57632 if (value)
57633 settings.tooltipItems.push({ displayName: values[i].source.displayName, value: visuals.converterHelper.formatFromMetadataColumn(value, values[i].source, Gauge.formatStringProp) });
57634 }
57635 }
57636 }
57637 // Override settings according to property pane axis values
57638 var gaugeObjectsSettings = Gauge.getGaugeObjectsProperties(dataView);
57639 if (gaugeObjectsSettings && !$.isEmptyObject(gaugeObjectsSettings))
57640 Gauge.overrideGaugeSettings(settings, gaugeObjectsSettings);
57641 }
57642 else {
57643 settings.tooltipItems = undefined;
57644 }
57645 return settings;
57646 };
57647 Gauge.overrideGaugeSettings = function (settings, gaugeObjectsSettings) {
57648 if ($.isNumeric(gaugeObjectsSettings.min))
57649 settings.min = gaugeObjectsSettings.min;
57650 if ($.isNumeric(gaugeObjectsSettings.max))
57651 settings.max = gaugeObjectsSettings.max;
57652 if ($.isNumeric(gaugeObjectsSettings.target))
57653 settings.target = gaugeObjectsSettings.target;
57654 };
57655 /** Note: Made public for testability */
57656 Gauge.converter = function (dataView, tooltipsEnabled) {
57657 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
57658 var gaugeData = Gauge.getGaugeData(dataView), total = gaugeData.total, formatString = null, hasPercent = false;
57659 if (dataView.metadata && !_.isEmpty(dataView.metadata.columns)) {
57660 formatString = visuals.valueFormatter.getFormatString(dataView.metadata.columns[0], Gauge.formatStringProp, true);
57661 if (formatString != null)
57662 hasPercent = visuals.valueFormatter.getFormatMetadata(formatString).hasPercent;
57663 }
57664 if (total > 0 && gaugeData.max === Gauge.MAX_VALUE) {
57665 gaugeData.max = hasPercent ? Gauge.DEFAULT_MAX : total * 2;
57666 }
57667 var settings = Gauge.getValidSettings(gaugeData);
57668 //Checking that the value is plotted inside the gauge boundaries
57669 var adjustedTotal = Math.max(total, settings.min);
57670 adjustedTotal = Math.min(adjustedTotal, settings.max);
57671 var percent = (settings.min !== settings.max)
57672 ? (adjustedTotal - settings.min) / (settings.max - settings.min)
57673 : 0;
57674 var tooltipInfo;
57675 if (tooltipsEnabled && dataView && gaugeData.tooltipItems != null) {
57676 tooltipInfo = gaugeData.tooltipItems;
57677 }
57678 return {
57679 percent: percent,
57680 adjustedTotal: adjustedTotal,
57681 total: total,
57682 metadataColumn: Gauge.getMetaDataColumn(dataView),
57683 targetSettings: settings,
57684 tooltipInfo: tooltipInfo,
57685 dataLabelsSettings: Gauge.convertDataLabelSettings(dataView, "labels"),
57686 calloutValueLabelsSettings: Gauge.convertDataLabelSettings(dataView, "calloutValue"),
57687 dataPointSettings: Gauge.convertDataPointSettings(dataView, settings)
57688 };
57689 };
57690 Gauge.convertDataLabelSettings = function (dataview, objectName) {
57691 var dataViewMetadata = dataview.metadata;
57692 var dataLabelsSettings = visuals.dataLabelUtils.getDefaultGaugeLabelSettings();
57693 if (dataViewMetadata) {
57694 var objects = dataViewMetadata.objects;
57695 if (objects) {
57696 // Handle label settings
57697 var labelsObj = objects[objectName];
57698 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelsObj, dataLabelsSettings);
57699 }
57700 }
57701 return dataLabelsSettings;
57702 };
57703 Gauge.convertDataPointSettings = function (dataView, targetSettings) {
57704 // Default the fill color the the default fill color. Default the target to undefined as it's only used if there's a target.
57705 var fillColor = Gauge.DefaultDataPointSettings.fillColor;
57706 var targetColor;
57707 if (dataView && dataView.metadata && dataView.metadata.objects) {
57708 // If there is saved metadata, use it for the colors
57709 var objects = dataView.metadata.objects;
57710 fillColor = powerbi.DataViewObjects.getFillColor(objects, visuals.gaugeProps.dataPoint.fill, Gauge.DefaultDataPointSettings.fillColor);
57711 if (targetSettings && (targetSettings.target != null)) {
57712 targetColor = powerbi.DataViewObjects.getFillColor(objects, visuals.gaugeProps.dataPoint.target, Gauge.DefaultDataPointSettings.targetColor);
57713 }
57714 }
57715 else if (targetSettings && (targetSettings.target != null)) {
57716 // If there isn't metadata, but a target is set, default to the default target color
57717 targetColor = Gauge.DefaultDataPointSettings.targetColor;
57718 }
57719 return {
57720 fillColor: fillColor,
57721 targetColor: targetColor
57722 };
57723 };
57724 Gauge.getMetaDataColumn = function (dataView) {
57725 if (dataView && dataView.metadata && dataView.metadata.columns) {
57726 for (var i = 0, ilen = dataView.metadata.columns.length; i < ilen; i++) {
57727 var column = dataView.metadata.columns[i];
57728 if (column.isMeasure) {
57729 return column;
57730 }
57731 }
57732 }
57733 return null;
57734 };
57735 Gauge.prototype.initKpiBands = function () {
57736 if (!this.settings.kpiBands.show)
57737 return;
57738 var kpiArcs = this.kpiArcs = [];
57739 var kpiArcPaths = this.kpiArcPaths = [];
57740 var mainGraphicsContext = this.mainGraphicsContext;
57741 for (var i = 0; i < 3; i++) {
57742 var arc = d3.svg.arc()
57743 .innerRadius(0)
57744 .outerRadius(0)
57745 .startAngle(0)
57746 .endAngle(0);
57747 kpiArcs.push(arc);
57748 var arcPath = mainGraphicsContext.append('path')
57749 .attr("d", arc);
57750 kpiArcPaths.push(arcPath);
57751 }
57752 };
57753 Gauge.prototype.updateKpiBands = function (radius, innerRadiusFactor, tString, kpiAngleAttr) {
57754 if (!this.settings.kpiBands.show)
57755 return;
57756 for (var i = 0; i < kpiAngleAttr.length; i++) {
57757 this.kpiArcs[i]
57758 .innerRadius(radius * innerRadiusFactor - (Gauge.KpiBandDistanceFromMainArc + this.settings.kpiBands.thickness))
57759 .outerRadius(radius * innerRadiusFactor - Gauge.KpiBandDistanceFromMainArc)
57760 .startAngle(kpiAngleAttr[i].start)
57761 .endAngle(kpiAngleAttr[i].end);
57762 this.kpiArcPaths[i]
57763 .attr('fill', kpiAngleAttr[i].fill)
57764 .attr('d', this.kpiArcs[i])
57765 .attr('transform', tString);
57766 }
57767 };
57768 Gauge.prototype.removeTargetElements = function () {
57769 if (this.targetLine) {
57770 this.targetLine.remove();
57771 this.targetText.remove();
57772 this.targetConnector.remove();
57773 this.targetLine = this.targetConnector = this.targetText = null;
57774 }
57775 };
57776 Gauge.prototype.getTargetRatio = function () {
57777 var targetSettings = this.targetSettings;
57778 var range = targetSettings.max - targetSettings.min;
57779 if (range !== 0)
57780 return (targetSettings.target - targetSettings.min) / range;
57781 return 0;
57782 };
57783 Gauge.prototype.updateTargetLine = function (radius, innerRadius, left, top) {
57784 if (!this.targetLine) {
57785 this.targetLine = this.mainGraphicsContext.append('line');
57786 }
57787 var angle = this.getTargetRatio() * Math.PI;
57788 var outY = top - radius * Math.sin(angle);
57789 var outX = left - radius * Math.cos(angle);
57790 var inY = top - innerRadius * Math.sin(angle);
57791 var inX = left - innerRadius * Math.cos(angle);
57792 this.targetLine.attr({
57793 x1: inX,
57794 y1: inY,
57795 x2: outX,
57796 y2: outY
57797 });
57798 };
57799 /** Note: public for testability */
57800 Gauge.prototype.getAnimatedNumberProperties = function (radius, innerRadiusFactor, top, left) {
57801 var boxAngle = Math.PI / 4;
57802 var scale = 1;
57803 var innerRadiusOfArc = radius * innerRadiusFactor;
57804 var innerRadiusForTextBoundingBox = innerRadiusOfArc - (this.settings.kpiBands.show
57805 ? (Gauge.KpiBandDistanceFromMainArc + this.settings.kpiBands.thickness)
57806 : 0);
57807 var innerRCos = innerRadiusForTextBoundingBox * Math.cos(boxAngle);
57808 var innerRSin = innerRadiusForTextBoundingBox * Math.sin(boxAngle);
57809 var innerY = top - innerRSin;
57810 var innerX = left - innerRCos;
57811 innerY = innerY * scale;
57812 innerX = innerX * scale;
57813 var animatedNumberWidth = innerRCos * 2;
57814 var properties = {
57815 transformString: visuals.SVGUtil.translate(innerX, innerY),
57816 viewport: { height: innerRSin, width: animatedNumberWidth }
57817 };
57818 return properties;
57819 };
57820 /** Note: public for testability */
57821 Gauge.prototype.getGaugeVisualProperties = function () {
57822 var viewport = this.currentViewport;
57823 var margin = this.margin;
57824 var width = viewport.width - margin.right - margin.left;
57825 var halfWidth = width / 2;
57826 var height = viewport.height - margin.top - margin.bottom;
57827 var radius = Math.min(halfWidth, height);
57828 var innerRadiusFactor = Gauge.InnerRadiusFactor;
57829 var left = margin.left + halfWidth;
57830 var top = radius + (height - radius) / 2 + margin.top;
57831 var tString = visuals.SVGUtil.translate(left, top);
57832 var innerRadiusOfArc = radius * innerRadiusFactor;
57833 var gaugeData = {
57834 radius: radius,
57835 innerRadiusOfArc: innerRadiusOfArc,
57836 left: left,
57837 top: top,
57838 height: height,
57839 width: width,
57840 margin: margin,
57841 transformString: tString,
57842 innerRadiusFactor: innerRadiusFactor
57843 };
57844 return gaugeData;
57845 };
57846 /** Note: public for testability */
57847 Gauge.prototype.drawViewPort = function (drawOptions) {
57848 debug.assertAnyValue(drawOptions, "Gauge options");
57849 var separation = this.settings.kpiBands.separationRadians;
57850 var innerRadiusFactor = Gauge.InnerRadiusFactor;
57851 var backgroudArc = this.backgroundArc;
57852 var color = this.color;
57853 var attrs = [{
57854 fill: color(0),
57855 start: -Math.PI / 2,
57856 end: -Math.PI / 2 + Math.PI / 4 - separation
57857 }, {
57858 fill: color(1),
57859 start: -Math.PI / 2 + Math.PI * 1 / 4 + separation,
57860 end: -Math.PI / 2 + Math.PI * 3 / 4 - separation
57861 }, {
57862 fill: color(2),
57863 start: -Math.PI / 2 + Math.PI * 3 / 4 + separation,
57864 end: Math.PI / 2
57865 }];
57866 var radius = drawOptions.radius;
57867 var transformString = drawOptions.transformString;
57868 this.updateKpiBands(radius, innerRadiusFactor, transformString, attrs);
57869 backgroudArc
57870 .innerRadius(radius * innerRadiusFactor)
57871 .outerRadius(radius)
57872 .startAngle(-Math.PI / 2)
57873 .endAngle(Math.PI / 2);
57874 this.backgroundArcPath
57875 .attr("d", backgroudArc)
57876 .attr("transform", transformString);
57877 var foregroundArc = this.foregroundArc;
57878 foregroundArc
57879 .innerRadius(radius * innerRadiusFactor)
57880 .outerRadius(radius)
57881 .startAngle(-Math.PI / 2);
57882 this.foregroundArcPath
57883 .datum({ endAngle: this.lastAngle })
57884 .attr("transform", transformString)
57885 .attr("d", foregroundArc);
57886 var innerRadiusOfArc = drawOptions.innerRadiusOfArc;
57887 var left = drawOptions.left;
57888 var top = drawOptions.top;
57889 var margin = drawOptions.margin;
57890 var height = drawOptions.height;
57891 var targetSettings = this.targetSettings;
57892 if (!this.settings.targetLine.show || targetSettings.target == null) {
57893 this.removeTargetElements();
57894 }
57895 else {
57896 if (targetSettings.min > targetSettings.target || targetSettings.max < targetSettings.target) {
57897 this.removeTargetElements();
57898 }
57899 else {
57900 this.updateTargetLine(radius, innerRadiusOfArc, left, top);
57901 this.appendTargetTextAlongArc(radius, height, drawOptions.width, margin);
57902 }
57903 }
57904 this.svg.attr('height', this.currentViewport.height).attr('width', this.currentViewport.width);
57905 };
57906 Gauge.prototype.createTicks = function () {
57907 var settings = this.settings;
57908 var targetSettings = this.targetSettings;
57909 var total = targetSettings.max - targetSettings.min;
57910 var numberOfLabels = settings.labels.count;
57911 var step = total / numberOfLabels;
57912 var arr = [];
57913 var formatter = this.getFormatter(this.data.dataLabelsSettings, targetSettings.max);
57914 for (var i = 0; i < numberOfLabels + 1; i++) {
57915 arr.push(formatter.format(targetSettings.min + (i * step)));
57916 }
57917 return arr;
57918 };
57919 Gauge.prototype.updateInternal = function (suppressAnimations) {
57920 var height = this.gaugeVisualProperties.height;
57921 var width = this.gaugeVisualProperties.width;
57922 var radius = this.gaugeVisualProperties.radius;
57923 var margin = this.margin;
57924 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
57925 var data = this.data;
57926 var lastAngle = this.lastAngle = -Math.PI / 2 + Math.PI * data.percent;
57927 var ticks = this.createTicks();
57928 this.foregroundArcPath
57929 .transition()
57930 .ease(this.settings.transition.ease)
57931 .duration(duration)
57932 .call(this.arcTween, [lastAngle, this.foregroundArc]);
57933 this.appendTextAlongArc(ticks, radius, height, width, margin);
57934 this.updateVisualConfigurations();
57935 this.updateVisualStyles();
57936 if (this.tooltipsEnabled) {
57937 visuals.TooltipManager.addTooltip(this.foregroundArcPath, function (tooltipEvent) { return data.tooltipInfo; });
57938 visuals.TooltipManager.addTooltip(this.backgroundArcPath, function (tooltipEvent) { return data.tooltipInfo; });
57939 }
57940 };
57941 Gauge.prototype.updateVisualStyles = function () {
57942 var fillColor = this.data.dataLabelsSettings.labelColor || this.style.labelText.color.value;
57943 this.mainGraphicsContext.selectAll('text')
57944 .style({
57945 'fill': fillColor,
57946 });
57947 };
57948 Gauge.prototype.updateVisualConfigurations = function () {
57949 var configOptions = this.settings;
57950 var dataPointSettings = this.data.dataPointSettings;
57951 this.mainGraphicsContext
57952 .select('line')
57953 .attr({
57954 stroke: dataPointSettings.targetColor,
57955 'stroke-width': configOptions.targetLine.thickness,
57956 });
57957 this.backgroundArcPath.style('fill', configOptions.arcColors.background);
57958 this.foregroundArcPath.style('fill', dataPointSettings.fillColor);
57959 };
57960 Gauge.prototype.appendTextAlongArc = function (ticks, radius, height, width, margin) {
57961 this.svg.selectAll(Gauge.LabelText.selector).remove();
57962 if (!this.data.dataLabelsSettings.show)
57963 return;
57964 var total = ticks.length;
57965 var divisor = total - 1;
57966 var top = (radius + (height - radius) / 2 + margin.top);
57967 var showMinMaxLabelsOnBottom = this.showMinMaxLabelsOnBottom();
57968 var fontSize = PixelConverter.fromPoint(this.data.dataLabelsSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt);
57969 var padding = this.settings.labels.padding;
57970 for (var count = 0; count < total; count++) {
57971 var textProperties = {
57972 text: ticks[count],
57973 fontFamily: visuals.dataLabelUtils.LabelTextProperties.fontFamily,
57974 fontSize: visuals.dataLabelUtils.LabelTextProperties.fontSize,
57975 fontWeight: visuals.dataLabelUtils.LabelTextProperties.fontWeight,
57976 };
57977 if (Math.floor(total / 2) === count)
57978 continue; // Skip Middle label, by design
57979 if (this.showSideNumbersLabelText()) {
57980 var x = (margin.left + width / 2) - (radius * Math.cos(Math.PI * count / divisor));
57981 var y = top - (radius * Math.sin(Math.PI * count / divisor));
57982 var anchor = void 0;
57983 var onRight = count * 2 > total;
57984 var onBottom = false;
57985 if (showMinMaxLabelsOnBottom && (count === 0 || count === total - 1)) {
57986 // If this is a min or max label and we're showing them on the bottom rather than the sides
57987 // Adjust the label display properties to appear under the arc
57988 onBottom = true;
57989 y += padding / 2;
57990 // Align the labels with the outer edge of the arc
57991 anchor = onRight ? 'end' : 'start';
57992 textProperties.text = powerbi.TextMeasurementService.getTailoredTextOrDefault(textProperties, radius);
57993 }
57994 else {
57995 // For all other labels, display around the arc
57996 anchor = onRight ? 'start' : 'end';
57997 x += padding * (onRight ? 1 : -1);
57998 }
57999 var text = this.mainGraphicsContext
58000 .append('text')
58001 .attr({
58002 'x': x,
58003 'y': y,
58004 'dy': onBottom ? fontSize : 0,
58005 'class': Gauge.LabelText.class
58006 })
58007 .style({
58008 'text-anchor': anchor,
58009 'font-size': fontSize
58010 })
58011 .text(textProperties.text)
58012 .append('title').text(textProperties.text);
58013 if (!onBottom)
58014 this.truncateTextIfNeeded(text, x, onRight);
58015 }
58016 }
58017 };
58018 Gauge.prototype.truncateTextIfNeeded = function (text, positionX, onRight) {
58019 var availableSpace = (onRight ? this.currentViewport.width - positionX : positionX);
58020 text.call(visuals.AxisHelper.LabelLayoutStrategy.clip, availableSpace, powerbi.TextMeasurementService.svgEllipsis);
58021 };
58022 Gauge.prototype.getFormatter = function (dataLabelSettings, value2) {
58023 var realValue2 = dataLabelSettings.displayUnits === 0 ? value2 : null;
58024 var formatString = visuals.valueFormatter.getFormatString(this.data.metadataColumn, Gauge.formatStringProp);
58025 var precision = visuals.dataLabelUtils.getLabelPrecision(dataLabelSettings.precision, formatString);
58026 var valueFormatterOptions = visuals.dataLabelUtils.getOptionsForLabelFormatter(dataLabelSettings, formatString, realValue2, precision);
58027 valueFormatterOptions.formatSingleValues = dataLabelSettings.displayUnits > 0 ? false : true;
58028 return visuals.valueFormatter.create(valueFormatterOptions);
58029 };
58030 Gauge.prototype.appendTargetTextAlongArc = function (radius, height, width, margin) {
58031 var targetSettings = this.targetSettings;
58032 var target = targetSettings.target;
58033 var tRatio = this.getTargetRatio();
58034 var top = (radius + (height - radius) / 2 + margin.top);
58035 var flag = tRatio > 0.5;
58036 var padding = this.settings.labels.padding;
58037 var anchor = flag ? 'start' : 'end';
58038 var formatter = this.getFormatter(this.data.dataLabelsSettings, targetSettings.max);
58039 var maxRatio = Math.asin(Gauge.MinDistanceFromBottom / radius) / Math.PI;
58040 var finalRatio = tRatio < maxRatio || tRatio > (1 - maxRatio)
58041 ? flag
58042 ? 1 - maxRatio
58043 : maxRatio
58044 : tRatio;
58045 var targetX = (margin.left + width / 2) - ((radius + padding) * Math.cos(Math.PI * finalRatio));
58046 var targetY = top - ((radius + padding) * Math.sin(Math.PI * finalRatio));
58047 if (!this.targetText) {
58048 this.targetText = this.mainGraphicsContext
58049 .append('text')
58050 .classed(Gauge.TargetText.class, true);
58051 }
58052 this.targetText
58053 .attr({
58054 'x': targetX,
58055 'y': targetY,
58056 })
58057 .style({
58058 'text-anchor': anchor,
58059 'display': this.showTargetLabel ? '' : 'none',
58060 'font-size': this.style.labelText.fontSize
58061 })
58062 .text(formatter.format(target));
58063 this.truncateTextIfNeeded(this.targetText, targetX, flag);
58064 this.targetText.call(visuals.tooltipUtils.tooltipUpdate, [formatter.format(target)]);
58065 if (!this.targetConnector) {
58066 this.targetConnector = this.mainGraphicsContext
58067 .append('line')
58068 .classed(Gauge.TargetConnector.class, true);
58069 }
58070 // Hide the target connector if the text is going to align with the target line in the arc
58071 // It should only be shown if the target text is displaced (ex. when the target is very close to min/max)
58072 if (tRatio === finalRatio) {
58073 this.targetConnector.style('display', 'none');
58074 }
58075 else {
58076 this.targetConnector
58077 .attr({
58078 'x1': (margin.left + width / 2) - (radius * Math.cos(Math.PI * tRatio)),
58079 'y1': top - (radius * Math.sin(Math.PI * tRatio)),
58080 'x2': targetX,
58081 'y2': targetY
58082 })
58083 .style({
58084 'stroke-width': this.settings.targetLine.thickness,
58085 'stroke': this.settings.targetLine.color,
58086 'display': ''
58087 });
58088 }
58089 };
58090 Gauge.prototype.arcTween = function (transition, arr) {
58091 transition.attrTween('d', function (d) {
58092 var interpolate = d3.interpolate(d.endAngle, arr[0]);
58093 return function (t) {
58094 d.endAngle = interpolate(t);
58095 return arr[1](d);
58096 };
58097 });
58098 };
58099 Gauge.prototype.showMinMaxLabelsOnBottom = function () {
58100 // More vertical space, put labels on bottom
58101 if (this.currentViewport.height > this.currentViewport.width)
58102 return true;
58103 // We want to show the start/end ticks on the bottom when there
58104 // is insufficient space for the left and right label text
58105 if (this.data && this.gaugeVisualProperties) {
58106 var ticks = this.createTicks();
58107 var visualWhitespace = (this.currentViewport.width - (this.gaugeVisualProperties.radius * 2)) / 2;
58108 var maxLabelWidth = visualWhitespace - this.settings.labels.padding;
58109 var textProperties = powerbi.TextMeasurementService.getMeasurementProperties($(this.svg.node()));
58110 textProperties.fontSize = PixelConverter.fromPoint(this.data.dataLabelsSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt);
58111 var width = void 0;
58112 for (var _i = 0, _a = [ticks[0], ticks[ticks.length - 1]]; _i < _a.length; _i++) {
58113 var tickValue = _a[_i];
58114 textProperties.text = tickValue;
58115 width = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
58116 if (width > maxLabelWidth)
58117 return true;
58118 }
58119 }
58120 return false;
58121 };
58122 Gauge.prototype.setMargins = function () {
58123 if (this.gaugeSmallViewPortProperties) {
58124 if (this.gaugeSmallViewPortProperties.smallGaugeMarginsOnSmallViewPort && (this.currentViewport.height < this.gaugeSmallViewPortProperties.MinHeightGaugeSideNumbersVisible)) {
58125 var margins = this.gaugeSmallViewPortProperties.GaugeMarginsOnSmallViewPort;
58126 this.margin = { top: margins, bottom: margins, left: margins, right: margins };
58127 return;
58128 }
58129 }
58130 this.margin = {
58131 top: Gauge.DefaultTopBottomMargin,
58132 bottom: Gauge.DefaultTopBottomMargin,
58133 left: Gauge.DefaultLeftRightMargin,
58134 right: Gauge.DefaultLeftRightMargin
58135 };
58136 // If we're not showing side labels, reduce the margin so that the gauge has more room to display
58137 if (!this.showSideNumbersLabelText() || this.showMinMaxLabelsOnBottom()) {
58138 var targetSettings = this.targetSettings;
58139 if (this.showTargetLabel) {
58140 // If we're showing the target label, only reduce the margin on the side that doesn't have a target label
58141 var tRatio = (targetSettings.target - targetSettings.min) / (targetSettings.max - targetSettings.min);
58142 if (tRatio > 0.5)
58143 this.margin.left = Gauge.ReducedLeftRightMargin;
58144 else
58145 this.margin.right = Gauge.ReducedLeftRightMargin;
58146 }
58147 else {
58148 // Otherwise, reduce both margins
58149 this.margin.left = this.margin.right = Gauge.ReducedLeftRightMargin;
58150 }
58151 }
58152 var fontSize = 0;
58153 if (this.data && this.data.dataLabelsSettings && this.data.dataLabelsSettings.fontSize && this.data.dataLabelsSettings.fontSize >= visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt) {
58154 fontSize = PixelConverter.fromPointToPixel(this.data.dataLabelsSettings.fontSize - visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt);
58155 }
58156 if (fontSize !== 0) {
58157 this.margin.bottom += fontSize;
58158 this.margin.left += fontSize;
58159 this.margin.right += fontSize;
58160 }
58161 };
58162 Gauge.prototype.showSideNumbersLabelText = function () {
58163 if (this.gaugeSmallViewPortProperties) {
58164 if (this.gaugeSmallViewPortProperties.hideGaugeSideNumbersOnSmallViewPort) {
58165 if (this.currentViewport.height < this.gaugeSmallViewPortProperties.MinHeightGaugeSideNumbersVisible) {
58166 return false;
58167 }
58168 }
58169 }
58170 return true;
58171 };
58172 Gauge.MIN_VALUE = -Infinity;
58173 Gauge.MAX_VALUE = +Infinity;
58174 Gauge.MinDistanceFromBottom = 10;
58175 Gauge.MinWidthForTargetLabel = 150;
58176 Gauge.DefaultTopBottomMargin = 20;
58177 Gauge.DefaultLeftRightMargin = 45;
58178 Gauge.ReducedLeftRightMargin = 15;
58179 Gauge.DEFAULT_MAX = 1;
58180 Gauge.DEFAULT_MIN = 0;
58181 Gauge.VisualClassName = 'gauge';
58182 Gauge.DefaultStyleProperties = {
58183 transition: {
58184 ease: 'bounce'
58185 },
58186 arcColors: {
58187 background: '#e9e9e9',
58188 foreground: '#00B8AA'
58189 },
58190 targetLine: {
58191 show: true,
58192 color: '#666666',
58193 thickness: 2
58194 },
58195 labels: {
58196 count: 2,
58197 padding: 5,
58198 fontSize: visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt,
58199 },
58200 kpiBands: {
58201 show: false,
58202 separationRadians: Math.PI / 128,
58203 thickness: 5
58204 },
58205 };
58206 Gauge.DefaultTargetSettings = {
58207 min: 0,
58208 max: 1,
58209 target: undefined
58210 };
58211 Gauge.DefaultDataPointSettings = {
58212 fillColor: Gauge.DefaultStyleProperties.arcColors.foreground,
58213 targetColor: Gauge.DefaultStyleProperties.targetLine.color
58214 };
58215 Gauge.InnerRadiusFactor = 0.7;
58216 Gauge.KpiBandDistanceFromMainArc = 2;
58217 Gauge.MainGaugeGroupClassName = 'mainGroup';
58218 Gauge.LabelText = createClassAndSelector('labelText');
58219 Gauge.TargetConnector = createClassAndSelector('targetConnector');
58220 Gauge.TargetText = createClassAndSelector('targetText');
58221 /** Note: Public for testability */
58222 Gauge.formatStringProp = {
58223 objectName: 'general',
58224 propertyName: 'formatString',
58225 };
58226 return Gauge;
58227 }());
58228 visuals.Gauge = Gauge;
58229 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
58230})(powerbi || (powerbi = {}));
58231/*
58232 * Power BI Visualizations
58233 *
58234 * Copyright (c) Microsoft Corporation
58235 * All rights reserved.
58236 * MIT License
58237 *
58238 * Permission is hereby granted, free of charge, to any person obtaining a copy
58239 * of this software and associated documentation files (the ""Software""), to deal
58240 * in the Software without restriction, including without limitation the rights
58241 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58242 * copies of the Software, and to permit persons to whom the Software is
58243 * furnished to do so, subject to the following conditions:
58244 *
58245 * The above copyright notice and this permission notice shall be included in
58246 * all copies or substantial portions of the Software.
58247 *
58248 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58249 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
58250 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58251 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58252 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58253 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58254 * THE SOFTWARE.
58255 */
58256var powerbi;
58257(function (powerbi) {
58258 var visuals;
58259 (function (visuals) {
58260 var Utility = jsCommon.Utility;
58261 var ImageVisual = (function () {
58262 function ImageVisual() {
58263 this.scalingType = visuals.imageScalingType.normal;
58264 }
58265 ImageVisual.prototype.init = function (options) {
58266 this.element = options.element;
58267 };
58268 ImageVisual.prototype.enumerateObjectInstances = function (options) {
58269 switch (options.objectName) {
58270 case 'imageScaling':
58271 return this.enumerateImageScaling();
58272 }
58273 return null;
58274 };
58275 ImageVisual.prototype.enumerateImageScaling = function () {
58276 return [{
58277 selector: null,
58278 objectName: 'imageScaling',
58279 properties: {
58280 imageScalingType: this.scalingType,
58281 }
58282 }];
58283 };
58284 ImageVisual.prototype.update = function (options) {
58285 var dataViews = options.dataViews;
58286 if (!dataViews || dataViews.length === 0)
58287 return;
58288 var objects = dataViews[0].metadata.objects;
58289 if (!objects || !objects.general)
58290 return;
58291 var div = this.imageBackgroundElement;
58292 if (!div) {
58293 div = $("<div class='imageBackground' />");
58294 this.imageBackgroundElement = div;
58295 this.imageBackgroundElement.appendTo(this.element);
58296 }
58297 var viewport = options.viewport;
58298 div.css('height', viewport.height);
58299 if (objects.imageScaling)
58300 this.scalingType = objects.imageScaling.imageScalingType.toString();
58301 else
58302 this.scalingType = visuals.imageScalingType.normal;
58303 var imageUrl = objects.general.imageUrl;
58304 if (Utility.isLocalUrl(imageUrl))
58305 div.css("backgroundImage", "url(" + imageUrl + ")");
58306 if (this.scalingType === visuals.imageScalingType.fit)
58307 div.css("background-size", "100% 100%");
58308 else if (this.scalingType === visuals.imageScalingType.fill)
58309 div.css("background-size", "cover");
58310 else
58311 div.css("background-size", "contain");
58312 };
58313 return ImageVisual;
58314 }());
58315 visuals.ImageVisual = ImageVisual;
58316 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
58317})(powerbi || (powerbi = {}));
58318/*
58319 * Power BI Visualizations
58320 *
58321 * Copyright (c) Microsoft Corporation
58322 * All rights reserved.
58323 * MIT License
58324 *
58325 * Permission is hereby granted, free of charge, to any person obtaining a copy
58326 * of this software and associated documentation files (the ""Software""), to deal
58327 * in the Software without restriction, including without limitation the rights
58328 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58329 * copies of the Software, and to permit persons to whom the Software is
58330 * furnished to do so, subject to the following conditions:
58331 *
58332 * The above copyright notice and this permission notice shall be included in
58333 * all copies or substantial portions of the Software.
58334 *
58335 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58336 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
58337 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58338 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58339 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58340 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58341 * THE SOFTWARE.
58342 */
58343var powerbi;
58344(function (powerbi) {
58345 var visuals;
58346 (function (visuals) {
58347 var DataRoleHelper = powerbi.data.DataRoleHelper;
58348 var KPIStatusWithHistory = (function () {
58349 function KPIStatusWithHistory() {
58350 }
58351 KPIStatusWithHistory.prototype.init = function (options) {
58352 KPIStatusWithHistory.getLocalizedString = options.host.getLocalizedString;
58353 this.rootElement = d3.select(options.element.get(0)).append('div').attr('text-align', 'center').classed('kpiVisual', true);
58354 this.svg = this.rootElement.append('svg');
58355 var mainGroupElement = this.mainGroupElement = this.svg.append('g');
58356 this.areaFill = mainGroupElement.append("path");
58357 this.textContainer = this.rootElement.append("div").classed('textContainer', true);
58358 this.indicatorTextContainer = this.textContainer.append("div").classed('indicatorText', true);
58359 this.absoluteGoalDistanceText = this.textContainer.append("div").classed('goalText', true);
58360 this.kpiActualText = this.indicatorTextContainer.append("div").attr('id', 'indicatorText');
58361 this.initIcons();
58362 this.host = options.host;
58363 };
58364 KPIStatusWithHistory.prototype.update = function (options) {
58365 if (!options.dataViews || !options.dataViews[0])
58366 return;
58367 var dataView = this.dataView = options.dataViews[0];
58368 var viewport = options.viewport;
58369 // We must have at least one measure
58370 if ((!dataView.categorical || !dataView.categorical.values || dataView.categorical.values.length < 1) &&
58371 (!dataView.categorical || !dataView.categorical.categories || dataView.categorical.categories.length < 1)) {
58372 this.svg.attr("visibility", "hidden");
58373 this.textContainer.attr("style", "display:none");
58374 return;
58375 }
58376 this.svg.attr("visibility", "visible");
58377 var kpiViewModel = KPIStatusWithHistory.converter(dataView, viewport, KPIStatusWithHistory.getProp_KPIDirection(dataView));
58378 this.render(kpiViewModel, viewport);
58379 };
58380 KPIStatusWithHistory.prototype.initIcons = function () {
58381 this.successMarkIcon = this.indicatorTextContainer.append("div").classed('powervisuals-glyph checkmark kpi-visual-green', true);
58382 this.betweenIcon = this.indicatorTextContainer.append('div').classed('powervisuals-glyph circle-small kpi-visual-yellow', true);
58383 this.exclamationMarkIcon = this.indicatorTextContainer.append("div").classed('powervisuals-glyph exclamation kpi-visual-red', true);
58384 this.successMarkIcon.attr('style', 'display:none');
58385 this.betweenIcon.attr('style', 'display:none');
58386 this.exclamationMarkIcon.attr('style', 'display:none');
58387 };
58388 KPIStatusWithHistory.prototype.render = function (kpiViewModel, viewport) {
58389 this.setShowDataMissingWarning(!(kpiViewModel.indicatorExists && kpiViewModel.trendExists));
58390 if (kpiViewModel.dataPoints.length === 0 || !kpiViewModel.indicatorExists || !kpiViewModel.trendExists) {
58391 this.areaFill.attr("visibility", "hidden");
58392 this.svg.attr("visibility", "hidden");
58393 this.textContainer.attr("style", "display:none");
58394 return;
58395 }
58396 this.svg.attr({
58397 'height': viewport.height,
58398 'width': viewport.width,
58399 });
58400 var status = KPIStatusWithHistory.status.NOGOAL;
58401 if (kpiViewModel.targetExists && kpiViewModel.indicatorExists && kpiViewModel.trendExists) {
58402 status = GetStatus(kpiViewModel.actual, kpiViewModel.goals, kpiViewModel.directionType);
58403 }
58404 var actualText = kpiViewModel.formattedValue;
58405 var calculatedHeight = KPIStatusWithHistory.indicatorTextSizeInPx;
58406 this.textContainer
58407 .attr('style', "width:" + viewport.width + "px;" +
58408 "top:" + ((viewport.height - calculatedHeight) / 2) + "px");
58409 this.kpiActualText
58410 .classed(KPIStatusWithHistory.allColorClasses, false)
58411 .classed(GetTextColorClassByStatus(status), true)
58412 .attr("text-anchor", "middle")
58413 .text(actualText);
58414 var icon = null;
58415 switch (status) {
58416 case KPIStatusWithHistory.status.INCREASE:
58417 icon = this.successMarkIcon;
58418 this.exclamationMarkIcon.attr("style", "display:none");
58419 this.betweenIcon.attr("style", "display:none");
58420 break;
58421 case KPIStatusWithHistory.status.IN_BETWEEN:
58422 icon = this.betweenIcon;
58423 this.exclamationMarkIcon.attr("style", "display:none");
58424 this.successMarkIcon.attr("style", "display:none");
58425 break;
58426 case KPIStatusWithHistory.status.DROP:
58427 icon = this.exclamationMarkIcon;
58428 this.successMarkIcon.attr("style", "display:none");
58429 this.betweenIcon.attr("style", "display:none");
58430 break;
58431 default:
58432 this.exclamationMarkIcon.attr("style", "display:none");
58433 this.successMarkIcon.attr("style", "display:none");
58434 this.betweenIcon.attr("style", "display:none");
58435 }
58436 if (icon) {
58437 icon.attr('style', 'font-size:12px');
58438 }
58439 var shownGoalString = kpiViewModel.showGoal ? kpiViewModel.formattedGoalString + " " : "";
58440 var shownDistanceFromGoalString = kpiViewModel.showDistanceFromGoal ? getDistanceFromGoalInPercentageString(kpiViewModel.actual, kpiViewModel.goals, kpiViewModel.directionType) : "";
58441 this.absoluteGoalDistanceText
58442 .attr("text-anchor", "middle")
58443 .text(shownGoalString + shownDistanceFromGoalString);
58444 if (kpiViewModel.showTrendLine && kpiViewModel.historyExists) {
58445 var area = d3.svg.area()
58446 .x(function (d) { return d.x; })
58447 .y0(viewport.height)
58448 .y1(function (d) { return d.y; });
58449 this.areaFill
58450 .classed(KPIStatusWithHistory.allColorClasses, false)
58451 .classed(GetGraphColorClassByStatus(status), true)
58452 .attr("d", area(kpiViewModel.dataPoints))
58453 .attr("stroke", "none")
58454 .attr("visibility", "visible")
58455 .attr('fill-opacity', 0.2);
58456 }
58457 else {
58458 this.areaFill.attr("visibility", "hidden");
58459 }
58460 };
58461 KPIStatusWithHistory.prototype.setShowDataMissingWarning = function (show) {
58462 this.host.setWarnings(show ? [new visuals.VisualKPIDataMissingWarning()] : []);
58463 };
58464 KPIStatusWithHistory.getDefaultFormatSettings = function () {
58465 return {
58466 labelSettings: visuals.dataLabelUtils.getDefaultLabelSettings(true, visuals.Card.DefaultStyle.value.color),
58467 textSize: 27,
58468 wordWrap: false
58469 };
58470 };
58471 KPIStatusWithHistory.getFormatString = function (column) {
58472 debug.assertAnyValue(column, 'column');
58473 return visuals.valueFormatter.getFormatString(column, visuals.AnimatedText.formatStringProp);
58474 };
58475 KPIStatusWithHistory.getProp_Show_KPIGoal = function (dataView) {
58476 if (dataView && dataView.metadata) {
58477 return powerbi.DataViewObjects.getValue(dataView.metadata.objects, KPIStatusWithHistory.showKPIGoal, true);
58478 }
58479 return true;
58480 };
58481 KPIStatusWithHistory.getProp_Show_KPITrendLine = function (dataView) {
58482 if (dataView && dataView.metadata) {
58483 return powerbi.DataViewObjects.getValue(dataView.metadata.objects, KPIStatusWithHistory.showKPITrendLine, true);
58484 }
58485 return true;
58486 };
58487 KPIStatusWithHistory.getProp_Show_KPIDistance = function (dataView) {
58488 if (dataView && dataView.metadata) {
58489 return powerbi.DataViewObjects.getValue(dataView.metadata.objects, KPIStatusWithHistory.showKPIDistance, true);
58490 }
58491 return true;
58492 };
58493 KPIStatusWithHistory.getProp_KPIDirection = function (dataView) {
58494 if (dataView && dataView.metadata) {
58495 return powerbi.DataViewObjects.getValue(dataView.metadata.objects, KPIStatusWithHistory.directionTypeStringProp, visuals.kpiDirection.positive);
58496 }
58497 return visuals.kpiDirection.positive;
58498 };
58499 KPIStatusWithHistory.getProp_Indicator_DisplayUnits = function (dataView) {
58500 KPIStatusWithHistory.initDefaultLabelSettings();
58501 if (dataView && dataView.metadata) {
58502 return powerbi.DataViewObjects.getValue(dataView.metadata.objects, KPIStatusWithHistory.indicatorDisplayUnitsProp, KPIStatusWithHistory.defaultLabelSettings.displayUnits);
58503 }
58504 return KPIStatusWithHistory.defaultLabelSettings.displayUnits;
58505 };
58506 KPIStatusWithHistory.getProp_Indicator_Precision = function (dataView) {
58507 KPIStatusWithHistory.initDefaultLabelSettings();
58508 if (dataView && dataView.metadata) {
58509 return powerbi.DataViewObjects.getValue(dataView.metadata.objects, KPIStatusWithHistory.indicatorPrecisionProp, KPIStatusWithHistory.defaultLabelSettings.precision);
58510 }
58511 return KPIStatusWithHistory.defaultLabelSettings.precision;
58512 };
58513 KPIStatusWithHistory.initDefaultLabelSettings = function () {
58514 if (!KPIStatusWithHistory.defaultCardFormatSetting) {
58515 KPIStatusWithHistory.defaultCardFormatSetting = KPIStatusWithHistory.getDefaultFormatSettings();
58516 KPIStatusWithHistory.defaultLabelSettings = KPIStatusWithHistory.defaultCardFormatSetting.labelSettings;
58517 }
58518 };
58519 KPIStatusWithHistory.getFormattedValue = function (metaDataColumn, theValue, precision, displayUnits, displayUnitSystemType) {
58520 if (displayUnitSystemType === void 0) { displayUnitSystemType = powerbi.DisplayUnitSystemType.WholeUnits; }
58521 var isDefaultDisplayUnit = displayUnits === 0;
58522 var formatter = visuals.valueFormatter.create({
58523 format: KPIStatusWithHistory.getFormatString(metaDataColumn),
58524 value: displayUnits,
58525 precision: precision,
58526 displayUnitSystemType: displayUnitSystemType,
58527 formatSingleValues: isDefaultDisplayUnit ? true : false,
58528 allowFormatBeautification: true,
58529 columnType: metaDataColumn ? metaDataColumn.type : undefined
58530 });
58531 return formatter.format(theValue);
58532 };
58533 KPIStatusWithHistory.getFormattedGoalString = function (metaDataColumn, goals, precision, displayUnits) {
58534 if (!goals || goals.length === 0) {
58535 return "";
58536 }
58537 var goalsString = KPIStatusWithHistory.getLocalizedString('Visual_KPI_Goal_Title') + ": " + KPIStatusWithHistory.getFormattedValue(metaDataColumn, goals[0], precision, displayUnits);
58538 if (goals.length === 2) {
58539 goalsString += ", " + KPIStatusWithHistory.getFormattedValue(metaDataColumn, goals[1], precision, displayUnits);
58540 }
58541 return goalsString;
58542 };
58543 KPIStatusWithHistory.converter = function (dataView, viewPort, directionType) {
58544 var dataPoints = [];
58545 var catDv = dataView.categorical;
58546 var indicatorMetadataColumn = null;
58547 var goalMetadataColumn = null;
58548 var formattedGoalString = "";
58549 var formattedValue = "";
58550 var targetExists = false;
58551 var indicatorExists = false;
58552 var trendExists = false;
58553 var historyExists = true;
58554 if (!dataView.categorical.categories) {
58555 historyExists = false;
58556 }
58557 var values = catDv.values;
58558 var columns = dataView.metadata.columns;
58559 for (var _i = 0, columns_2 = columns; _i < columns_2.length; _i++) {
58560 var column = columns_2[_i];
58561 if (DataRoleHelper.hasRole(column, 'Indicator')) {
58562 indicatorExists = true;
58563 indicatorMetadataColumn = column;
58564 }
58565 if (DataRoleHelper.hasRole(column, 'TrendLine')) {
58566 trendExists = true;
58567 }
58568 if (DataRoleHelper.hasRole(column, 'Goal')) {
58569 targetExists = true;
58570 goalMetadataColumn = column;
58571 }
58572 }
58573 if (!indicatorExists || !trendExists || !values || values.length === 0 || !values[0].values || !dataView.categorical.values) {
58574 return {
58575 dataPoints: dataPoints,
58576 directionType: directionType,
58577 actual: 0,
58578 goals: [],
58579 formattedGoalString: formattedGoalString,
58580 targetExists: targetExists,
58581 historyExists: historyExists,
58582 indicatorExists: indicatorExists,
58583 trendExists: trendExists,
58584 formattedValue: formattedValue,
58585 showGoal: false,
58586 showDistanceFromGoal: false,
58587 showTrendLine: false
58588 };
58589 }
58590 var category, categoryValues;
58591 if (historyExists) {
58592 category = catDv.categories[0]; // This only works if we have a category axis
58593 categoryValues = category.values;
58594 }
58595 var historyActualData = [];
58596 var historyGoalData = [];
58597 var indicatorColumns = KPIStatusWithHistory.getColumnsByRole(values, "Indicator");
58598 var goalColumns = KPIStatusWithHistory.getColumnsByRole(values, "Goal");
58599 var actualValue;
58600 for (var i = 0, len = values[0].values.length; i < len; i++) {
58601 actualValue = indicatorColumns[0].values[i];
58602 var goals_1 = [];
58603 for (var goalCnt = 0; goalCnt < goalColumns.length; goalCnt++) {
58604 goals_1.push(goalColumns[goalCnt].values[i]);
58605 }
58606 historyGoalData.push(goals_1);
58607 historyActualData.push(actualValue);
58608 }
58609 var maxActualData = Math.max.apply(Math, historyActualData);
58610 var minActualData = Math.min.apply(Math, historyActualData);
58611 var areaMaxHight = viewPort.height * KPIStatusWithHistory.trendAreaFilePercentage;
58612 var precision = KPIStatusWithHistory.getProp_Indicator_Precision(dataView);
58613 var displayUnits = KPIStatusWithHistory.getProp_Indicator_DisplayUnits(dataView);
58614 for (var i = 0; i < historyActualData.length; i++) {
58615 var yPos = areaMaxHight * (historyActualData[i] - minActualData) / (maxActualData - minActualData);
58616 var selectorId = null;
58617 if (historyExists) {
58618 selectorId = visuals.SelectionId.createWithId(category.identity[i]).getSelector();
58619 }
58620 dataPoints.push({
58621 x: i * viewPort.width / (historyActualData.length - 1),
58622 y: viewPort.height - yPos,
58623 actual: historyActualData[i],
58624 goals: historyGoalData[i],
58625 });
58626 }
58627 var actual, goals;
58628 if (dataPoints.length > 0) {
58629 actual = dataPoints[dataPoints.length - 1].actual;
58630 goals = dataPoints[dataPoints.length - 1].goals;
58631 }
58632 if (dataPoints.length === 1) {
58633 historyExists = false;
58634 }
58635 formattedValue = KPIStatusWithHistory.getFormattedValue(indicatorMetadataColumn, actual, precision, displayUnits, powerbi.DisplayUnitSystemType.DataLabels);
58636 formattedGoalString = KPIStatusWithHistory.getFormattedGoalString(goalMetadataColumn, goals, precision, displayUnits);
58637 var showGoal = KPIStatusWithHistory.getProp_Show_KPIGoal(dataView);
58638 var showDistanceFromGoal = KPIStatusWithHistory.getProp_Show_KPIDistance(dataView);
58639 var showTrendLine = KPIStatusWithHistory.getProp_Show_KPITrendLine(dataView);
58640 return {
58641 dataPoints: dataPoints,
58642 directionType: directionType,
58643 actual: actual,
58644 goals: goals,
58645 formattedGoalString: formattedGoalString,
58646 targetExists: targetExists,
58647 historyExists: historyExists,
58648 indicatorExists: indicatorExists,
58649 trendExists: trendExists,
58650 formattedValue: formattedValue,
58651 showGoal: showGoal,
58652 showDistanceFromGoal: showDistanceFromGoal,
58653 showTrendLine: showTrendLine
58654 };
58655 };
58656 KPIStatusWithHistory.getColumnsByRole = function (values, roleString) {
58657 var retval = [];
58658 for (var i = 0; i < values.length; i++) {
58659 if (DataRoleHelper.hasRole(values[i].source, roleString)) {
58660 retval.push(values[i]);
58661 }
58662 }
58663 return retval;
58664 };
58665 KPIStatusWithHistory.prototype.enumerateObjectInstances = function (options) {
58666 var instances = [];
58667 var dataView = this.dataView;
58668 switch (options.objectName) {
58669 case 'indicator':
58670 instances.push({
58671 selector: null,
58672 objectName: 'indicator',
58673 properties: {
58674 indicatorDisplayUnits: KPIStatusWithHistory.getProp_Indicator_DisplayUnits(dataView),
58675 indicatorPrecision: KPIStatusWithHistory.getProp_Indicator_Precision(dataView)
58676 }
58677 });
58678 case 'trendline':
58679 instances.push({
58680 selector: null,
58681 objectName: 'trendline',
58682 properties: {
58683 show: KPIStatusWithHistory.getProp_Show_KPITrendLine(dataView)
58684 }
58685 });
58686 case 'goals':
58687 instances.push({
58688 selector: null,
58689 objectName: 'goals',
58690 properties: {
58691 showGoal: KPIStatusWithHistory.getProp_Show_KPIGoal(dataView),
58692 showDistance: KPIStatusWithHistory.getProp_Show_KPIDistance(dataView)
58693 }
58694 });
58695 case 'status':
58696 instances.push({
58697 selector: null,
58698 objectName: 'status',
58699 properties: {
58700 direction: KPIStatusWithHistory.getProp_KPIDirection(dataView)
58701 }
58702 });
58703 }
58704 return instances;
58705 };
58706 KPIStatusWithHistory.prototype.destroy = function () {
58707 this.svg = null;
58708 };
58709 KPIStatusWithHistory.directionTypeStringProp = { objectName: 'status', propertyName: 'direction' };
58710 KPIStatusWithHistory.showKPIGoal = { objectName: 'goals', propertyName: 'showGoal' };
58711 KPIStatusWithHistory.showKPIDistance = { objectName: 'goals', propertyName: 'showDistance' };
58712 KPIStatusWithHistory.showKPITrendLine = { objectName: 'trendline', propertyName: 'show' };
58713 KPIStatusWithHistory.indicatorDisplayUnitsProp = { objectName: 'indicator', propertyName: 'indicatorDisplayUnits' };
58714 KPIStatusWithHistory.indicatorPrecisionProp = { objectName: 'indicator', propertyName: 'indicatorPrecision' };
58715 KPIStatusWithHistory.status = { INCREASE: "increase", DROP: "drop", IN_BETWEEN: "in-between", NOGOAL: "no-goal" };
58716 KPIStatusWithHistory.statusBandingType = { Below: "BELOW", Above: "ABOVE" };
58717 KPIStatusWithHistory.actualTextConsts = { VERTICAL_OFFSET_FROM_HALF_HEIGHT: 20, FONT_WIDTH_FACTOR: 14, RIGHT_MARGIN: 10 };
58718 KPIStatusWithHistory.kpiRedClass = 'kpi-visual-red';
58719 KPIStatusWithHistory.kpiYellowClass = 'kpi-visual-yellow';
58720 KPIStatusWithHistory.kpiGreenClass = 'kpi-visual-green';
58721 KPIStatusWithHistory.kpiTextGreyClass = 'kpi-visual-text-grey';
58722 KPIStatusWithHistory.kpiGraphGreyClass = 'kpi-visual-graph-grey';
58723 KPIStatusWithHistory.allColorClasses = KPIStatusWithHistory.kpiRedClass + ' ' + KPIStatusWithHistory.kpiYellowClass + ' ' + KPIStatusWithHistory.kpiGreenClass + ' ' + KPIStatusWithHistory.kpiTextGreyClass + ' ' + KPIStatusWithHistory.kpiGraphGreyClass;
58724 KPIStatusWithHistory.trendAreaFilePercentage = 1;
58725 KPIStatusWithHistory.estimatedIconHeightInPx = 9;
58726 KPIStatusWithHistory.indicatorTextSizeInPx = 60;
58727 return KPIStatusWithHistory;
58728 }());
58729 visuals.KPIStatusWithHistory = KPIStatusWithHistory;
58730 function GetStatus(actual, goals, directionType) {
58731 if (!goals || goals.length === 0) {
58732 return KPIStatusWithHistory.status.NOGOAL;
58733 }
58734 var maxGoal, minGoal;
58735 if (goals.length === 2) {
58736 maxGoal = Math.max.apply(Math, goals);
58737 minGoal = Math.min.apply(Math, goals);
58738 if (actual >= minGoal && actual <= maxGoal) {
58739 return KPIStatusWithHistory.status.IN_BETWEEN;
58740 }
58741 }
58742 else {
58743 maxGoal = goals[0];
58744 minGoal = goals[0];
58745 }
58746 switch (directionType) {
58747 case visuals.kpiDirection.positive:
58748 if (actual < minGoal) {
58749 return KPIStatusWithHistory.status.DROP;
58750 }
58751 break;
58752 case visuals.kpiDirection.negative:
58753 if (actual > maxGoal) {
58754 return KPIStatusWithHistory.status.DROP;
58755 }
58756 break;
58757 default:
58758 break;
58759 }
58760 return KPIStatusWithHistory.status.INCREASE;
58761 }
58762 function getDistanceFromGoalInPercentageString(actual, goals, directionType) {
58763 if (!goals || goals.length !== 1 || goals[0] === 0) {
58764 return "";
58765 }
58766 var sign = "+";
58767 var distance;
58768 var goal = goals[0];
58769 distance = Math.abs(actual - goal);
58770 switch (directionType) {
58771 case visuals.kpiDirection.positive:
58772 if (actual < goal) {
58773 sign = "-";
58774 }
58775 break;
58776 case visuals.kpiDirection.negative:
58777 if (actual > goal) {
58778 sign = "-";
58779 }
58780 break;
58781 }
58782 var percent = Number((100 * distance / goal).toFixed(2));
58783 return "(" + sign + percent + "%)";
58784 }
58785 function GetTextColorClassByStatus(status) {
58786 switch (status) {
58787 case KPIStatusWithHistory.status.NOGOAL:
58788 return KPIStatusWithHistory.kpiTextGreyClass;
58789 case KPIStatusWithHistory.status.INCREASE:
58790 return KPIStatusWithHistory.kpiGreenClass;
58791 case KPIStatusWithHistory.status.IN_BETWEEN:
58792 return KPIStatusWithHistory.kpiYellowClass;
58793 case KPIStatusWithHistory.status.DROP:
58794 return KPIStatusWithHistory.kpiRedClass;
58795 }
58796 }
58797 function GetGraphColorClassByStatus(status) {
58798 switch (status) {
58799 case KPIStatusWithHistory.status.NOGOAL:
58800 return KPIStatusWithHistory.kpiGraphGreyClass;
58801 case KPIStatusWithHistory.status.INCREASE:
58802 return KPIStatusWithHistory.kpiGreenClass;
58803 case KPIStatusWithHistory.status.IN_BETWEEN:
58804 return KPIStatusWithHistory.kpiYellowClass;
58805 case KPIStatusWithHistory.status.DROP:
58806 return KPIStatusWithHistory.kpiRedClass;
58807 }
58808 }
58809 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
58810})(powerbi || (powerbi = {}));
58811/*
58812 * Power BI Visualizations
58813 *
58814 * Copyright (c) Microsoft Corporation
58815 * All rights reserved.
58816 * MIT License
58817 *
58818 * Permission is hereby granted, free of charge, to any person obtaining a copy
58819 * of this software and associated documentation files (the ""Software""), to deal
58820 * in the Software without restriction, including without limitation the rights
58821 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58822 * copies of the Software, and to permit persons to whom the Software is
58823 * furnished to do so, subject to the following conditions:
58824 *
58825 * The above copyright notice and this permission notice shall be included in
58826 * all copies or substantial portions of the Software.
58827 *
58828 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58829 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
58830 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58831 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58832 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58833 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58834 * THE SOFTWARE.
58835 */
58836var powerbi;
58837(function (powerbi) {
58838 var visuals;
58839 (function (visuals) {
58840 var EnumExtensions = jsCommon.EnumExtensions;
58841 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
58842 var PixelConverter = jsCommon.PixelConverter;
58843 ;
58844 /**
58845 * Renders a data series as a line visual.
58846 */
58847 var LineChart = (function () {
58848 function LineChart(options) {
58849 var _this = this;
58850 this.deferDragMoveOperation = jsCommon.DeferUtility.deferUntilNextFrame(function () {
58851 if (_this.lastDragMoveXPosition) {
58852 var index = _this.findIndex(_this.lastDragMoveXPosition - _this.margin.left);
58853 _this.selectColumn(index);
58854 _this.lastDragMoveXPosition = undefined;
58855 }
58856 });
58857 this.isScrollable = options.isScrollable ? options.isScrollable : false;
58858 this.tooltipsEnabled = options.tooltipsEnabled;
58859 this.lineType = options.chartType ? options.chartType : 1 /* default */;
58860 this.interactivityService = options.interactivityService;
58861 this.animator = options.animator;
58862 this.lineChartLabelDensityEnabled = options.lineChartLabelDensityEnabled;
58863 this.lineClassAndSelector = LineChart.LineClassSelector;
58864 }
58865 LineChart.customizeQuery = function (options) {
58866 var dataViewMapping = options.dataViewMappings[0];
58867 if (!dataViewMapping || !dataViewMapping.categorical || !dataViewMapping.categorical.categories)
58868 return;
58869 dataViewMapping.categorical.dataVolume = 4;
58870 if (visuals.CartesianChart.detectScalarMapping(dataViewMapping)) {
58871 var dataViewCategories = dataViewMapping.categorical.categories;
58872 dataViewCategories.dataReductionAlgorithm = { sample: {} };
58873 }
58874 };
58875 LineChart.getSortableRoles = function (options) {
58876 var dataViewMapping = options.dataViewMappings[0];
58877 if (!dataViewMapping || !dataViewMapping.categorical || !dataViewMapping.categorical.categories)
58878 return null;
58879 var dataViewCategories = dataViewMapping.categorical.categories;
58880 var categoryItems = dataViewCategories.for.in.items;
58881 if (!_.isEmpty(categoryItems)) {
58882 var categoryType = categoryItems[0].type;
58883 var objects = void 0;
58884 if (dataViewMapping.metadata)
58885 objects = dataViewMapping.metadata.objects;
58886 //TODO: line chart should be sortable by X if it has scalar axis
58887 // But currently it doesn't support this. Always return 'category'
58888 // once it is supported.
58889 if (!visuals.CartesianChart.getIsScalar(objects, visuals.lineChartProps.categoryAxis.axisType, categoryType))
58890 return ['Category', 'Y'];
58891 }
58892 return null;
58893 };
58894 LineChart.converter = function (dataView, blankCategoryValue, colors, isScalar, interactivityService, shouldCalculateStacked, isComboChart, tooltipsEnabled) {
58895 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
58896 var reader = powerbi.data.createIDataViewCategoricalReader(dataView);
58897 var valueRoleName = isComboChart ? "Y2" : "Y";
58898 var categorical = dataView.categorical;
58899 var category = categorical.categories && categorical.categories.length > 0
58900 ? categorical.categories[0]
58901 : {
58902 source: undefined,
58903 values: [blankCategoryValue],
58904 identity: undefined,
58905 };
58906 var xAxisCardProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataView.metadata);
58907 isScalar = visuals.CartesianHelper.isScalar(isScalar, xAxisCardProperties);
58908 categorical = visuals.ColumnUtil.applyUserMinMax(isScalar, categorical, xAxisCardProperties);
58909 var formatStringProp = visuals.lineChartProps.general.formatString;
58910 var categoryType = visuals.AxisHelper.getCategoryValueType(category.source, isScalar);
58911 var isDateTime = visuals.AxisHelper.isDateTime(categoryType);
58912 var categoryValues = category.values;
58913 var categoryData = [];
58914 var series = [];
58915 var seriesLen = categorical.values ? categorical.values.length : 0;
58916 var hasDynamicSeries = !!(categorical.values && categorical.values.source);
58917 var values = categorical.values;
58918 var defaultLabelSettings = visuals.dataLabelUtils.getDefaultLineChartLabelSettings(isComboChart);
58919 var defaultSeriesColor;
58920 if (dataView.metadata && dataView.metadata.objects) {
58921 var objects = dataView.metadata.objects;
58922 // If the line layer is in a combo chart, the "Default Column Color" slice's value (lineChartProps.dataPoint.defaultColor) will not affect the line series as well
58923 defaultSeriesColor = isComboChart ? undefined : powerbi.DataViewObjects.getFillColor(objects, visuals.lineChartProps.dataPoint.defaultColor);
58924 var labelsObj = objects['labels'];
58925 visuals.dataLabelUtils.updateLineChartLabelSettingsFromLabelsObject(labelsObj, defaultLabelSettings);
58926 }
58927 var colorHelper = new visuals.ColorHelper(colors, visuals.lineChartProps.dataPoint.fill, defaultSeriesColor);
58928 var grouped;
58929 if (dataView.categorical.values)
58930 grouped = dataView.categorical.values.grouped();
58931 var stackedValues;
58932 if (shouldCalculateStacked) {
58933 //initialize array with zeros
58934 stackedValues = categorical.values && categorical.values.length > 0 ? _.times(categorical.values[0].values.length, function () { return 0; }) : [];
58935 }
58936 for (var seriesIndex = 0; seriesIndex < seriesLen; seriesIndex++) {
58937 var column = categorical.values[seriesIndex];
58938 var valuesMetadata = column.source;
58939 var dataPoints = [];
58940 var groupedIdentity = grouped[seriesIndex];
58941 var identity = hasDynamicSeries && groupedIdentity
58942 ? visuals.SelectionId.createWithIdAndMeasure(groupedIdentity.identity, column.source.queryName)
58943 : visuals.SelectionId.createWithMeasure(column.source.queryName);
58944 var key = identity.getKey();
58945 var color = this.getColor(colorHelper, hasDynamicSeries, values, grouped, seriesIndex, groupedIdentity);
58946 var seriesLabelSettings = void 0;
58947 if (!hasDynamicSeries) {
58948 var labelsSeriesGroup = grouped && grouped.length > 0 && grouped[0].values ? grouped[0].values[seriesIndex] : null;
58949 var labelObjects = (labelsSeriesGroup && labelsSeriesGroup.source && labelsSeriesGroup.source.objects) ? labelsSeriesGroup.source.objects['labels'] : null;
58950 if (labelObjects) {
58951 seriesLabelSettings = powerbi.Prototype.inherit(defaultLabelSettings);
58952 visuals.dataLabelUtils.updateLineChartLabelSettingsFromLabelsObject(labelObjects, seriesLabelSettings);
58953 }
58954 }
58955 var dataPointLabelSettings = (seriesLabelSettings) ? seriesLabelSettings : defaultLabelSettings;
58956 var useHighlightValues = column.highlights && column.highlights.length > 0;
58957 var categoryCount = reader.hasCategories() ? reader.getCategoryCount() : 1;
58958 // NOTE: line capabilities don't allow highlights, but comboChart does - so only use highlight values if we are in "combo" mode
58959 for (var categoryIndex = 0; categoryIndex < categoryCount; categoryIndex++) {
58960 var categoryValue = categoryValues[categoryIndex];
58961 var value = visuals.AxisHelper.normalizeNonFiniteNumber(useHighlightValues ? reader.getHighlight(valueRoleName, categoryIndex, seriesIndex) : reader.getValue(valueRoleName, categoryIndex, seriesIndex));
58962 // When Scalar, skip null categories and null values so we draw connected lines and never draw isolated dots.
58963 if (isScalar && (categoryValue == null || value == null))
58964 continue;
58965 // ignore variant measures
58966 if (isDateTime && categoryValue != null && !(categoryValue instanceof Date))
58967 continue;
58968 var categorical_1 = dataView.categorical;
58969 var tooltipInfo = void 0;
58970 if (tooltipsEnabled) {
58971 // This tooltip is using in combo chart and mobile tooltip.
58972 tooltipInfo = [];
58973 if (category.source) {
58974 tooltipInfo.push({
58975 displayName: category.source.displayName,
58976 value: visuals.converterHelper.formatFromMetadataColumn(categoryValue, category.source, formatStringProp),
58977 });
58978 }
58979 // This dynamicSeries tooltip is only using in mobile tooltip.
58980 if (hasDynamicSeries) {
58981 if (!category.source || category.source !== categorical_1.values.source) {
58982 // Category/series on the same column -- don't repeat its value in the tooltip.
58983 tooltipInfo.push({
58984 displayName: categorical_1.values.source.displayName,
58985 value: visuals.converterHelper.formatFromMetadataColumn(grouped[seriesIndex].name, categorical_1.values.source, formatStringProp),
58986 });
58987 }
58988 }
58989 if (value != null) {
58990 tooltipInfo.push({
58991 displayName: valuesMetadata.displayName,
58992 value: visuals.converterHelper.formatFromMetadataColumn(value, valuesMetadata, formatStringProp),
58993 });
58994 }
58995 }
58996 var categoryKey = category && !_.isEmpty(category.identity) && category.identity[categoryIndex] ? category.identity[categoryIndex].key : categoryIndex;
58997 var dataPoint = {
58998 categoryValue: isDateTime && categoryValue ? categoryValue.getTime() : categoryValue,
58999 value: value,
59000 categoryIndex: categoryIndex,
59001 seriesIndex: seriesIndex,
59002 tooltipInfo: tooltipInfo,
59003 selected: false,
59004 identity: identity,
59005 key: JSON.stringify({ series: key, category: categoryKey }),
59006 labelFill: dataPointLabelSettings.labelColor,
59007 labelFormatString: valuesMetadata.format,
59008 labelSettings: dataPointLabelSettings
59009 };
59010 if (shouldCalculateStacked) {
59011 stackedValues[categoryIndex] += value;
59012 dataPoint.stackedValue = stackedValues[categoryIndex];
59013 }
59014 if (category.objects && category.objects[categoryIndex]) {
59015 dataPoint['pointColor'] = powerbi.DataViewObjects.getFillColor(category.objects[categoryIndex], visuals.lineChartProps.dataPoint.fill);
59016 }
59017 dataPoints.push(dataPoint);
59018 if (!categoryData[categoryIndex]) {
59019 categoryData[categoryIndex] = dataPoint;
59020 }
59021 }
59022 if (interactivityService) {
59023 interactivityService.applySelectionStateToData(dataPoints);
59024 }
59025 if (dataPoints.length > 0) {
59026 series.push({
59027 displayName: valuesMetadata.displayName,
59028 key: key,
59029 lineIndex: seriesIndex,
59030 color: color,
59031 xCol: category.source,
59032 yCol: column.source,
59033 data: dataPoints,
59034 identity: identity,
59035 selected: false,
59036 labelSettings: seriesLabelSettings,
59037 });
59038 }
59039 }
59040 xAxisCardProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataView.metadata);
59041 var valueAxisProperties = visuals.CartesianHelper.getValueAxisProperties(dataView.metadata);
59042 // Convert to DataViewMetadataColumn
59043 var valuesMetadataArray = [];
59044 if (values) {
59045 for (var i = 0; i < values.length; i++) {
59046 if (values[i] && values[i].source && values[i].source.displayName) {
59047 valuesMetadataArray.push({ displayName: values[i].source.displayName });
59048 }
59049 }
59050 }
59051 var axesLabels = visuals.converterHelper.createAxesLabels(xAxisCardProperties, valueAxisProperties, category.source, valuesMetadataArray);
59052 if (interactivityService) {
59053 interactivityService.applySelectionStateToData(series);
59054 }
59055 return {
59056 series: series,
59057 isScalar: isScalar,
59058 dataLabelsSettings: defaultLabelSettings,
59059 axesLabels: { x: axesLabels.xAxisLabel, y: axesLabels.yAxisLabel },
59060 hasDynamicSeries: hasDynamicSeries,
59061 categoryMetadata: category.source,
59062 categories: categoryValues,
59063 categoryData: categoryData,
59064 };
59065 };
59066 LineChart.getInteractiveLineChartDomElement = function (element) {
59067 return element.children("svg").get(0);
59068 };
59069 LineChart.getColor = function (colorHelper, hasDynamicSeries, values, grouped, seriesIndex, groupedIdentity) {
59070 var objects;
59071 if (hasDynamicSeries) {
59072 if (grouped && grouped[seriesIndex])
59073 objects = grouped[seriesIndex].objects;
59074 }
59075 else if (values[seriesIndex]) {
59076 objects = values[seriesIndex].source.objects;
59077 }
59078 return hasDynamicSeries && groupedIdentity
59079 ? colorHelper.getColorForSeriesValue(objects, values.identityFields, groupedIdentity.name)
59080 : colorHelper.getColorForMeasure(objects, values[seriesIndex].source.queryName);
59081 };
59082 LineChart.createStackedValueDomain = function (data) {
59083 debug.assertValue(data, 'data');
59084 if (data.length === 0)
59085 return null;
59086 var minY = d3.min(data, function (kv) { return d3.min(kv.data, function (d) { return d.stackedValue; }); });
59087 var maxY = d3.max(data, function (kv) { return d3.max(kv.data, function (d) { return d.stackedValue; }); });
59088 return [minY, maxY];
59089 };
59090 LineChart.prototype.init = function (options) {
59091 var _this = this;
59092 this.options = options;
59093 this.element = options.element;
59094 this.cartesainSVG = options.svg;
59095 this.host = options.host;
59096 this.currentViewport = options.viewport;
59097 this.colors = options.style.colorPalette.dataColors;
59098 this.isInteractiveChart = options.interactivity && options.interactivity.isInteractiveLegend;
59099 this.cartesianVisualHost = options.cartesianHost;
59100 this.scaleDetector = new visuals.SVGScaleDetector(this.cartesainSVG);
59101 var chartType = options.chartType;
59102 this.isComboChart = chartType === 10 /* ComboChart */ || chartType === 13 /* LineClusteredColumnCombo */ || chartType === 14 /* LineStackedColumnCombo */;
59103 var svg = options.svg;
59104 svg.classed(LineChart.ClassName, true);
59105 var graphicsContextParent = this.mainGraphicsSVG = svg.append('svg')
59106 .classed('lineChartSVG', true);
59107 if (!this.isComboChart && !this.isInteractiveChart) {
59108 this.overlayRect = graphicsContextParent
59109 .append(LineChart.RectOverlayName)
59110 .style("opacity", visuals.SVGUtil.AlmostZero);
59111 }
59112 this.mainGraphicsContext = graphicsContextParent
59113 .append('g')
59114 .classed(LineChart.MainGraphicsContextClassName, true);
59115 this.hoverLineContext = svg.append('g')
59116 .classed('hover-line', true);
59117 this.hoverLineContext.append(LineChart.LineElementName)
59118 .attr("x1", 0).attr("x2", 0)
59119 .attr("y1", 0).attr("y2", 0);
59120 var hoverLine = this.hoverLine = this.hoverLineContext.select(LineChart.LineElementName);
59121 if (this.isInteractiveChart) {
59122 hoverLine.classed('interactive', true);
59123 }
59124 hoverLine.style('opacity', visuals.SVGUtil.AlmostZero);
59125 // define circles object - which will hold the handle circles.
59126 // this object will be populated on render() function, with number of circles which matches the nubmer of lines.
59127 this.selectionCircles = [];
59128 this.xAxisProperties = {
59129 axis: null,
59130 scale: null,
59131 isScalar: null,
59132 axisType: null,
59133 formatter: null,
59134 graphicsContext: null,
59135 values: null,
59136 axisLabel: null,
59137 isCategoryAxis: true
59138 };
59139 if (this.isInteractiveChart) {
59140 var rootSvg_1 = LineChart.getInteractiveLineChartDomElement(this.element);
59141 var dragMove = function () {
59142 _this.lastDragMoveXPosition = d3.mouse(rootSvg_1)[0];
59143 _this.deferDragMoveOperation();
59144 };
59145 // assign drag and onClick events
59146 var drag = d3.behavior.drag()
59147 .origin(Object)
59148 .on("drag", dragMove);
59149 d3.select(rootSvg_1)
59150 .style('touch-action', 'none')
59151 .call(drag)
59152 .on('click', dragMove);
59153 }
59154 // Internet Explorer and Edge use the stroke edge, not the path edge for the mouse coordinate's origin.
59155 // We need to adjust mouse events on the interactivity lines to account for this.
59156 this.shouldAdjustMouseCoordsOnPathsForStroke = !jsCommon.BrowserUtils.isChrome();
59157 };
59158 LineChart.prototype.setData = function (dataViews) {
59159 this.data = {
59160 series: [],
59161 dataLabelsSettings: visuals.dataLabelUtils.getDefaultLineChartLabelSettings(this.isComboChart),
59162 axesLabels: { x: null, y: null },
59163 hasDynamicSeries: false,
59164 categories: [],
59165 categoryMetadata: undefined,
59166 categoryData: [],
59167 };
59168 if (dataViews.length > 0) {
59169 var dataView = dataViews[0];
59170 if (dataView) {
59171 if (dataView.categorical) {
59172 var dataViewCat = this.dataViewCat = dataView.categorical;
59173 var dvCategories = dataViewCat.categories;
59174 var categoryType = powerbi.ValueType.fromDescriptor({ text: true });
59175 if (dvCategories && dvCategories.length > 0 && dvCategories[0].source && dvCategories[0].source.type)
59176 categoryType = dvCategories[0].source.type;
59177 var convertedData = LineChart.converter(dataView, visuals.valueFormatter.format(null), this.cartesianVisualHost.getSharedColors(), visuals.CartesianChart.getIsScalar(dataView.metadata ? dataView.metadata.objects : null, visuals.lineChartProps.categoryAxis.axisType, categoryType), this.interactivityService, EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */), this.isComboChart);
59178 this.data = convertedData;
59179 }
59180 }
59181 }
59182 };
59183 LineChart.prototype.calculateLegend = function () {
59184 return this.createLegendDataPoints(0); // start with index 0
59185 };
59186 LineChart.prototype.hasLegend = function () {
59187 return this.data && (this.data.hasDynamicSeries || (this.data.series && this.data.series.length > 1));
59188 };
59189 LineChart.prototype.setFilteredData = function (startIndex, endIndex) {
59190 var catgSize = endIndex - startIndex;
59191 var data = this.clippedData = powerbi.Prototype.inherit(this.data);
59192 data.series = LineChart.sliceSeries(data.series, catgSize, startIndex);
59193 data.categories = data.categories.slice(startIndex, endIndex);
59194 return data;
59195 };
59196 LineChart.prototype.calculateAxesProperties = function (options) {
59197 var _this = this;
59198 var data = this.data;
59199 var viewport = options.viewport;
59200 var margin = options.margin;
59201 this.currentViewport = viewport;
59202 this.margin = margin;
59203 var origCatgSize = data.series && data.series.length > 0 ? data.series[0].data.length : 0;
59204 var categoryWidth = visuals.CartesianChart.MinOrdinalRectThickness;
59205 var isScalar = this.data.isScalar;
59206 var trimOrdinalDataOnOverflow = options.trimOrdinalDataOnOverflow;
59207 var preferredPlotArea = this.getPreferredPlotArea(isScalar, origCatgSize, categoryWidth);
59208 this.clippedData = undefined;
59209 if (data && !isScalar && !this.isScrollable && trimOrdinalDataOnOverflow) {
59210 // trim data that doesn't fit on dashboard
59211 var categoryCount = this.getCategoryCount(origCatgSize);
59212 var catgSize = Math.min(origCatgSize, categoryCount);
59213 if (catgSize !== origCatgSize) {
59214 data = this.clippedData = powerbi.Prototype.inherit(data);
59215 this.clippedData.series = LineChart.sliceSeries(data.series, catgSize);
59216 }
59217 }
59218 var xMetaDataColumn;
59219 var yMetaDataColumn;
59220 if (data.series && data.series.length > 0) {
59221 xMetaDataColumn = data.series[0].xCol;
59222 yMetaDataColumn = data.series[0].yCol;
59223 }
59224 var valueDomain = EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */) ? LineChart.createStackedValueDomain(data.series) : visuals.AxisHelper.createValueDomain(data.series, false);
59225 var hasZeroValueInYDomain = options.valueAxisScaleType === visuals.axisScale.log && !visuals.AxisHelper.isLogScalePossible(valueDomain);
59226 var combinedDomain = visuals.AxisHelper.combineDomain(options.forcedYDomain, valueDomain, options.ensureYDomain);
59227 this.yAxisProperties = visuals.AxisHelper.createAxis({
59228 pixelSpan: preferredPlotArea.height,
59229 dataDomain: combinedDomain,
59230 metaDataColumn: yMetaDataColumn,
59231 formatString: visuals.valueFormatter.getFormatString(yMetaDataColumn, visuals.lineChartProps.general.formatString),
59232 outerPadding: 0,
59233 isScalar: true,
59234 isVertical: true,
59235 forcedTickCount: options.forcedTickCount,
59236 useTickIntervalForDisplayUnits: true,
59237 isCategoryAxis: false,
59238 scaleType: options.valueAxisScaleType,
59239 axisDisplayUnits: options.valueAxisDisplayUnits,
59240 axisPrecision: options.valueAxisPrecision,
59241 shouldClamp: false,
59242 });
59243 var metaDataColumn = this.data ? this.data.categoryMetadata : undefined;
59244 var categoryDataType = visuals.AxisHelper.getCategoryValueType(metaDataColumn);
59245 var xDomain = visuals.AxisHelper.createDomain(data.series, categoryDataType, this.data.isScalar, options.forcedXDomain, options.ensureXDomain);
59246 var hasZeroValueInXDomain = options.categoryAxisScaleType === visuals.axisScale.log && !visuals.AxisHelper.isLogScalePossible(xDomain);
59247 this.xAxisProperties = visuals.AxisHelper.createAxis({
59248 pixelSpan: preferredPlotArea.width,
59249 dataDomain: xDomain,
59250 metaDataColumn: xMetaDataColumn,
59251 formatString: visuals.valueFormatter.getFormatString(xMetaDataColumn, visuals.lineChartProps.general.formatString),
59252 outerPadding: this.data.isScalar ? LineChart.ScalarOuterPadding : 0,
59253 isScalar: this.data.isScalar,
59254 isVertical: false,
59255 forcedTickCount: options.forcedTickCount,
59256 useTickIntervalForDisplayUnits: true,
59257 getValueFn: function (index, type) { return visuals.CartesianHelper.lookupXValue(_this.data, index, type, _this.data.isScalar); },
59258 categoryThickness: visuals.CartesianChart.getCategoryThickness(data.series, origCatgSize, this.getAvailableWidth(), xDomain, isScalar, trimOrdinalDataOnOverflow),
59259 isCategoryAxis: true,
59260 scaleType: options.categoryAxisScaleType,
59261 axisDisplayUnits: options.categoryAxisDisplayUnits,
59262 axisPrecision: options.categoryAxisPrecision
59263 });
59264 this.xAxisProperties.axisLabel = options.showCategoryAxisLabel ? data.axesLabels.x : null;
59265 this.yAxisProperties.axisLabel = options.showValueAxisLabel ? data.axesLabels.y : null;
59266 this.xAxisProperties.hasDisallowedZeroInDomain = hasZeroValueInXDomain;
59267 this.yAxisProperties.hasDisallowedZeroInDomain = hasZeroValueInYDomain;
59268 return [this.xAxisProperties, this.yAxisProperties];
59269 };
59270 LineChart.prototype.enumerateObjectInstances = function (enumeration, options) {
59271 switch (options.objectName) {
59272 case 'dataPoint':
59273 this.enumerateDataPoints(enumeration);
59274 break;
59275 case 'labels':
59276 this.enumerateDataLabels(enumeration);
59277 break;
59278 }
59279 };
59280 LineChart.prototype.enumerateDataPoints = function (enumeration) {
59281 var data = this.data;
59282 if (!data || !data.series || data.series.length === 0)
59283 return;
59284 var formatStringProp = visuals.lineChartProps.general.formatString;
59285 var singleSeriesData = data.series;
59286 var seriesLength = singleSeriesData.length;
59287 for (var i = 0; i < seriesLength; i++) {
59288 var selector = visuals.ColorHelper.normalizeSelector(singleSeriesData[i].identity.getSelector());
59289 var label = visuals.converterHelper.getFormattedLegendLabel(singleSeriesData[i].yCol, this.dataViewCat.values, formatStringProp);
59290 enumeration.pushInstance({
59291 objectName: 'dataPoint',
59292 displayName: label,
59293 selector: selector,
59294 properties: {
59295 fill: { solid: { color: data.defaultSeriesColor || singleSeriesData[i].color } }
59296 },
59297 });
59298 }
59299 };
59300 LineChart.prototype.enumerateDataLabels = function (enumeration) {
59301 var data = this.data, labelSettings = this.data.dataLabelsSettings, seriesCount = data.series.length, showLabelPerSeries = this.showLabelPerSeries();
59302 //Draw default settings
59303 visuals.dataLabelUtils.enumerateDataLabels(this.getLabelSettingsOptions(enumeration, labelSettings, null, showLabelPerSeries));
59304 if (seriesCount === 0)
59305 return;
59306 //Draw series settings
59307 if (showLabelPerSeries && labelSettings.showLabelPerSeries) {
59308 for (var i = 0; i < seriesCount; i++) {
59309 var series = data.series[i], labelSettings_2 = (series.labelSettings) ? series.labelSettings : this.data.dataLabelsSettings;
59310 enumeration.pushContainer({ displayName: series.displayName });
59311 visuals.dataLabelUtils.enumerateDataLabels(this.getLabelSettingsOptions(enumeration, labelSettings_2, series));
59312 enumeration.popContainer();
59313 }
59314 }
59315 };
59316 LineChart.prototype.supportsTrendLine = function () {
59317 var isScalar = this.data ? this.data.isScalar : false;
59318 return !EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */) && isScalar;
59319 };
59320 LineChart.prototype.getLabelSettingsOptions = function (enumeration, labelSettings, series, showAll) {
59321 return {
59322 enumeration: enumeration,
59323 dataLabelsSettings: labelSettings,
59324 show: true,
59325 displayUnits: true,
59326 precision: true,
59327 selector: series && series.identity ? series.identity.getSelector() : null,
59328 showAll: showAll,
59329 fontSize: true,
59330 labelDensity: this.lineChartLabelDensityEnabled,
59331 };
59332 };
59333 LineChart.prototype.overrideXScale = function (xProperties) {
59334 this.xAxisProperties = xProperties;
59335 };
59336 LineChart.prototype.onClearSelection = function () {
59337 if (this.interactivityService)
59338 this.interactivityService.clearSelection();
59339 };
59340 LineChart.prototype.render = function (suppressAnimations) {
59341 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
59342 if (this.data.categoryData.length !== this.previousCategoryCount) {
59343 duration = 0;
59344 }
59345 this.previousCategoryCount = this.data.categoryData.length;
59346 var result;
59347 if (!this.isInteractiveChart)
59348 result = this.renderNew(duration);
59349 else
59350 result = this.renderOld(duration);
59351 // This should always be the last line in the render code.
59352 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
59353 return result;
59354 };
59355 LineChart.prototype.renderNew = function (duration) {
59356 var _this = this;
59357 var data = this.clippedData ? this.clippedData : this.data;
59358 if (!data)
59359 return;
59360 var dataPointCount = data.categories.length * data.series.length;
59361 if (dataPointCount > visuals.AnimatorCommon.MaxDataPointsToAnimate) {
59362 // Too many data points to animate.
59363 duration = 0;
59364 }
59365 var isStackedArea = EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */);
59366 var margin = this.margin;
59367 var viewport = this.currentViewport;
59368 var height = viewport.height - (margin.top + margin.bottom);
59369 var width = viewport.width - (margin.left + margin.right);
59370 var xScale = this.xAxisProperties.scale;
59371 var yScale = this.yAxisProperties.scale;
59372 var horizontalOffset = this.getXOfFirstCategory();
59373 var hasSelection = this.interactivityService && this.interactivityService.hasSelection();
59374 var renderAreas = EnumExtensions.hasFlag(this.lineType, 2 /* area */) || EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */);
59375 var xPosition = function (d) { return xScale(_this.getXValue(d)) + horizontalOffset; };
59376 var y0Position, yPosition;
59377 if (isStackedArea) {
59378 y0Position = function (d) { return yScale(d.stackedValue - d.value); };
59379 yPosition = function (d) { return yScale(d.stackedValue); };
59380 }
59381 else {
59382 y0Position = yScale(0);
59383 yPosition = function (d) { return yScale(d.value); };
59384 }
59385 var area;
59386 if (renderAreas) {
59387 area = d3.svg.area()
59388 .x(xPosition)
59389 .y0(y0Position)
59390 .y1(yPosition)
59391 .defined(function (d) { return d.value !== null; });
59392 }
59393 var line = d3.svg.line()
59394 .x(xPosition)
59395 .y(yPosition)
59396 .defined(function (d) {
59397 return d.value !== null;
59398 });
59399 if (EnumExtensions.hasFlag(this.lineType, 4 /* smooth */)) {
59400 line.interpolate('basis');
59401 if (area) {
59402 area.interpolate('basis');
59403 }
59404 }
59405 this.mainGraphicsSVG
59406 .attr('height', height)
59407 .attr('width', width);
59408 var areas = undefined;
59409 // Render Areas
59410 if (renderAreas) {
59411 areas = this.mainGraphicsContext.selectAll(LineChart.CategoryAreaSelector.selector).data(data.series, function (d) { return d.identity.getKey(); });
59412 areas.enter()
59413 .append(LineChart.PathElementName)
59414 .classed(LineChart.CategoryAreaSelector.class, true);
59415 areas
59416 .style('fill', function (d) { return d.color; })
59417 .style('fill-opacity', function (d) { return (hasSelection && !d.selected) ? LineChart.DimmedAreaFillOpacity : LineChart.AreaFillOpacity; })
59418 .transition()
59419 .ease('linear')
59420 .duration(duration)
59421 .attr('d', function (d) { return area(d.data); });
59422 areas.exit()
59423 .remove();
59424 }
59425 // Render Lines
59426 var lines = this.mainGraphicsContext.selectAll(this.lineClassAndSelector.selector).data(data.series, function (d) { return d.identity.getKey(); });
59427 lines.enter()
59428 .append(LineChart.PathElementName)
59429 .classed(this.lineClassAndSelector.class, true);
59430 lines
59431 .style('stroke', function (d) { return d.color; })
59432 .style('stroke-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); })
59433 .transition()
59434 .ease('linear')
59435 .duration(duration)
59436 .attr('d', function (d) {
59437 return line(d.data);
59438 });
59439 lines.exit()
59440 .remove();
59441 // Render extra lines that are wider and invisible used for better interactivity
59442 var interactivityLines;
59443 if (this.interactivityService) {
59444 interactivityLines = this.mainGraphicsContext.selectAll(".interactivity-line").data(data.series, function (d) { return d.identity.getKey(); });
59445 interactivityLines.enter()
59446 .append(LineChart.PathElementName)
59447 .classed('interactivity-line', true)
59448 .style('stroke-width', LineChart.interactivityStrokeWidth);
59449 interactivityLines
59450 .attr('d', function (d) {
59451 return line(d.data);
59452 });
59453 interactivityLines.exit()
59454 .remove();
59455 }
59456 // Prepare grouping for dots
59457 var dotGroups = this.mainGraphicsContext.selectAll(LineChart.CategorySelector.selector)
59458 .data(data.series, function (d) { return d.identity.getKey(); });
59459 dotGroups.enter()
59460 .append('g')
59461 .classed(LineChart.CategorySelector.class, true);
59462 dotGroups.exit()
59463 .remove();
59464 // Render dots
59465 var dots = dotGroups.selectAll(LineChart.CategoryValuePoint.selector)
59466 .data(function (series) {
59467 return series.data.filter(function (value, i) {
59468 return _this.shouldDrawCircle(series, i);
59469 });
59470 }, function (d) { return d.key; });
59471 dots.enter()
59472 .append(LineChart.CircleElementName)
59473 .classed(LineChart.CategoryValuePoint.class, true);
59474 dots
59475 .style('fill', function () {
59476 var lineSeries = d3.select(this.parentNode).datum();
59477 return lineSeries.color;
59478 })
59479 .style('fill-opacity', function () {
59480 var lineSeries = d3.select(this.parentNode).datum();
59481 return visuals.ColumnUtil.getFillOpacity(lineSeries.selected, false, hasSelection, false);
59482 })
59483 .transition()
59484 .duration(duration)
59485 .attr({
59486 cx: function (d, i) { return xScale(_this.getXValue(d)) + horizontalOffset; },
59487 cy: function (d, i) { return yScale(isStackedArea ? d.stackedValue : d.value); },
59488 r: LineChart.CircleRadius
59489 });
59490 dots.exit()
59491 .remove();
59492 // Render explicit dots
59493 var explicitDots;
59494 if (!this.isComboChart) {
59495 explicitDots = dotGroups.selectAll(LineChart.CategoryPointSelector.selector)
59496 .data(function (series) {
59497 return _.filter(series.data, function (value) { return value.pointColor != null; });
59498 }, function (d) { return d.key; });
59499 explicitDots.enter()
59500 .append(LineChart.CircleElementName)
59501 .classed(LineChart.CategoryPointSelector.class, true);
59502 explicitDots
59503 .style('fill', function (d) { return d.pointColor; })
59504 .transition()
59505 .duration(duration)
59506 .attr({
59507 cx: function (d) { return xScale(_this.getXValue(d)); },
59508 cy: function (d) { return yScale(isStackedArea ? d.stackedValue : d.value); },
59509 r: LineChart.PointRadius
59510 });
59511 explicitDots.exit()
59512 .remove();
59513 }
59514 // Add data labels
59515 var labelDataPointsGroups;
59516 if (data.dataLabelsSettings.show)
59517 labelDataPointsGroups = this.createLabelDataPoints();
59518 if (this.tooltipsEnabled) {
59519 if (!this.isComboChart) {
59520 this.overlayRect
59521 .attr({
59522 x: 0,
59523 width: width,
59524 height: height
59525 });
59526 var seriesTooltipApplier = function (tooltipEvent) {
59527 var pointX = tooltipEvent.elementCoordinates[0];
59528 var index = _this.getCategoryIndexFromTooltipEvent(tooltipEvent, pointX);
59529 var categoryData = _this.selectColumnForTooltip(index);
59530 return _this.getSeriesTooltipInfo(categoryData);
59531 };
59532 var clearHoverLine = function () {
59533 _this.hoverLine.style('opacity', visuals.SVGUtil.AlmostZero);
59534 _this.hoverLineContext.selectAll(LineChart.HoverLineCircleDot.selector).remove();
59535 };
59536 visuals.TooltipManager.addTooltip(this.mainGraphicsSVG, seriesTooltipApplier, true, clearHoverLine);
59537 }
59538 else {
59539 var seriesTooltipApplier = function (tooltipEvent) {
59540 var pointX = tooltipEvent.elementCoordinates[0];
59541 return _this.getTooltipInfoForCombo(tooltipEvent, pointX);
59542 };
59543 if (interactivityLines)
59544 visuals.TooltipManager.addTooltip(interactivityLines, seriesTooltipApplier, true);
59545 visuals.TooltipManager.addTooltip(dots, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; }, true);
59546 if (explicitDots)
59547 visuals.TooltipManager.addTooltip(explicitDots, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; }, true);
59548 }
59549 }
59550 var dataPointsToBind = undefined;
59551 var behaviorOptions = undefined;
59552 if (this.interactivityService) {
59553 // Register interactivity
59554 dataPointsToBind = data.series.slice();
59555 for (var i = 0, ilen = data.series.length; i < ilen; i++) {
59556 dataPointsToBind = dataPointsToBind.concat(data.series[i].data);
59557 }
59558 behaviorOptions = {
59559 lines: lines,
59560 interactivityLines: interactivityLines,
59561 dots: dots,
59562 areas: areas,
59563 tooltipOverlay: this.overlayRect,
59564 };
59565 }
59566 return {
59567 dataPoints: dataPointsToBind,
59568 behaviorOptions: behaviorOptions,
59569 labelDataPoints: [],
59570 labelsAreNumeric: true,
59571 labelDataPointGroups: labelDataPointsGroups,
59572 };
59573 };
59574 LineChart.prototype.renderOld = function (duration) {
59575 var _this = this;
59576 var data = this.clippedData ? this.clippedData : this.data;
59577 if (!data)
59578 return;
59579 var margin = this.margin;
59580 var viewport = this.currentViewport;
59581 var height = viewport.height - (margin.top + margin.bottom);
59582 var xScale = this.xAxisProperties.scale;
59583 var yScale = this.yAxisProperties.scale;
59584 var hasSelection = this.interactivityService && this.interactivityService.hasSelection();
59585 var area;
59586 if (EnumExtensions.hasFlag(this.lineType, 2 /* area */)) {
59587 area = d3.svg.area()
59588 .x(function (d) { return xScale(_this.getXValue(d)); })
59589 .y0(height)
59590 .y1(function (d) { return yScale(d.value); })
59591 .defined(function (d) { return d.value !== null; });
59592 }
59593 var line = d3.svg.line()
59594 .x(function (d) {
59595 return xScale(_this.getXValue(d));
59596 })
59597 .y(function (d) {
59598 return yScale(d.value);
59599 })
59600 .defined(function (d) {
59601 return d.value !== null;
59602 });
59603 if (EnumExtensions.hasFlag(this.lineType, 4 /* smooth */)) {
59604 line.interpolate('basis');
59605 if (area) {
59606 area.interpolate('basis');
59607 }
59608 }
59609 var firstCategoryOffset = this.getXOfFirstCategory();
59610 this.mainGraphicsContext.attr('transform', visuals.SVGUtil.translate(firstCategoryOffset, 0));
59611 this.mainGraphicsSVG.attr('height', this.getAvailableHeight())
59612 .attr('width', this.getAvailableWidth());
59613 this.hoverLineContext.attr('transform', visuals.SVGUtil.translate(firstCategoryOffset, 0));
59614 if (EnumExtensions.hasFlag(this.lineType, 2 /* area */)) {
59615 var catAreaSelect = this.mainGraphicsContext.selectAll(LineChart.CategoryAreaSelector.selector)
59616 .data(data.series, function (d) { return d.identity.getKey(); });
59617 var catAreaEnter = catAreaSelect
59618 .enter().append('g')
59619 .classed(LineChart.CategoryAreaSelector.class, true);
59620 catAreaEnter.append(LineChart.PathElementName);
59621 var catAreaUpdate = this.mainGraphicsContext.selectAll(LineChart.CategoryAreaSelector.selector);
59622 catAreaUpdate.select(LineChart.PathElementName)
59623 .transition()
59624 .ease('linear')
59625 .duration(duration)
59626 .attr('d', function (d) { return area(d.data); })
59627 .style('fill', function (d) { return d.color; })
59628 .style('fill-opacity', function (d) { return (hasSelection && !d.selected) ? LineChart.DimmedAreaFillOpacity : LineChart.AreaFillOpacity; });
59629 catAreaSelect.exit().remove();
59630 }
59631 var catSelect = this.mainGraphicsContext.selectAll(LineChart.CategorySelector.selector)
59632 .data(data.series, function (d) { return d.identity.getKey(); });
59633 var catEnter = catSelect
59634 .enter()
59635 .append('g')
59636 .classed(LineChart.CategorySelector.class, true);
59637 catEnter.append(LineChart.PathElementName);
59638 catEnter.selectAll(LineChart.CategoryValuePoint.selector)
59639 .data(function (d) { return d.data; })
59640 .enter()
59641 .append(LineChart.CircleElementName)
59642 .classed(LineChart.CategoryValuePoint.class, true);
59643 // moving this up to avoid using the svg path generator with NaN values
59644 // do not move this without validating that no errors are thrown in the browser console
59645 catSelect.exit().remove();
59646 // add the drag handle, if needed
59647 if (this.isInteractiveChart && !this.dragHandle) {
59648 var handleTop = this.getAvailableHeight();
59649 this.dragHandle = this.hoverLineContext.append('circle')
59650 .attr('cx', 0)
59651 .attr('cy', handleTop)
59652 .attr('r', '6px')
59653 .classed('drag-handle', true);
59654 }
59655 // Create the selection circles
59656 var linesCount = catSelect.data().length; // number of lines plotted
59657 while (this.selectionCircles.length < linesCount) {
59658 var addedCircle = this.hoverLineContext.append(LineChart.CircleElementName)
59659 .classed(LineChart.CircleClassName, true)
59660 .attr('r', LineChart.CircleRadius).style('opacity', 0);
59661 this.selectionCircles.push(addedCircle);
59662 }
59663 while (this.selectionCircles.length > linesCount) {
59664 this.selectionCircles.pop().remove();
59665 }
59666 var catUpdate = this.mainGraphicsContext.selectAll(LineChart.CategorySelector.selector);
59667 var lineSelection = catUpdate.select(LineChart.PathElementName)
59668 .classed(this.lineClassAndSelector.class, true)
59669 .style('stroke', function (d) { return d.color; })
59670 .style('stroke-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); });
59671 lineSelection
59672 .transition()
59673 .ease('linear')
59674 .duration(duration)
59675 .attr('d', function (d) {
59676 return line(d.data);
59677 });
59678 var that = this;
59679 var updateSelection = catUpdate.selectAll(LineChart.CategoryValuePoint.selector);
59680 var transitions = updateSelection
59681 .style('fill', function () {
59682 var lineSeries = d3.select(this.parentNode).datum();
59683 return lineSeries.color;
59684 })
59685 .style('fill-opacity', function () {
59686 var lineSeries = d3.select(this.parentNode).datum();
59687 return visuals.ColumnUtil.getFillOpacity(lineSeries.selected, false, hasSelection, false);
59688 })
59689 .transition()
59690 .duration(duration)
59691 .attr({
59692 'cx': function (d, i) {
59693 var lineSeries = d3.select(this.parentNode).datum();
59694 var circleIndex = that.shouldDrawCircle(lineSeries, i);
59695 return circleIndex ? xScale(that.getXValue(d)) : 0;
59696 },
59697 'cy': function (d, i) {
59698 var lineSeries = d3.select(this.parentNode).datum();
59699 var circleIndex = that.shouldDrawCircle(lineSeries, i);
59700 return circleIndex ? yScale(d.value) : 0;
59701 },
59702 'r': function (d, i) {
59703 var lineSeries = d3.select(this.parentNode).datum();
59704 var circleIndex = that.shouldDrawCircle(lineSeries, i);
59705 return circleIndex ? LineChart.CircleRadius : 0;
59706 }
59707 });
59708 if (this.isInteractiveChart && this.hasDataPoint(data.series)) {
59709 var selectionSize_1 = updateSelection.size();
59710 var endedTransitionCount_1 = 0;
59711 transitions.each('end', function () {
59712 // When transitions finish, and it's an interactive chart - select the last column (draw the legend and the handle)
59713 endedTransitionCount_1++;
59714 if (endedTransitionCount_1 === selectionSize_1) {
59715 _this.selectColumn(visuals.CartesianHelper.findMaxCategoryIndex(data.series), true);
59716 }
59717 });
59718 }
59719 var dataPoints = null;
59720 if (data.dataLabelsSettings.show) {
59721 dataPoints = [];
59722 for (var i = 0, ilen = data.series.length; i < ilen; i++) {
59723 Array.prototype.push.apply(dataPoints, data.series[i].data);
59724 }
59725 }
59726 catSelect.exit().remove();
59727 // # Code from here is taken from renderNew:
59728 // Add data labels
59729 var labelDataPointsGroups;
59730 if (data.dataLabelsSettings.show)
59731 labelDataPointsGroups = this.createLabelDataPoints();
59732 return dataPoints == null ? null : {
59733 dataPoints: dataPoints,
59734 behaviorOptions: null,
59735 labelDataPoints: null,
59736 labelsAreNumeric: null,
59737 labelDataPointGroups: labelDataPointsGroups
59738 };
59739 };
59740 /**
59741 * Note: Public for tests.
59742 */
59743 LineChart.prototype.getSeriesTooltipInfo = function (pointData) {
59744 var tooltipinfo = [];
59745 var maxNumberOfItems = 10; // to limit the number of rows we display
59746 // count to the maximum number of rows we can display
59747 var count = 0;
59748 for (var _i = 0, pointData_1 = pointData; _i < pointData_1.length; _i++) {
59749 var point = pointData_1[_i];
59750 if (count >= maxNumberOfItems)
59751 break;
59752 if (point.value != null) {
59753 tooltipinfo.push({
59754 header: point.category,
59755 color: point.color,
59756 displayName: point.label,
59757 value: point.measure
59758 });
59759 count++;
59760 }
59761 }
59762 if (tooltipinfo.length === 0)
59763 return null; //don't draw an empty tooltip container
59764 return tooltipinfo;
59765 };
59766 /**
59767 * Note: Public for tests.
59768 */
59769 LineChart.prototype.getTooltipInfoForCombo = function (tooltipEvent, pointX) {
59770 // update pointX, the mouse coordinate, with the left-offset of the SVGRect from the x-scale space so we can use the d3.scale to get the index.
59771 var categoryIndex = this.getCategoryIndexFromTooltipEvent(tooltipEvent, pointX);
59772 var seriesData = tooltipEvent.data;
59773 var dataPoint;
59774 if (seriesData && seriesData.data && seriesData.data.length) {
59775 dataPoint = _.find(seriesData.data, function (dp) { return dp.categoryIndex === categoryIndex; });
59776 }
59777 if (dataPoint)
59778 return dataPoint.tooltipInfo;
59779 // return undefined so we don't show an empty tooltip
59780 };
59781 /**
59782 * Note: Public for tests.
59783 */
59784 LineChart.prototype.getCategoryIndexFromTooltipEvent = function (tooltipEvent, pointX) {
59785 if (tooltipEvent.data && tooltipEvent.data.categoryIndex != null) {
59786 // Tooltip originated with a dot; simply return the categoryIndex from the dot's bound data
59787 return tooltipEvent.data.categoryIndex;
59788 }
59789 var seriesData = tooltipEvent.data;
59790 var offsetX = 0; // Offset based on the firstCategoryOffset (since lines don't start at x = 0) as well as the offset due to lines that may not start at the first category
59791 if (seriesData && !_.isEmpty(seriesData.data) && this.xAxisProperties) {
59792 // Tooltip originated from a path; determine series offset from the first point that is part of a path
59793 pointX = this.adjustPathXCoordinate(pointX);
59794 var firstPathPoint = _.find(seriesData.data, function (dataPoint, index, dataPoints) {
59795 var nextDataPoint = dataPoints[index + 1];
59796 return dataPoint.value != null && nextDataPoint && nextDataPoint.value != null;
59797 });
59798 debug.assertValue(firstPathPoint, "If there is data on the tooltipEvent but no categoryIndex, there should always be two consecutive non-null values");
59799 offsetX = this.xAxisProperties.scale(this.getXValue(firstPathPoint)) + this.getXOfFirstCategory();
59800 }
59801 // else: Tooltip originated from the background; no offsetX is needed
59802 return this.findIndex(pointX, offsetX);
59803 };
59804 LineChart.prototype.getVisualCategoryAxisIsScalar = function () {
59805 return this.data ? this.data.isScalar : false;
59806 };
59807 LineChart.prototype.getSupportedCategoryAxisType = function () {
59808 var dvCategories = this.dataViewCat ? this.dataViewCat.categories : undefined;
59809 var categoryType = powerbi.ValueType.fromDescriptor({ text: true });
59810 if (dvCategories && dvCategories.length > 0 && dvCategories[0].source && dvCategories[0].source.type)
59811 categoryType = dvCategories[0].source.type;
59812 var isOrdinal = visuals.AxisHelper.isOrdinal(categoryType);
59813 return isOrdinal ? visuals.axisType.categorical : visuals.axisType.both;
59814 };
59815 LineChart.prototype.getPreferredPlotArea = function (isScalar, categoryCount, categoryThickness) {
59816 return visuals.CartesianChart.getPreferredPlotArea(categoryCount, categoryThickness, this.currentViewport, this.isScrollable, isScalar, this.margin, true);
59817 };
59818 LineChart.prototype.getCategoryCount = function (origCatgSize) {
59819 var availableWidth = this.getAvailableWidth();
59820 var categoryThickness = visuals.CartesianChart.MinOrdinalRectThickness;
59821 return Math.min(Math.round((availableWidth - categoryThickness * visuals.CartesianChart.OuterPaddingRatio * 2) / categoryThickness), origCatgSize);
59822 };
59823 LineChart.prototype.getAvailableWidth = function () {
59824 return this.currentViewport.width - (this.margin.left + this.margin.right);
59825 };
59826 LineChart.prototype.getAvailableHeight = function () {
59827 return this.currentViewport.height - (this.margin.top + this.margin.bottom);
59828 };
59829 LineChart.sliceSeries = function (series, newLength, startIndex) {
59830 if (startIndex === void 0) { startIndex = 0; }
59831 var newSeries = [];
59832 if (series && series.length > 0) {
59833 debug.assert(series[0].data.length >= newLength, "invalid newLength");
59834 for (var i = 0, len = series.length; i < len; i++) {
59835 newSeries[i] = powerbi.Prototype.inherit(series[i]);
59836 newSeries[i].data = series[i].data.slice(startIndex, startIndex + newLength);
59837 }
59838 }
59839 return newSeries;
59840 };
59841 LineChart.prototype.getXOfFirstCategory = function () {
59842 if (!this.data.isScalar) {
59843 // This will place the line points in the middle of the bands
59844 // So they center with Labels when scale is ordinal.
59845 var xScale = this.xAxisProperties.scale;
59846 if (xScale.rangeBand) {
59847 return xScale.rangeBand() / 2;
59848 }
59849 }
59850 return 0;
59851 };
59852 LineChart.prototype.hasDataPoint = function (series) {
59853 if (series.length === 0)
59854 return false;
59855 for (var i = 0, len = series.length; i < len; i++) {
59856 if (series[i].data.length > 0)
59857 return true;
59858 }
59859 return false;
59860 };
59861 LineChart.prototype.getXValue = function (d) {
59862 return this.data.isScalar ? d.categoryValue : d.categoryIndex;
59863 };
59864 /**
59865 * This checks to see if a data point is isolated, which means
59866 * the previous and next data point are both null.
59867 */
59868 LineChart.prototype.shouldDrawCircle = function (d, i) {
59869 var dataLength = d.data.length;
59870 var isLastPoint = i === (dataLength - 1);
59871 var isFirstPoint = i === 0;
59872 if (i > dataLength - 1 || d.data[i] === null || d.data[i].value === null)
59873 return false;
59874 if (isFirstPoint && isLastPoint)
59875 return true;
59876 if (isFirstPoint && dataLength > 1 && d.data[i + 1].value === null)
59877 return true;
59878 if (!isFirstPoint && isLastPoint && d.data[i - 1].value === null)
59879 return true;
59880 if (!isFirstPoint && !isLastPoint && d.data[i - 1].value === null && d.data[i + 1].value === null)
59881 return true;
59882 return false;
59883 };
59884 LineChart.prototype.selectColumnForTooltip = function (columnIndex, force) {
59885 if (force === void 0) { force = false; }
59886 var x = this.getChartX(columnIndex) + this.getXOfFirstCategory();
59887 var dataPoints = this.createTooltipDataPoints(columnIndex);
59888 if (dataPoints.length > 0) {
59889 this.setHoverLineForTooltip(x);
59890 }
59891 this.setDotsForTooltip(x, dataPoints);
59892 return dataPoints;
59893 };
59894 LineChart.prototype.setHoverLineForTooltip = function (chartX) {
59895 chartX = chartX || 0;
59896 this.hoverLine
59897 .attr('x1', chartX)
59898 .attr('x2', chartX)
59899 .attr("y1", 0)
59900 .attr("y2", this.getAvailableHeight())
59901 .style('opacity', 1);
59902 };
59903 LineChart.prototype.setDotsForTooltip = function (chartX, dataPoints) {
59904 var _this = this;
59905 var isStackedArea = EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */);
59906 var dotYPosition = isStackedArea ? function (d) { return _this.yAxisProperties.scale(d.stackedValue); } : function (d) { return _this.yAxisProperties.scale(d.value); };
59907 var tooltipDots = this.hoverLineContext.selectAll(LineChart.HoverLineCircleDot.selector).data(dataPoints);
59908 tooltipDots
59909 .enter()
59910 .append(LineChart.CircleElementName)
59911 .classed(LineChart.HoverLineCircleDot.class, true);
59912 tooltipDots
59913 .filter(function (d) { return d.value; })
59914 .attr('fill', function (d) { return d.color; })
59915 .attr("r", 3)
59916 .attr("cx", chartX)
59917 .attr("cy", dotYPosition);
59918 tooltipDots.exit().remove();
59919 };
59920 /**
59921 * Updates the hover line and the legend with the selected colums (given by columnIndex).
59922 * This is for the Mobile renderer with InteractiveLegend
59923 */
59924 LineChart.prototype.selectColumn = function (columnIndex, force) {
59925 if (force === void 0) { force = false; }
59926 if (!force && this.lastInteractiveSelectedColumnIndex === columnIndex)
59927 return; // same column, nothing to do here
59928 this.lastInteractiveSelectedColumnIndex = columnIndex;
59929 var x = this.getChartX(columnIndex);
59930 this.setHoverLine(x, columnIndex);
59931 var legendItems = this.createLegendDataPoints(columnIndex);
59932 if (legendItems)
59933 this.options.cartesianHost.updateLegend(legendItems);
59934 };
59935 LineChart.prototype.setHoverLine = function (chartX, columnIndex) {
59936 this.hoverLine
59937 .attr('x1', chartX)
59938 .attr('x2', chartX)
59939 .attr("y1", 0).attr("y2", this.getAvailableHeight())
59940 .style('opacity', 1);
59941 var that = this;
59942 this.mainGraphicsContext
59943 .selectAll(LineChart.CategorySelector.selector)
59944 .selectAll(LineChart.PathElementName)
59945 .each(function (series) {
59946 var _this = this;
59947 // Get the item color for the handle dots
59948 var color = series.color;
59949 var circleToChange = that.selectionCircles[series.lineIndex];
59950 circleToChange
59951 .attr({
59952 'cx': chartX,
59953 'cy': function () {
59954 var pathElement = d3.select(_this).node();
59955 var pos = that.getPosition(chartX, pathElement);
59956 return pos.y;
59957 }
59958 })
59959 .style({
59960 'opacity': function () { return _.some(series.data, function (value) { return value.categoryIndex === columnIndex; }) ? 1 : 0; },
59961 'fill': color
59962 });
59963 if (that.dragHandle)
59964 that.dragHandle.attr('cx', chartX);
59965 });
59966 };
59967 LineChart.prototype.getChartX = function (columnIndex) {
59968 var x = 0;
59969 if (this.data.isScalar) {
59970 if (columnIndex >= 0 && columnIndex < this.data.categoryData.length)
59971 x = Math.max(0, this.xAxisProperties.scale(this.data.categoryData[columnIndex].categoryValue));
59972 }
59973 else {
59974 x = Math.max(0, this.xAxisProperties.scale(columnIndex));
59975 }
59976 var rangeEnd = powerbi.visuals.AxisHelper.extent(this.xAxisProperties.scale)[1];
59977 x = Math.min(x, rangeEnd);
59978 if (!isNaN(x))
59979 return x;
59980 return 0;
59981 };
59982 /**
59983 * Finds the index of the category of the given x coordinate given.
59984 * pointX is in non-scaled screen-space, and offsetX is in render-space.
59985 * offsetX does not need any scaling adjustment.
59986 * @param {number} pointX The mouse coordinate in screen-space, without scaling applied
59987 * @param {number} offsetX Any left offset in d3.scale render-space
59988 * @return {number}
59989 */
59990 LineChart.prototype.findIndex = function (pointX, offsetX) {
59991 // we are using mouse coordinates that do not know about any potential CSS transform scale
59992 var xScale = this.scaleDetector.getScale().x;
59993 if (!powerbi.Double.equalWithPrecision(xScale, 1.0, 0.00001)) {
59994 pointX = pointX / xScale;
59995 }
59996 if (offsetX) {
59997 pointX += offsetX;
59998 }
59999 var index = powerbi.visuals.AxisHelper.invertScale(this.xAxisProperties.scale, pointX);
60000 if (this.data.isScalar) {
60001 // When we have scalar data the inverted scale produces a category value, so we need to search for the closest index.
60002 index = visuals.AxisHelper.findClosestXAxisIndex(index, this.data.categoryData);
60003 }
60004 return index;
60005 };
60006 LineChart.prototype.getPosition = function (x, pathElement) {
60007 var pathLength = pathElement.getTotalLength();
60008 var pos;
60009 var beginning = 0, end = pathLength, target;
60010 while (true) {
60011 target = Math.floor((beginning + end) / 2);
60012 pos = pathElement.getPointAtLength(target);
60013 visuals.SVGUtil.ensureValidSVGPoint(pos);
60014 if ((target === end || target === beginning) && pos.x !== x)
60015 break;
60016 if (pos.x > x)
60017 end = target;
60018 else if (pos.x < x)
60019 beginning = target;
60020 else
60021 break;
60022 }
60023 return pos;
60024 };
60025 LineChart.prototype.createTooltipDataPoints = function (columnIndex) {
60026 var data = this.data;
60027 if (!data || data.series.length === 0 || !data.categoryData)
60028 return [];
60029 var dataPoints = [];
60030 var category;
60031 debug.assert(columnIndex < data.categoryData.length, 'category index out of range');
60032 var categoryDataPoint = data.categoryData[columnIndex];
60033 if (this.data.isScalar) {
60034 if (categoryDataPoint) {
60035 if (visuals.AxisHelper.isDateTime(this.xAxisProperties.axisType)) {
60036 category = visuals.CartesianHelper.lookupXValue(this.data, categoryDataPoint.categoryValue, this.xAxisProperties.axisType, this.data.isScalar);
60037 }
60038 else {
60039 category = categoryDataPoint.categoryValue;
60040 }
60041 }
60042 }
60043 else {
60044 category = visuals.CartesianHelper.lookupXValue(this.data, columnIndex, this.xAxisProperties.axisType, this.data.isScalar);
60045 }
60046 var formatStringProp = visuals.lineChartProps.general.formatString;
60047 for (var _i = 0, _a = data.series; _i < _a.length; _i++) {
60048 var series = _a[_i];
60049 var lineData = series.data;
60050 var lineDataPoint = void 0;
60051 if (this.data.isScalar) {
60052 if (categoryDataPoint) {
60053 lineDataPoint = lineData.filter(function (data) {
60054 return data.categoryValue === categoryDataPoint.categoryValue;
60055 })[0];
60056 }
60057 }
60058 else {
60059 lineDataPoint = lineData[columnIndex];
60060 }
60061 var value = lineDataPoint && lineDataPoint.value;
60062 if (value != null) {
60063 var label = visuals.converterHelper.getFormattedLegendLabel(series.yCol, this.dataViewCat.values, formatStringProp);
60064 dataPoints.push({
60065 color: series.color,
60066 label: label,
60067 category: visuals.valueFormatter.format(category, visuals.valueFormatter.getFormatString(series.xCol, formatStringProp)),
60068 measure: visuals.valueFormatter.format(value, visuals.valueFormatter.getFormatString(series.yCol, formatStringProp)),
60069 value: value,
60070 stackedValue: lineDataPoint.stackedValue
60071 });
60072 }
60073 }
60074 return dataPoints;
60075 };
60076 LineChart.prototype.createLegendDataPoints = function (columnIndex) {
60077 var data = this.data;
60078 if (!data || !data.series || data.series.length < 1)
60079 return;
60080 var legendDataPoints = [];
60081 var category;
60082 // 'category' and 'measure' are only for Mobile interactive legend, Minerva legend does not need them
60083 var categoryDataPoint = data.categoryData[columnIndex];
60084 if (this.isInteractiveChart && categoryDataPoint) {
60085 if (this.data.isScalar) {
60086 category = categoryDataPoint.categoryValue;
60087 if (visuals.AxisHelper.isDateTime(this.xAxisProperties.axisType))
60088 category = new Date(category);
60089 }
60090 else {
60091 category = visuals.CartesianHelper.lookupXValue(this.data, columnIndex, this.xAxisProperties.axisType, this.data.isScalar);
60092 }
60093 }
60094 var formatStringProp = visuals.lineChartProps.general.formatString;
60095 var seriesYCol = null;
60096 // iterating over the line data (i is for a line)
60097 for (var i = 0, len = data.series.length; i < len; i++) {
60098 var series = data.series[i];
60099 var lineData = series.data;
60100 // 'category' and 'measure' are only for Mobile interactive legend, Minerva legend does not need them
60101 var measure = void 0;
60102 if (this.isInteractiveChart) {
60103 var lineDataPoint = void 0;
60104 if (this.data.isScalar) {
60105 // Scalar series skip null values, and therefore do not share the same category index
60106 // Search this series for the categoryValue - it may not exist
60107 if (categoryDataPoint) {
60108 var targetCategoryValue = categoryDataPoint.categoryValue;
60109 for (var i_1 = 0; i_1 < lineData.length; i_1++) {
60110 if (lineData[i_1].categoryValue === targetCategoryValue) {
60111 lineDataPoint = lineData[i_1];
60112 break;
60113 }
60114 }
60115 }
60116 }
60117 else {
60118 // ordinal series all share the same x-indicies
60119 lineDataPoint = lineData[columnIndex];
60120 }
60121 measure = lineDataPoint && lineDataPoint.value;
60122 }
60123 var label = visuals.converterHelper.getFormattedLegendLabel(series.yCol, this.dataViewCat.values, formatStringProp);
60124 seriesYCol = series.yCol;
60125 legendDataPoints.push({
60126 color: series.color,
60127 icon: visuals.LegendIcon.Line,
60128 label: label,
60129 // TODO: category: CartesianChartInteractiveLegend only needs one category value for part of the Title, we don't need to put it on each point.
60130 category: visuals.valueFormatter.format(category, visuals.valueFormatter.getFormatString(series.xCol, formatStringProp)),
60131 measure: visuals.valueFormatter.format(measure, visuals.valueFormatter.getFormatString(series.yCol, formatStringProp)),
60132 identity: series.identity,
60133 selected: series.selected,
60134 });
60135 }
60136 var dvValues = this.dataViewCat ? this.dataViewCat.values : null;
60137 var title = dvValues && dvValues.source ? dvValues.source.displayName : "";
60138 return {
60139 title: title,
60140 dataPoints: legendDataPoints
60141 };
60142 };
60143 LineChart.prototype.createLabelDataPoints = function () {
60144 var _this = this;
60145 var xScale = this.xAxisProperties.scale;
60146 var yScale = this.yAxisProperties.scale;
60147 var lineshift = this.getXOfFirstCategory();
60148 var data = this.data;
60149 var series = data.series;
60150 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
60151 var dataLabelsSettings = data.dataLabelsSettings;
60152 var isStackedArea = EnumExtensions.hasFlag(this.lineType, 16 /* stackedArea */);
60153 var labelDataPointsGroups = [];
60154 var labelSettings;
60155 var axisFormatter;
60156 var seriesLabelDataPoints;
60157 var seriesDataPointsCandidates;
60158 var seriesIndex;
60159 var seriesCount;
60160 for (seriesIndex = 0, seriesCount = series.length; seriesIndex < seriesCount; seriesIndex++) {
60161 var currentSeries = series[seriesIndex];
60162 labelSettings = (currentSeries.labelSettings) ? currentSeries.labelSettings : dataLabelsSettings;
60163 if (!labelSettings.show)
60164 continue;
60165 axisFormatter = visuals.NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter(this.yAxisProperties.formatter, labelSettings);
60166 var dataPoints = currentSeries.data;
60167 seriesLabelDataPoints = [];
60168 seriesDataPointsCandidates = [];
60169 var createLabelDataPoint = function (dataPoint) {
60170 if (dataPoint.value == null)
60171 return null;
60172 var formatString = "";
60173 formatString = dataPoint.labelFormatString;
60174 var formatter = formattersCache.getOrCreate(formatString, labelSettings, axisFormatter);
60175 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(dataPoint.value));
60176 var properties = {
60177 text: text,
60178 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
60179 fontSize: PixelConverter.fromPoint(labelSettings.fontSize),
60180 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
60181 };
60182 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties) + visuals.NewDataLabelUtils.LabelDensityPadding;
60183 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
60184 var parentShape;
60185 var isParentRect = false;
60186 if (isStackedArea) {
60187 var bottomPos = Math.max(dataPoint.stackedValue - dataPoint.value, yScale.domain()[0]); //this is to make sure the bottom position doesn't go below the domain
60188 var areaWidth = _this.currentViewport.width; // Conceptually, we allow line labels to fill the full plot area, so the width is equal to the plot area
60189 parentShape = {
60190 rect: {
60191 left: xScale(_this.getXValue(dataPoint)) - areaWidth / 2,
60192 top: yScale(Math.max(dataPoint.stackedValue, dataPoint.stackedValue - dataPoint.value)),
60193 width: areaWidth,
60194 height: Math.abs(yScale(dataPoint.stackedValue) - yScale(bottomPos))
60195 },
60196 orientation: dataPoint.value >= 0 ? 1 /* VerticalBottomBased */ : 2 /* VerticalTopBased */,
60197 validPositions: LineChart.validStackedLabelPositions,
60198 };
60199 isParentRect = true;
60200 }
60201 else {
60202 parentShape = {
60203 point: {
60204 x: xScale(_this.getXValue(dataPoint)) + lineshift,
60205 y: yScale(dataPoint.value),
60206 },
60207 radius: 0,
60208 validPositions: _this.lineChartLabelDensityEnabled ? LineChart.validLabelPositions : [1 /* Above */],
60209 };
60210 }
60211 var labelDataPoint = {
60212 isPreferred: false,
60213 text: text,
60214 textSize: {
60215 width: textWidth,
60216 height: textHeight,
60217 },
60218 outsideFill: labelSettings.labelColor ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultLabelColor,
60219 insideFill: labelSettings.labelColor && isStackedArea ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultInsideLabelColor,
60220 parentType: isParentRect ? 1 /* Rectangle */ : 0 /* Point */,
60221 parentShape: parentShape,
60222 fontSize: labelSettings.fontSize,
60223 identity: dataPoint.identity,
60224 key: dataPoint.key,
60225 };
60226 return labelDataPoint;
60227 };
60228 if (!_.isEmpty(dataPoints)) {
60229 var categoryCount = dataPoints.length;
60230 var lastDataPoint = dataPoints[categoryCount - 1];
60231 var lastLabelDataPoint = createLabelDataPoint(lastDataPoint, seriesIndex);
60232 if (lastLabelDataPoint)
60233 seriesLabelDataPoints.push(lastLabelDataPoint);
60234 for (var categoryIndex = 0; categoryIndex < categoryCount - 1; categoryIndex++) {
60235 var labelDataPoint = createLabelDataPoint(dataPoints[categoryIndex], seriesIndex);
60236 if (labelDataPoint)
60237 seriesLabelDataPoints.push(labelDataPoint);
60238 }
60239 }
60240 var maxLabelsToRender = dataPoints.length;
60241 labelDataPointsGroups[seriesIndex] = {
60242 labelDataPoints: seriesLabelDataPoints,
60243 maxNumberOfLabels: maxLabelsToRender,
60244 };
60245 }
60246 return labelDataPointsGroups;
60247 };
60248 /**
60249 * Adjust a mouse coordinate originating from a path; used to fix
60250 * an inconsistency between Internet Explorer and other browsers.
60251 *
60252 * Internet explorer places the origin for the coordinate system of
60253 * mouse events based on the stroke, so that the very edge of the stroke
60254 * is zero. Chrome places the 0 on the edge of the path so that the
60255 * edge of the stroke is -(strokeWidth / 2). We adjust coordinates
60256 * to match Chrome.
60257 *
60258 * TODO: Firefox is similar to IE, but does a very poor job at it, so
60259 * the edge is inacurate.
60260 *
60261 * @param value The x coordinate to be adjusted
60262 */
60263 LineChart.prototype.adjustPathXCoordinate = function (x) {
60264 if (this.shouldAdjustMouseCoordsOnPathsForStroke) {
60265 var xScale = this.scaleDetector.getScale().x;
60266 if (!powerbi.Double.equalWithPrecision(xScale, 1.0, 0.00001)) {
60267 x -= LineChart.pathXAdjustment * xScale;
60268 }
60269 else {
60270 x -= LineChart.pathXAdjustment;
60271 }
60272 }
60273 return x;
60274 };
60275 //private isMinMax(index: number, dataPoints: LineChartDataPoint[]): boolean {
60276 // // Check if the point is the start/end point
60277 // if (!dataPoints[index - 1] || !dataPoints[index + 1])
60278 // return true;
60279 // let currentValue = dataPoints[index].value;
60280 // let prevValue = dataPoints[index - 1].value;
60281 // let nextValue = dataPoints[index + 1].value;
60282 // return (prevValue > currentValue && currentValue < nextValue) // Min point
60283 // || (prevValue < currentValue && currentValue > nextValue); // Max point
60284 //}
60285 //private calculatePointsWeight(labelDataPoints: LabelDataPoint[], dataPointsCandidates: LineChartDataPoint[], minIndex: number, maxIndex: number) {
60286 // let previousMinMaxIndex = 0;
60287 // labelDataPoints[0].weight = dataPointsCandidates[0].weight = 0;
60288 // let previousMinMax: LineChartDataPoint = dataPointsCandidates[0];
60289 // let dataPointCount = labelDataPoints.length;
60290 // let yScale = this.yAxisProperties.scale;
60291 // let totalValueDelta = yScale(dataPointsCandidates[maxIndex].value) - yScale(dataPointsCandidates[minIndex].value);
60292 // for (let i = 1; i < dataPointCount; i++) {
60293 // let dataPoint = dataPointsCandidates[i];
60294 // let weight = (Math.abs(yScale(previousMinMax.value) - yScale(dataPoint.value))) / totalValueDelta + (i - previousMinMaxIndex) / dataPointCount;
60295 // labelDataPoints[i].weight = weight;
60296 // if (this.isMinMax(i, dataPointsCandidates)) {
60297 // previousMinMax.weight += weight;
60298 // previousMinMax = dataPoint;
60299 // previousMinMaxIndex = i;
60300 // }
60301 // }
60302 //}
60303 //private sortByWeightAndPreferrance(a: LabelDataPoint, b: LabelDataPoint): number {
60304 // // Compare by prederrance first
60305 // if (!a.isPreferred && b.isPreferred) return 1;
60306 // if (a.isPreferred && !b.isPreferred) return -1;
60307 // // Compare by weight
60308 // if ((!a.weight && b.weight) || (a.weight < b.weight)) return 1;
60309 // if ((a.weight && !b.weight) || (a.weight > b.weight)) return -1;
60310 // return 0;
60311 //}
60312 LineChart.prototype.showLabelPerSeries = function () {
60313 var data = this.data;
60314 return !data.hasDynamicSeries && (data.series.length > 1 || !data.categoryMetadata);
60315 };
60316 LineChart.ClassName = 'lineChart';
60317 LineChart.MainGraphicsContextClassName = 'mainGraphicsContext';
60318 LineChart.CategorySelector = createClassAndSelector('cat');
60319 LineChart.CategoryValuePoint = createClassAndSelector('dot');
60320 LineChart.CategoryPointSelector = createClassAndSelector('point');
60321 LineChart.CategoryAreaSelector = createClassAndSelector('catArea');
60322 LineChart.HoverLineCircleDot = createClassAndSelector('circle-item');
60323 LineChart.LineClassSelector = createClassAndSelector('line');
60324 LineChart.PointRadius = 5;
60325 LineChart.CircleRadius = 4;
60326 LineChart.PathElementName = 'path';
60327 LineChart.CircleElementName = 'circle';
60328 LineChart.CircleClassName = 'selection-circle';
60329 LineChart.LineElementName = 'line';
60330 LineChart.RectOverlayName = 'rect';
60331 LineChart.ScalarOuterPadding = 10;
60332 LineChart.interactivityStrokeWidth = 10;
60333 LineChart.pathXAdjustment = 5; // Based on half the stroke width for taking stroke into account in coordinate transforms
60334 LineChart.AreaFillOpacity = 0.4;
60335 LineChart.DimmedAreaFillOpacity = 0.2;
60336 LineChart.validLabelPositions = [
60337 1 /* Above */,
60338 2 /* Below */,
60339 8 /* Right */,
60340 4 /* Left */,
60341 64 /* AboveRight */,
60342 128 /* AboveLeft */,
60343 16 /* BelowRight */,
60344 32 /* BelowLeft */
60345 ];
60346 LineChart.validStackedLabelPositions = [1 /* InsideCenter */, 4 /* InsideEnd */, 2 /* InsideBase */];
60347 return LineChart;
60348 }());
60349 visuals.LineChart = LineChart;
60350 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
60351})(powerbi || (powerbi = {}));
60352/*
60353 * Power BI Visualizations
60354 *
60355 * Copyright (c) Microsoft Corporation
60356 * All rights reserved.
60357 * MIT License
60358 *
60359 * Permission is hereby granted, free of charge, to any person obtaining a copy
60360 * of this software and associated documentation files (the ""Software""), to deal
60361 * in the Software without restriction, including without limitation the rights
60362 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
60363 * copies of the Software, and to permit persons to whom the Software is
60364 * furnished to do so, subject to the following conditions:
60365 *
60366 * The above copyright notice and this permission notice shall be included in
60367 * all copies or substantial portions of the Software.
60368 *
60369 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60370 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60371 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60372 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
60373 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60374 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
60375 * THE SOFTWARE.
60376 */
60377var powerbi;
60378(function (powerbi) {
60379 var visuals;
60380 (function (visuals) {
60381 var Color = jsCommon.Color;
60382 var PixelConverter = jsCommon.PixelConverter;
60383 var Polygon = visuals.shapes.Polygon;
60384 var DataRoleHelper = powerbi.data.DataRoleHelper;
60385 visuals.MaxLevelOfDetail = 23;
60386 visuals.MinLevelOfDetail = 1;
60387 visuals.DefaultFillOpacity = 0.5;
60388 visuals.DefaultBackgroundColor = "#000000";
60389 visuals.LeaderLineColor = "#000000";
60390 var MapBubbleDataPointRenderer = (function () {
60391 function MapBubbleDataPointRenderer(tooltipsEnabled) {
60392 this.tooltipsEnabled = tooltipsEnabled;
60393 }
60394 MapBubbleDataPointRenderer.prototype.init = function (mapControl, mapDiv, addClearCatcher) {
60395 /*
60396 The layout of the visual would look like :
60397 <div class="visual mapControl">
60398 <div class="MicrosoftMap">
60399 <!-- Bing maps stuff -->
60400 <svg>
60401 <rect class="clearCatcher"></rect>
60402 </svg>
60403 </div>
60404 <svg>
60405 <g class="mapBubbles>
60406 <!-- our geometry -->
60407 </g>
60408 <g class="mapSlices>
60409 <!-- our geometry -->
60410 </g>
60411 </svg>
60412 </div>
60413
60414 */
60415 this.mapControl = mapControl;
60416 this.root = mapDiv;
60417 var root = d3.select(mapDiv[0]);
60418 root.attr("drag-resize-disabled", "true"); // Enable panning within the maps in IE
60419 var svg = this.svg = root
60420 .append('svg')
60421 .style("position", "absolute") // Absolute position so that the svg will overlap with the canvas.
60422 .style("pointer-events", "none");
60423 if (addClearCatcher) {
60424 var clearSvg = this.clearSvg = d3.select(this.mapControl.getRootElement())
60425 .append('svg')
60426 .style('position', 'absolute'); // Absolute position so that the svg will overlap with the canvas.
60427 this.clearCatcher = visuals.appendClearCatcher(clearSvg);
60428 }
60429 this.bubbleGraphicsContext = svg
60430 .append("g")
60431 .classed("mapBubbles", true);
60432 this.sliceGraphicsContext = svg
60433 .append("g")
60434 .classed("mapSlices", true);
60435 this.labelBackgroundGraphicsContext = svg
60436 .append("g")
60437 .classed(visuals.NewDataLabelUtils.labelBackgroundGraphicsContextClass.class, true);
60438 this.labelGraphicsContext = svg
60439 .append("g")
60440 .classed(visuals.NewDataLabelUtils.labelGraphicsContextClass.class, true);
60441 this.sliceLayout = d3.layout.pie()
60442 .sort(null)
60443 .value(function (d) {
60444 return d.value;
60445 });
60446 this.arc = d3.svg.arc();
60447 this.clearMaxDataPointRadius();
60448 this.dataLabelsSettings = visuals.dataLabelUtils.getDefaultMapLabelSettings();
60449 };
60450 MapBubbleDataPointRenderer.prototype.setData = function (data) {
60451 this.mapData = data;
60452 };
60453 MapBubbleDataPointRenderer.prototype.clearDataPoints = function () {
60454 this.mapData = {
60455 dataPoints: [],
60456 geocodingCategory: null,
60457 hasDynamicSeries: false,
60458 hasSize: false,
60459 };
60460 };
60461 MapBubbleDataPointRenderer.prototype.getDataPointCount = function () {
60462 if (!this.mapData)
60463 return 0;
60464 // Filter out any data points without a location since those aren't actually being drawn
60465 return _.filter(this.mapData.dataPoints, function (value) { return !!value.location; }).length;
60466 };
60467 MapBubbleDataPointRenderer.prototype.getDataPointPadding = function () {
60468 return this.maxDataPointRadius * 2;
60469 };
60470 MapBubbleDataPointRenderer.prototype.clearMaxDataPointRadius = function () {
60471 this.maxDataPointRadius = 0;
60472 };
60473 MapBubbleDataPointRenderer.prototype.setMaxDataPointRadius = function (dataPointRadius) {
60474 this.maxDataPointRadius = Math.max(dataPointRadius, this.maxDataPointRadius);
60475 };
60476 MapBubbleDataPointRenderer.prototype.getDefaultMap = function (geocodingCategory, dataPointCount) {
60477 this.clearDataPoints();
60478 };
60479 MapBubbleDataPointRenderer.prototype.converter = function (viewport, dataView, labelSettings, interactivityService, tooltipsEnabled) {
60480 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
60481 var mapControl = this.mapControl;
60482 var widthOverTwo = viewport.width / 2;
60483 var heightOverTwo = viewport.height / 2;
60484 var strokeWidth = 1;
60485 //update data label settings
60486 this.dataLabelsSettings = labelSettings;
60487 // See MapSeriesPresenter::GetDataPointRadius for the PV behavior
60488 var radiusScale = Math.min(viewport.width, viewport.height) / 384;
60489 this.clearMaxDataPointRadius();
60490 var bubbleData = [];
60491 var sliceData = [];
60492 var categorical = dataView ? dataView.categorical : null;
60493 var grouped;
60494 var sizeIndex = -1;
60495 var dataValuesSource;
60496 if (categorical && categorical.values) {
60497 grouped = categorical.values.grouped();
60498 sizeIndex = DataRoleHelper.getMeasureIndexOfRole(grouped, "Size");
60499 dataValuesSource = categorical.values.source;
60500 }
60501 var dataPoints = this.mapData ? this.mapData.dataPoints : [];
60502 var hasSize = this.mapData.hasSize;
60503 for (var categoryIndex = 0, categoryCount = dataPoints.length; categoryIndex < categoryCount; categoryIndex++) {
60504 var dataPoint = dataPoints[categoryIndex];
60505 var categoryValue = dataPoint.categoryValue;
60506 var location_2 = dataPoint.location;
60507 if (location_2) {
60508 var xy = mapControl.tryLocationToPixel(new Microsoft.Maps.Location(location_2.latitude, location_2.longitude));
60509 var x = xy.x + widthOverTwo;
60510 var y = xy.y + heightOverTwo;
60511 var radius = dataPoint.radius * radiusScale;
60512 this.setMaxDataPointRadius(radius);
60513 var subDataPoints = dataPoint.subDataPoints;
60514 var seriesCount = subDataPoints.length;
60515 if (seriesCount === 1) {
60516 var subDataPoint = subDataPoints[0];
60517 bubbleData.push({
60518 x: x,
60519 y: y,
60520 labeltext: categoryValue,
60521 radius: radius,
60522 fill: subDataPoint.fill,
60523 stroke: subDataPoint.stroke,
60524 strokeWidth: strokeWidth,
60525 tooltipInfo: subDataPoint.tooltipInfo,
60526 identity: subDataPoint.identity,
60527 selected: false,
60528 labelFill: labelSettings.labelColor,
60529 });
60530 }
60531 else {
60532 var slices = [];
60533 for (var seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
60534 var subDataPoint = subDataPoints[seriesIndex];
60535 var value = hasSize ? subDataPoint.value : 1; // Normalize values if there is no size in the data
60536 slices.push({
60537 x: x,
60538 y: y,
60539 labeltext: categoryValue,
60540 radius: radius,
60541 fill: subDataPoint.fill,
60542 stroke: subDataPoint.stroke,
60543 strokeWidth: strokeWidth,
60544 value: value,
60545 tooltipInfo: subDataPoint.tooltipInfo,
60546 identity: subDataPoint.identity,
60547 selected: false,
60548 labelFill: labelSettings.labelColor,
60549 });
60550 }
60551 if (interactivityService) {
60552 interactivityService.applySelectionStateToData(slices);
60553 }
60554 sliceData.push(slices);
60555 }
60556 }
60557 }
60558 if (interactivityService) {
60559 interactivityService.applySelectionStateToData(bubbleData);
60560 }
60561 return { bubbleData: bubbleData, sliceData: sliceData };
60562 };
60563 MapBubbleDataPointRenderer.prototype.updateInternal = function (data, viewport, dataChanged, interactivityService, redrawDataLabels) {
60564 debug.assertValue(viewport, "viewport");
60565 Map.removeTransform3d(this.root);
60566 this.mapRendererData = data;
60567 if (this.svg) {
60568 this.svg
60569 .style("width", viewport.width.toString() + "px")
60570 .style("height", viewport.height.toString() + "px");
60571 }
60572 if (this.clearSvg) {
60573 this.clearSvg
60574 .style("width", viewport.width.toString() + "px")
60575 .style("height", viewport.height.toString() + "px");
60576 }
60577 var arc = this.arc;
60578 var hasSelection = interactivityService && interactivityService.hasSelection();
60579 var bubbles = this.bubbleGraphicsContext.selectAll(".bubble").data(data.bubbleData, function (d) { return d.identity.getKey(); });
60580 bubbles.enter()
60581 .append("circle")
60582 .classed("bubble", true);
60583 bubbles
60584 .attr("cx", function (d) { return d.x; })
60585 .attr("cy", function (d) { return d.y; })
60586 .attr("r", function (d) { return d.radius; })
60587 .style("fill", function (d) { return d.fill; })
60588 .style("stroke", function (d) { return d.stroke; })
60589 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); })
60590 .style("strokeWidth", function (d) { return d.strokeWidth; })
60591 .style("stroke-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); })
60592 .style("cursor", "default");
60593 bubbles.exit().remove();
60594 if (this.tooltipsEnabled) {
60595 visuals.TooltipManager.addTooltip(this.bubbleGraphicsContext, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
60596 bubbles.style("pointer-events", "all");
60597 }
60598 var sliceData = data.sliceData;
60599 var sliceContainers = this.sliceGraphicsContext.selectAll(".sliceContainer").data(sliceData);
60600 sliceContainers.enter()
60601 .append("g")
60602 .classed("sliceContainer", true);
60603 sliceContainers.exit().remove();
60604 var sliceLayout = this.sliceLayout;
60605 var slices = sliceContainers.selectAll(".slice")
60606 .data(function (d) {
60607 return sliceLayout(d);
60608 }, function (d) { return d.data.identity.getKey(); });
60609 slices.enter()
60610 .append("path")
60611 .classed("slice", true);
60612 slices
60613 .style("fill", function (t) { return t.data.fill; })
60614 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, false); })
60615 .style("stroke", function (t) { return t.data.stroke; })
60616 .style("strokeWidth", function (t) { return t.data.strokeWidth; })
60617 .style("stroke-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, false); })
60618 .style("cursor", "default")
60619 .attr("transform", function (t) { return visuals.SVGUtil.translate(t.data.x, t.data.y); })
60620 .attr('d', function (t) {
60621 return arc.innerRadius(0).outerRadius(function (t) { return t.data.radius; })(t);
60622 });
60623 slices.exit().remove();
60624 this.updateInternalDataLabels(viewport, redrawDataLabels);
60625 if (this.tooltipsEnabled) {
60626 visuals.TooltipManager.addTooltip(this.sliceGraphicsContext, function (tooltipEvent) { return tooltipEvent.data.data.tooltipInfo; });
60627 slices.style("pointer-events", "all");
60628 }
60629 var allData = data.bubbleData.slice();
60630 for (var i = 0, ilen = sliceData.length; i < ilen; i++) {
60631 allData.push.apply(allData, sliceData[i]);
60632 }
60633 var behaviorOptions = {
60634 bubbleEventGroup: this.bubbleGraphicsContext,
60635 sliceEventGroup: this.sliceGraphicsContext,
60636 bubbles: bubbles,
60637 slices: slices,
60638 clearCatcher: this.clearCatcher,
60639 dataPoints: allData,
60640 };
60641 return behaviorOptions;
60642 };
60643 MapBubbleDataPointRenderer.prototype.updateInternalDataLabels = function (viewport, redrawDataLabels) {
60644 var labelSettings = this.dataLabelsSettings;
60645 var dataLabels = [];
60646 if (labelSettings && (labelSettings.show || labelSettings.showCategory)) {
60647 var labelDataPoints = this.createLabelDataPoints();
60648 var labelLayout = new powerbi.LabelLayout({
60649 maximumOffset: visuals.NewDataLabelUtils.maxLabelOffset,
60650 startingOffset: visuals.NewDataLabelUtils.startingLabelOffset
60651 });
60652 var labelDataPointsGroup = {
60653 labelDataPoints: labelDataPoints,
60654 maxNumberOfLabels: labelDataPoints.length
60655 };
60656 dataLabels = labelLayout.layout([labelDataPointsGroup], { width: viewport.width, height: viewport.height });
60657 }
60658 visuals.NewDataLabelUtils.drawLabelBackground(this.labelGraphicsContext, dataLabels, powerbi.visuals.DefaultBackgroundColor, powerbi.visuals.DefaultFillOpacity);
60659 visuals.NewDataLabelUtils.drawDefaultLabels(this.labelGraphicsContext, dataLabels, false); // Once we properly split up and handle show and showCategory, the false here should change to !labelSettings.showCategory
60660 };
60661 MapBubbleDataPointRenderer.prototype.createLabelDataPoints = function () {
60662 var data = this.mapRendererData;
60663 var labelDataPoints = [];
60664 var dataPoints = data.bubbleData;
60665 dataPoints = dataPoints.concat(_.map(data.sliceData, function (value) { return value[0]; }));
60666 var labelSettings = this.dataLabelsSettings;
60667 for (var _i = 0, dataPoints_4 = dataPoints; _i < dataPoints_4.length; _i++) {
60668 var dataPoint = dataPoints_4[_i];
60669 debug.assertValue(dataPoint, 'dataPoint should never be null/undefined');
60670 var text = dataPoint.labeltext;
60671 var properties = {
60672 text: text,
60673 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
60674 fontSize: PixelConverter.fromPoint(labelSettings.fontSize),
60675 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
60676 };
60677 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
60678 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
60679 labelDataPoints.push({
60680 isPreferred: true,
60681 text: text,
60682 textSize: {
60683 width: textWidth,
60684 height: textHeight,
60685 },
60686 outsideFill: labelSettings.labelColor ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultInsideLabelColor,
60687 insideFill: visuals.NewDataLabelUtils.defaultInsideLabelColor,
60688 parentType: 0 /* Point */,
60689 parentShape: {
60690 point: {
60691 x: dataPoint.x,
60692 y: dataPoint.y,
60693 },
60694 radius: dataPoint.radius,
60695 validPositions: MapBubbleDataPointRenderer.validLabelPositions,
60696 },
60697 fontSize: labelSettings.fontSize,
60698 identity: undefined,
60699 hasBackground: true,
60700 });
60701 }
60702 return labelDataPoints;
60703 };
60704 MapBubbleDataPointRenderer.validLabelPositions = [1 /* Above */, 2 /* Below */, 4 /* Left */, 8 /* Right */];
60705 return MapBubbleDataPointRenderer;
60706 }());
60707 visuals.MapBubbleDataPointRenderer = MapBubbleDataPointRenderer;
60708 var MapShapeDataPointRenderer = (function () {
60709 function MapShapeDataPointRenderer(fillMapDataLabelsEnabled, tooltipsEnabled) {
60710 this.filledMapDataLabelsEnabled = fillMapDataLabelsEnabled;
60711 this.tooltipsEnabled = tooltipsEnabled;
60712 }
60713 MapShapeDataPointRenderer.getFilledMapParams = function (category, dataCount) {
60714 switch (category) {
60715 case visuals.MapUtil.CategoryTypes.Continent:
60716 case visuals.MapUtil.CategoryTypes.CountryRegion:
60717 if (dataCount < 10) {
60718 return { level: 1, maxPolygons: 50, strokeWidth: 0 };
60719 }
60720 else if (dataCount < 30) {
60721 return { level: 1, maxPolygons: 20, strokeWidth: 0 };
60722 }
60723 return { level: 1, maxPolygons: 5, strokeWidth: 0 };
60724 default:
60725 if (dataCount < 100) {
60726 return { level: 1, maxPolygons: 5, strokeWidth: 6 };
60727 }
60728 if (dataCount < 200) {
60729 return { level: 0, maxPolygons: 5, strokeWidth: 6 };
60730 }
60731 return { level: 0, maxPolygons: 5, strokeWidth: 0 };
60732 }
60733 };
60734 MapShapeDataPointRenderer.buildPaths = function (locations) {
60735 var paths = [];
60736 for (var i = 0; i < locations.length; i++) {
60737 var location_3 = locations[i];
60738 var polygon = location_3.geographic;
60739 if (polygon.length > 2) {
60740 paths.push(location_3);
60741 }
60742 }
60743 return paths;
60744 };
60745 MapShapeDataPointRenderer.prototype.init = function (mapControl, mapDiv, addClearCatcher) {
60746 /*
60747 The layout of the visual would look like :
60748 <div class="visual mapControl">
60749 <div class="MicrosoftMap">
60750 <!-- Bing maps stuff -->
60751 <svg>
60752 <rect class="clearCatcher"></rect>
60753 </svg>
60754 </div>
60755 <svg>
60756 <g class="mapShapes>
60757 <!-- our geometry -->
60758 </g>
60759 </svg>
60760 </div>
60761
60762 */
60763 this.mapControl = mapControl;
60764 this.polygonInfo = new visuals.MapPolygonInfo();
60765 this.root = mapDiv;
60766 var root = d3.select(mapDiv[0]);
60767 root.attr('drag-resize-disabled', 'true'); // Enable panning within the maps in IE
60768 var svg = this.svg = root
60769 .append('svg')
60770 .style('position', 'absolute') // Absolute position so that the svg will overlap with the canvas.
60771 .style("pointer-events", "none");
60772 if (addClearCatcher) {
60773 var clearSvg = this.clearSvg = d3.select(this.mapControl.getRootElement())
60774 .append('svg')
60775 .style('position', 'absolute'); // Absolute position so that the svg will overlap with the canvas.
60776 this.clearCatcher = visuals.appendClearCatcher(clearSvg);
60777 }
60778 this.shapeGraphicsContext = svg
60779 .append('g')
60780 .classed('mapShapes', true);
60781 this.labelBackgroundGraphicsContext = svg
60782 .append("g")
60783 .classed(visuals.NewDataLabelUtils.labelBackgroundGraphicsContextClass.class, true);
60784 this.labelGraphicsContext = svg
60785 .append("g")
60786 .classed(visuals.NewDataLabelUtils.labelGraphicsContextClass.class, true);
60787 this.clearMaxShapeDimension();
60788 this.dataLabelsSettings = visuals.dataLabelUtils.getDefaultMapLabelSettings();
60789 };
60790 MapShapeDataPointRenderer.prototype.setData = function (data) {
60791 this.mapData = data;
60792 };
60793 MapShapeDataPointRenderer.prototype.clearDataPoints = function () {
60794 this.mapData = {
60795 dataPoints: [],
60796 geocodingCategory: null,
60797 hasDynamicSeries: false,
60798 hasSize: false,
60799 };
60800 };
60801 MapShapeDataPointRenderer.prototype.getDataPointCount = function () {
60802 if (!this.mapData)
60803 return 0;
60804 // Filter out any data points without a location since those aren't actually being drawn
60805 return _.filter(this.mapData.dataPoints, function (value) { return !!value.paths; }).length;
60806 };
60807 MapShapeDataPointRenderer.prototype.converter = function (viewport, dataView, labelSettings, interactivityService) {
60808 this.clearMaxShapeDimension();
60809 this.dataLabelsSettings = labelSettings;
60810 var strokeWidth = 1;
60811 var shapeData = [];
60812 var dataPoints = this.mapData ? this.mapData.dataPoints : [];
60813 for (var categoryIndex = 0, categoryCount = dataPoints.length; categoryIndex < categoryCount; categoryIndex++) {
60814 var categorical = dataView ? dataView.categorical : null;
60815 var dataPoint = dataPoints[categoryIndex];
60816 var subDataPoint = dataPoint.subDataPoints[0];
60817 var paths = dataPoint.paths;
60818 var grouped = void 0;
60819 var sizeIndex = -1;
60820 var dataValuesSource = void 0;
60821 if (categorical && categorical.values) {
60822 grouped = categorical.values.grouped();
60823 sizeIndex = DataRoleHelper.getMeasureIndexOfRole(grouped, "Size");
60824 dataValuesSource = categorical.values.source;
60825 }
60826 if (paths) {
60827 var value = dataPoint.value;
60828 var categoryValue = dataPoint.categoryValue;
60829 var identity = subDataPoint.identity;
60830 var idKey = identity.getKey();
60831 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
60832 //Determine Largest Shape
60833 var mainShapeIndex = MapShapeDataPointRenderer.getIndexOfLargestShape(paths);
60834 for (var pathIndex = 0, pathCount = paths.length; pathIndex < pathCount; pathIndex++) {
60835 var path = paths[pathIndex];
60836 var labelFormatString = (dataView && dataView.categorical && !_.isEmpty(dataView.categorical.values)) ? visuals.valueFormatter.getFormatString(dataView.categorical.values[0].source, visuals.filledMapProps.general.formatString) : undefined;
60837 this.setMaxShapeDimension(path.absoluteBounds.width, path.absoluteBounds.height);
60838 var formatter = formattersCache.getOrCreate(labelFormatString, labelSettings);
60839 shapeData.push({
60840 absolutePointArray: path.absolute,
60841 path: path.absoluteString,
60842 fill: subDataPoint.fill,
60843 stroke: subDataPoint.stroke,
60844 strokeWidth: strokeWidth,
60845 tooltipInfo: subDataPoint.tooltipInfo,
60846 identity: identity,
60847 selected: false,
60848 key: JSON.stringify({ id: idKey, pIdx: pathIndex }),
60849 displayLabel: pathIndex === mainShapeIndex,
60850 labeltext: categoryValue,
60851 catagoryLabeltext: (value != null) ? visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(value)) : undefined,
60852 labelFormatString: labelFormatString,
60853 });
60854 }
60855 }
60856 }
60857 if (interactivityService)
60858 interactivityService.applySelectionStateToData(shapeData);
60859 return { shapeData: shapeData };
60860 };
60861 MapShapeDataPointRenderer.prototype.updateInternal = function (data, viewport, dataChanged, interactivityService, redrawDataLabels) {
60862 debug.assertValue(viewport, "viewport");
60863 Map.removeTransform3d(this.root);
60864 this.mapRendererData = data;
60865 if (this.svg) {
60866 this.svg
60867 .style("width", viewport.width.toString() + "px")
60868 .style("height", viewport.height.toString() + "px");
60869 }
60870 if (this.clearSvg) {
60871 this.clearSvg
60872 .style("width", viewport.width.toString() + "px")
60873 .style("height", viewport.height.toString() + "px");
60874 }
60875 this.polygonInfo.reCalc(this.mapControl, viewport.width, viewport.height);
60876 this.shapeGraphicsContext.attr("transform", this.polygonInfo.transformToString(this.polygonInfo.transform));
60877 var hasSelection = interactivityService && interactivityService.hasSelection();
60878 var shapes = this.shapeGraphicsContext.selectAll("polygon").data(data.shapeData, function (d) { return d.key; });
60879 shapes.enter()
60880 .append("polygon")
60881 .classed("shape", true)
60882 .attr("points", function (d) {
60883 return d.path;
60884 });
60885 shapes
60886 .style("fill", function (d) { return d.fill; })
60887 .style("fill-opacity", function (d) { return visuals.ColumnUtil.getFillOpacity(d.selected, false, hasSelection, false); })
60888 .style("cursor", "default");
60889 if (dataChanged) {
60890 // We only update the paths of existing shapes if we have a change in the data. Updating the lengthy path
60891 // strings every update during resize or zooming/panning is extremely bad for performance.
60892 shapes
60893 .attr("points", function (d) {
60894 return d.path;
60895 });
60896 }
60897 shapes.exit()
60898 .remove();
60899 this.updateInternalDataLabels(viewport, redrawDataLabels);
60900 if (this.tooltipsEnabled) {
60901 visuals.TooltipManager.addTooltip(this.shapeGraphicsContext, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
60902 shapes.style("pointer-events", "all");
60903 }
60904 var behaviorOptions = {
60905 shapeEventGroup: this.shapeGraphicsContext,
60906 shapes: shapes,
60907 clearCatcher: this.clearCatcher,
60908 dataPoints: data.shapeData,
60909 };
60910 return behaviorOptions;
60911 };
60912 MapShapeDataPointRenderer.prototype.getDataPointPadding = function () {
60913 return 12;
60914 };
60915 MapShapeDataPointRenderer.getIndexOfLargestShape = function (paths) {
60916 var largestShapeIndex = 0;
60917 var largestShapeArea = 0;
60918 for (var pathIndex = 0, pathCount = paths.length; pathIndex < pathCount; pathIndex++) {
60919 var path = paths[pathIndex];
60920 // Using the area of the polygon (and taking the largest)
60921 var polygon = new Polygon(path.absolute);
60922 var currentShapeArea = Math.abs(Polygon.calculateAbsolutePolygonArea(polygon.polygonPoints));
60923 if (currentShapeArea > largestShapeArea) {
60924 largestShapeIndex = pathIndex;
60925 largestShapeArea = currentShapeArea;
60926 }
60927 }
60928 return largestShapeIndex;
60929 };
60930 MapShapeDataPointRenderer.prototype.updateInternalDataLabels = function (viewport, redrawDataLabels) {
60931 var labelSettings = this.dataLabelsSettings;
60932 var labels;
60933 if (labelSettings && (labelSettings.show || labelSettings.showCategory)) {
60934 var labelDataPoints = this.createLabelDataPoints();
60935 if (this.labelLayout === undefined) {
60936 this.labelLayout = new powerbi.FilledMapLabelLayout();
60937 }
60938 labels = this.labelLayout.layout(labelDataPoints, { width: viewport.width, height: viewport.height }, this.polygonInfo.transform, redrawDataLabels);
60939 }
60940 this.drawLabelStems(this.labelGraphicsContext, labels, labelSettings.show, labelSettings.showCategory);
60941 visuals.NewDataLabelUtils.drawLabelBackground(this.labelGraphicsContext, labels, powerbi.visuals.DefaultBackgroundColor, powerbi.visuals.DefaultFillOpacity);
60942 visuals.NewDataLabelUtils.drawDefaultLabels(this.labelGraphicsContext, labels, false, labelSettings.show && labelSettings.showCategory);
60943 };
60944 MapShapeDataPointRenderer.prototype.clearMaxShapeDimension = function () {
60945 this.maxShapeDimension = 0;
60946 };
60947 MapShapeDataPointRenderer.prototype.setMaxShapeDimension = function (width, height) {
60948 this.maxShapeDimension = Math.max(width, this.maxShapeDimension);
60949 this.maxShapeDimension = Math.max(height, this.maxShapeDimension);
60950 };
60951 MapShapeDataPointRenderer.prototype.createLabelDataPoints = function () {
60952 var data = this.mapRendererData;
60953 var labelDataPoints = [];
60954 if (this.filledMapDataLabelsEnabled) {
60955 var dataShapes = data.shapeData;
60956 var labelSettings = this.dataLabelsSettings;
60957 for (var _i = 0, dataShapes_1 = dataShapes; _i < dataShapes_1.length; _i++) {
60958 var dataShape = dataShapes_1[_i];
60959 if (!dataShape.displayLabel) {
60960 continue;
60961 }
60962 var text = void 0, secondRowText = void 0;
60963 var secondRowTextWidth = 0;
60964 var hasSecondRow = false;
60965 if (this.dataLabelsSettings.show && !this.dataLabelsSettings.showCategory) {
60966 text = dataShape.catagoryLabeltext;
60967 if (text === undefined)
60968 continue;
60969 }
60970 else if (this.dataLabelsSettings.showCategory && !this.dataLabelsSettings.show) {
60971 text = dataShape.labeltext;
60972 if (text === undefined)
60973 continue;
60974 }
60975 else if (this.dataLabelsSettings.showCategory && this.dataLabelsSettings.show) {
60976 text = dataShape.catagoryLabeltext;
60977 secondRowText = dataShape.labeltext;
60978 if (text === undefined && secondRowText === undefined)
60979 continue;
60980 hasSecondRow = true;
60981 }
60982 if (hasSecondRow) {
60983 var secondRowProperties = {
60984 text: secondRowText,
60985 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
60986 fontSize: visuals.NewDataLabelUtils.LabelTextProperties.fontSize,
60987 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
60988 };
60989 secondRowTextWidth = powerbi.TextMeasurementService.measureSvgTextWidth(secondRowProperties);
60990 }
60991 var firstRowProperties = {
60992 text: text,
60993 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
60994 fontSize: visuals.NewDataLabelUtils.LabelTextProperties.fontSize,
60995 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
60996 };
60997 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(firstRowProperties);
60998 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(firstRowProperties);
60999 if (secondRowText && dataShape.labeltext !== undefined && dataShape.catagoryLabeltext !== undefined) {
61000 textHeight = textHeight * 2;
61001 }
61002 var labelDataPoint = {
61003 parentType: 2 /* Polygon */,
61004 parentShape: {
61005 polygon: new Polygon(dataShape.absolutePointArray),
61006 validPositions: MapShapeDataPointRenderer.validLabelPolygonPositions,
61007 },
61008 text: text,
61009 secondRowText: secondRowText,
61010 textSize: {
61011 width: Math.max(textWidth, secondRowTextWidth),
61012 height: textHeight,
61013 },
61014 insideFill: labelSettings.labelColor,
61015 outsideFill: labelSettings.labelColor ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultInsideLabelColor,
61016 isPreferred: false,
61017 identity: undefined,
61018 hasBackground: true,
61019 };
61020 labelDataPoints.push(labelDataPoint);
61021 }
61022 }
61023 return labelDataPoints;
61024 };
61025 MapShapeDataPointRenderer.prototype.drawLabelStems = function (labelsContext, dataLabels, showText, showCategory) {
61026 var filteredLabels = _.filter(dataLabels, function (d) { return d.isVisible; });
61027 var key = function (d, index) { return d.identity ? d.identity.getKeyWithoutHighlight() : index; };
61028 visuals.NewDataLabelUtils.drawLabelLeaderLines(labelsContext, filteredLabels, key, visuals.LeaderLineColor);
61029 };
61030 MapShapeDataPointRenderer.validLabelPolygonPositions = [256 /* Center */, 2 /* Below */, 1 /* Above */, 8 /* Right */, 4 /* Left */, 16 /* BelowRight */, 32 /* BelowLeft */, 64 /* AboveRight */, 128 /* AboveLeft */];
61031 return MapShapeDataPointRenderer;
61032 }());
61033 visuals.MapShapeDataPointRenderer = MapShapeDataPointRenderer;
61034 var DefaultLocationZoomLevel = 11;
61035 var Map = (function () {
61036 function Map(options) {
61037 if (options.filledMap) {
61038 this.dataPointRenderer = new MapShapeDataPointRenderer(options.filledMapDataLabelsEnabled, options.tooltipsEnabled);
61039 this.filledMapDataLabelsEnabled = options.filledMapDataLabelsEnabled;
61040 this.isFilledMap = true;
61041 }
61042 else {
61043 this.dataPointRenderer = new MapBubbleDataPointRenderer(options.tooltipsEnabled);
61044 this.isFilledMap = false;
61045 }
61046 this.mapControlFactory = options.mapControlFactory ? options.mapControlFactory : this.getDefaultMapControlFactory();
61047 this.behavior = options.behavior;
61048 this.tooltipsEnabled = options.tooltipsEnabled;
61049 this.disableZooming = options.disableZooming;
61050 this.disablePanning = options.disablePanning;
61051 this.isLegendScrollable = !!options.behavior;
61052 this.viewChangeThrottleInterval = options.viewChangeThrottleInterval;
61053 this.enableCurrentLocation = options.enableCurrentLocation;
61054 this.boundsHaveBeenUpdated = false;
61055 }
61056 Map.prototype.init = function (options) {
61057 var _this = this;
61058 debug.assertValue(options, 'options');
61059 var element = this.element = $("<div>");
61060 element.appendTo(options.element);
61061 this.pendingGeocodingRender = false;
61062 this.currentViewport = options.viewport;
61063 this.style = options.style;
61064 this.colors = this.style.colorPalette.dataColors;
61065 if (this.behavior)
61066 this.interactivityService = visuals.createInteractivityService(options.host);
61067 this.dataLabelsSettings = visuals.dataLabelUtils.getDefaultMapLabelSettings();
61068 this.legend = powerbi.visuals.createLegend(element, options.interactivity && options.interactivity.isInteractiveLegend, this.interactivityService, this.isLegendScrollable);
61069 this.legendHeight = 0;
61070 this.legendData = { dataPoints: [] };
61071 this.geoTaggingAnalyzerService = powerbi.createGeoTaggingAnalyzerService(options.host.getLocalizedString);
61072 this.host = options.host;
61073 if (options.host.locale)
61074 this.locale = options.host.locale();
61075 this.geocoder = options.host.geocoder();
61076 this.resetBounds();
61077 this.mapControlFactory.ensureMap(this.locale, function () {
61078 Map.removeHillShading();
61079 Microsoft.Maps.loadModule('Microsoft.Maps.Overlays.Style', {
61080 callback: function () {
61081 _this.initialize(element[0]);
61082 if (_this.enableCurrentLocation) {
61083 _this.createCurrentLocation(element);
61084 }
61085 }
61086 });
61087 });
61088 };
61089 Map.prototype.createCurrentLocation = function (element) {
61090 var _this = this;
61091 var myLocBtn = InJs.DomFactory.div().addClass("mapCurrentLocation").appendTo(element);
61092 var pushpin;
61093 myLocBtn.on('click', function () {
61094 if (_this.isCurrentLocation) {
61095 // Restore previous map view and remove pushpin
61096 if (pushpin) {
61097 _this.mapControl.entities.remove(pushpin);
61098 }
61099 _this.updateInternal(false, false);
61100 _this.isCurrentLocation = false;
61101 }
61102 else {
61103 _this.host.geolocation().getCurrentPosition(function (position) {
61104 var location = new Microsoft.Maps.Location(position.coords.latitude, position.coords.longitude);
61105 if (pushpin) {
61106 _this.mapControl.entities.remove(pushpin);
61107 }
61108 pushpin = visuals.MapUtil.CurrentLocation.createPushpin(location);
61109 _this.mapControl.entities.push(pushpin);
61110 _this.updateMapView(location, DefaultLocationZoomLevel);
61111 _this.isCurrentLocation = true;
61112 });
61113 }
61114 });
61115 };
61116 Map.prototype.addDataPoint = function (dataPoint) {
61117 var location = dataPoint.location;
61118 this.updateBounds(location.latitude, location.longitude);
61119 this.scheduleRedraw();
61120 };
61121 Map.prototype.scheduleRedraw = function () {
61122 var _this = this;
61123 if (!this.pendingGeocodingRender && this.mapControl) {
61124 this.pendingGeocodingRender = true;
61125 // Maintain a 3 second delay between redraws from geocoded geometry
61126 setTimeout(function () {
61127 _this.updateInternal(true, true);
61128 _this.pendingGeocodingRender = false;
61129 }, 3000);
61130 }
61131 };
61132 Map.prototype.enqueueGeoCode = function (dataPoint) {
61133 var _this = this;
61134 var location = this.geocoder.tryGeocodeImmediate(dataPoint.geocodingQuery, this.geocodingCategory);
61135 if (location)
61136 this.completeGeoCode(dataPoint, location);
61137 else {
61138 var geocodingContext_1 = this.geocodingContext;
61139 this.geocoder.geocode(dataPoint.geocodingQuery, this.geocodingCategory).then(function (location) {
61140 if (location && geocodingContext_1 === _this.geocodingContext) {
61141 _this.completeGeoCode(dataPoint, location);
61142 }
61143 });
61144 }
61145 };
61146 Map.prototype.completeGeoCode = function (dataPoint, location) {
61147 dataPoint.location = location;
61148 this.addDataPoint(dataPoint);
61149 };
61150 Map.prototype.enqueueGeoCodeAndGeoShape = function (dataPoint, params) {
61151 var _this = this;
61152 var location = this.geocoder.tryGeocodeImmediate(dataPoint.geocodingQuery, this.geocodingCategory);
61153 if (location)
61154 this.completeGeoCodeAndGeoShape(dataPoint, params, location);
61155 else {
61156 var geocodingContext_2 = this.geocodingContext;
61157 this.geocoder.geocode(dataPoint.geocodingQuery, this.geocodingCategory).then(function (location) {
61158 if (location && geocodingContext_2 === _this.geocodingContext) {
61159 _this.completeGeoCodeAndGeoShape(dataPoint, params, location);
61160 }
61161 });
61162 }
61163 };
61164 Map.prototype.completeGeoCodeAndGeoShape = function (dataPoint, params, location) {
61165 dataPoint.location = location;
61166 this.enqueueGeoShape(dataPoint, params);
61167 };
61168 Map.prototype.enqueueGeoShape = function (dataPoint, params) {
61169 var _this = this;
61170 debug.assertValue(dataPoint.location, "cachedLocation");
61171 var result = this.geocoder.tryGeocodeBoundaryImmediate(dataPoint.location.latitude, dataPoint.location.longitude, this.geocodingCategory, params.level, params.maxPolygons);
61172 if (result)
61173 this.completeGeoShape(dataPoint, params, result);
61174 else {
61175 var geocodingContext_3 = this.geocodingContext;
61176 this.geocoder.geocodeBoundary(dataPoint.location.latitude, dataPoint.location.longitude, this.geocodingCategory, params.level, params.maxPolygons)
61177 .then(function (result) {
61178 if (geocodingContext_3 === _this.geocodingContext)
61179 _this.completeGeoShape(dataPoint, params, result);
61180 });
61181 }
61182 };
61183 Map.prototype.completeGeoShape = function (dataPoint, params, result) {
61184 var paths;
61185 if (result.locations.length === 0 || result.locations[0].geographic) {
61186 paths = MapShapeDataPointRenderer.buildPaths(result.locations);
61187 }
61188 else {
61189 visuals.MapUtil.calcGeoData(result);
61190 paths = MapShapeDataPointRenderer.buildPaths(result.locations);
61191 }
61192 dataPoint.paths = paths;
61193 this.addDataPoint(dataPoint);
61194 };
61195 Map.prototype.getOptimumLevelOfDetail = function (width, height) {
61196 var dataPointCount = this.dataPointRenderer.getDataPointCount();
61197 if (dataPointCount === 0)
61198 return visuals.MapUtil.MinLevelOfDetail;
61199 var threshold = this.dataPointRenderer.getDataPointPadding();
61200 for (var levelOfDetail = visuals.MapUtil.MaxLevelOfDetail; levelOfDetail >= visuals.MapUtil.MinLevelOfDetail; levelOfDetail--) {
61201 var minXmaxY = visuals.MapUtil.latLongToPixelXY(this.minLatitude, this.minLongitude, levelOfDetail);
61202 var maxXminY = visuals.MapUtil.latLongToPixelXY(this.maxLatitude, this.maxLongitude, levelOfDetail);
61203 if (maxXminY.x - minXmaxY.x + threshold <= width && minXmaxY.y - maxXminY.y + threshold <= height) {
61204 // if we have less than 2 data points we should not zoom in "too much"
61205 if (dataPointCount < 2)
61206 levelOfDetail = Math.min(visuals.MapUtil.MaxAutoZoomLevel, levelOfDetail);
61207 return levelOfDetail;
61208 }
61209 }
61210 return visuals.MapUtil.MinLevelOfDetail;
61211 };
61212 Map.prototype.getViewCenter = function (levelOfDetail) {
61213 var minXmaxY = visuals.MapUtil.latLongToPixelXY(this.minLatitude, this.minLongitude, levelOfDetail);
61214 var maxXminY = visuals.MapUtil.latLongToPixelXY(this.maxLatitude, this.maxLongitude, levelOfDetail);
61215 return visuals.MapUtil.pixelXYToLocation((minXmaxY.x + maxXminY.x) / 2.0, (maxXminY.y + minXmaxY.y) / 2.0, levelOfDetail);
61216 };
61217 Map.prototype.resetBounds = function () {
61218 this.boundsHaveBeenUpdated = false;
61219 this.minLongitude = visuals.MapUtil.MaxAllowedLongitude;
61220 this.maxLongitude = visuals.MapUtil.MinAllowedLongitude;
61221 this.minLatitude = visuals.MapUtil.MaxAllowedLatitude;
61222 this.maxLatitude = visuals.MapUtil.MinAllowedLatitude;
61223 };
61224 Map.prototype.updateBounds = function (latitude, longitude) {
61225 this.boundsHaveBeenUpdated = true;
61226 if (longitude < this.minLongitude) {
61227 this.minLongitude = longitude;
61228 }
61229 if (longitude > this.maxLongitude) {
61230 this.maxLongitude = longitude;
61231 }
61232 if (latitude < this.minLatitude) {
61233 this.minLatitude = latitude;
61234 }
61235 if (latitude > this.maxLatitude) {
61236 this.maxLatitude = latitude;
61237 }
61238 };
61239 Map.legendObject = function (dataView) {
61240 return dataView &&
61241 dataView.metadata &&
61242 dataView.metadata.objects &&
61243 dataView.metadata.objects['legend'];
61244 };
61245 Map.isLegendHidden = function (dataView) {
61246 var legendObject = Map.legendObject(dataView);
61247 return legendObject != null && legendObject[visuals.legendProps.show] === false;
61248 };
61249 Map.legendPosition = function (dataView) {
61250 var legendObject = Map.legendObject(dataView);
61251 return legendObject && visuals.LegendPosition[legendObject[visuals.legendProps.position]];
61252 };
61253 Map.getLegendFontSize = function (dataView) {
61254 var legendObject = Map.legendObject(dataView);
61255 return (legendObject && legendObject[visuals.legendProps.fontSize]) || visuals.SVGLegend.DefaultFontSizeInPt;
61256 };
61257 Map.isShowLegendTitle = function (dataView) {
61258 var legendObject = Map.legendObject(dataView);
61259 return legendObject && legendObject[visuals.legendProps.showTitle];
61260 };
61261 Map.prototype.legendTitle = function () {
61262 var legendObject = Map.legendObject(this.dataView);
61263 return (legendObject && legendObject[visuals.legendProps.titleText]) || this.legendData.title;
61264 };
61265 Map.prototype.renderLegend = function (legendData) {
61266 var hideLegend = Map.isLegendHidden(this.dataView);
61267 var showTitle = Map.isShowLegendTitle(this.dataView);
61268 var title = this.legendTitle();
61269 // Update the legendData based on the hide flag. Cartesian passes in no-datapoints. OnResize reuses the legendData, so this can't mutate.
61270 var clonedLegendData = {
61271 dataPoints: hideLegend ? [] : legendData.dataPoints,
61272 grouped: legendData.grouped,
61273 title: showTitle ? title : "",
61274 fontSize: Map.getLegendFontSize(this.dataView)
61275 };
61276 // Update the orientation to match what's in the dataView
61277 var targetOrientation = Map.legendPosition(this.dataView);
61278 if (targetOrientation !== undefined) {
61279 this.legend.changeOrientation(targetOrientation);
61280 }
61281 else {
61282 this.legend.changeOrientation(visuals.LegendPosition.Top);
61283 }
61284 this.legend.drawLegend(clonedLegendData, this.currentViewport);
61285 };
61286 /** Note: public for UnitTest */
61287 Map.calculateGroupSizes = function (categorical, grouped, groupSizeTotals, sizeMeasureIndex, currentValueScale) {
61288 var categoryCount = categorical.values[0].values.length;
61289 var seriesCount = grouped.length;
61290 for (var i = 0, len = categoryCount; i < len; ++i) {
61291 var groupTotal = null;
61292 if (sizeMeasureIndex >= 0) {
61293 for (var j = 0; j < seriesCount; ++j) {
61294 var value = grouped[j].values[sizeMeasureIndex].values[i];
61295 if (value) {
61296 if (groupTotal === null) {
61297 groupTotal = value;
61298 }
61299 else {
61300 groupTotal += value;
61301 }
61302 }
61303 }
61304 }
61305 groupSizeTotals.push(groupTotal);
61306 if (groupTotal) {
61307 if (!currentValueScale) {
61308 currentValueScale = {
61309 min: groupTotal,
61310 max: groupTotal
61311 };
61312 }
61313 else {
61314 currentValueScale.min = Math.min(currentValueScale.min, groupTotal);
61315 currentValueScale.max = Math.max(currentValueScale.max, groupTotal);
61316 }
61317 }
61318 }
61319 return currentValueScale;
61320 };
61321 /** Note: public for UnitTest */
61322 Map.calculateRadius = function (range, value) {
61323 var rangeDiff = range ? range.max - range.min : 0;
61324 var radius = 6;
61325 if (range != null && value != null && rangeDiff !== 0) {
61326 radius = (14 * ((value - range.min) / rangeDiff)) + 6;
61327 }
61328 return radius;
61329 };
61330 /** Note: public for UnitTest */
61331 Map.getGeocodingCategory = function (categorical, geoTaggingAnalyzerService) {
61332 if (categorical && categorical.categories && categorical.categories.length > 0 && categorical.categories[0].source) {
61333 // Check categoryString for manually specified information in the model
61334 var type = categorical.categories[0].source.type;
61335 if (type && type.categoryString) {
61336 return geoTaggingAnalyzerService.getFieldType(type.categoryString);
61337 }
61338 // Check the category name
61339 var categoryName = categorical.categories[0].source.displayName;
61340 var geotaggedResult = geoTaggingAnalyzerService.getFieldType(categoryName);
61341 if (geotaggedResult)
61342 return geotaggedResult;
61343 // Checking roles for VRM backwards compatibility
61344 var roles = categorical.categories[0].source.roles;
61345 if (roles) {
61346 var roleNames = Object.keys(roles);
61347 for (var i = 0, len = roleNames.length; i < len; ++i) {
61348 var typeFromRoleName = geoTaggingAnalyzerService.getFieldType(roleNames[i]);
61349 if (typeFromRoleName)
61350 return typeFromRoleName;
61351 }
61352 }
61353 }
61354 return undefined;
61355 };
61356 /** Note: public for UnitTest */
61357 Map.hasSizeField = function (values, defaultIndexIfNoRole) {
61358 if (_.isEmpty(values))
61359 return false;
61360 for (var i = 0, ilen = values.length; i < ilen; i++) {
61361 var roles = values[i].source.roles;
61362 // case for Power Q&A since Power Q&A does not assign role to measures.
61363 if (!roles && i === defaultIndexIfNoRole && values[i].source.type.numeric)
61364 return true;
61365 if (roles) {
61366 var roleNames = Object.keys(roles);
61367 for (var j = 0, jlen = roleNames.length; j < jlen; j++) {
61368 var role = roleNames[j];
61369 if (role === "Size")
61370 return true;
61371 }
61372 }
61373 }
61374 return false;
61375 };
61376 Map.shouldEnumerateDataPoints = function (dataView, usesSizeForGradient) {
61377 var hasSeries = DataRoleHelper.hasRoleInDataView(dataView, 'Series');
61378 var gradientRole = usesSizeForGradient ? 'Size' : 'Gradient';
61379 var hasGradientRole = DataRoleHelper.hasRoleInDataView(dataView, gradientRole);
61380 return hasSeries || !hasGradientRole;
61381 };
61382 Map.shouldEnumerateCategoryLabels = function (isFilledMap, filledMapDataLabelsEnabled) {
61383 return (!isFilledMap || filledMapDataLabelsEnabled);
61384 };
61385 Map.prototype.enumerateObjectInstances = function (options) {
61386 var enumeration = new visuals.ObjectEnumerationBuilder();
61387 switch (options.objectName) {
61388 case 'dataPoint':
61389 if (Map.shouldEnumerateDataPoints(this.dataView, this.isFilledMap)) {
61390 var bubbleData = [];
61391 //TODO: better way of getting this data
61392 var hasDynamicSeries = this.hasDynamicSeries;
61393 if (!hasDynamicSeries) {
61394 var mapData = this.dataPointRenderer.converter(this.getMapViewPort(), this.dataView, this.dataLabelsSettings, this.interactivityService, this.tooltipsEnabled);
61395 bubbleData = mapData.bubbleData;
61396 }
61397 Map.enumerateDataPoints(enumeration, this.dataPointsToEnumerate, this.colors, hasDynamicSeries, this.defaultDataPointColor, this.showAllDataPoints, bubbleData);
61398 }
61399 break;
61400 case 'categoryLabels':
61401 if (Map.shouldEnumerateCategoryLabels(this.isFilledMap, this.filledMapDataLabelsEnabled)) {
61402 visuals.dataLabelUtils.enumerateCategoryLabels(enumeration, this.dataLabelsSettings, true, true);
61403 }
61404 break;
61405 case 'legend':
61406 if (this.hasDynamicSeries) {
61407 Map.enumerateLegend(enumeration, this.dataView, this.legend, this.legendTitle());
61408 }
61409 break;
61410 case 'labels':
61411 if (this.filledMapDataLabelsEnabled) {
61412 this.dataLabelsSettings = this.dataLabelsSettings ? this.dataLabelsSettings : visuals.dataLabelUtils.getDefaultMapLabelSettings();
61413 var labelSettingOptions = {
61414 enumeration: enumeration,
61415 dataLabelsSettings: this.dataLabelsSettings,
61416 show: true,
61417 displayUnits: true,
61418 precision: true,
61419 };
61420 visuals.dataLabelUtils.enumerateDataLabels(labelSettingOptions);
61421 }
61422 break;
61423 }
61424 return enumeration.complete();
61425 };
61426 Map.enumerateDataPoints = function (enumeration, dataPoints, colors, hasDynamicSeries, defaultDataPointColor, showAllDataPoints, bubbleData) {
61427 var seriesLength = dataPoints && dataPoints.length;
61428 if (hasDynamicSeries) {
61429 for (var i = 0; i < seriesLength; i++) {
61430 var dataPoint = dataPoints[i];
61431 enumeration.pushInstance({
61432 objectName: 'dataPoint',
61433 displayName: dataPoint.label,
61434 selector: visuals.ColorHelper.normalizeSelector(dataPoint.identity.getSelector()),
61435 properties: {
61436 fill: { solid: { color: dataPoint.color } }
61437 },
61438 });
61439 }
61440 }
61441 else {
61442 enumeration.pushInstance({
61443 objectName: 'dataPoint',
61444 selector: null,
61445 properties: {
61446 defaultColor: { solid: { color: defaultDataPointColor || colors.getColorByIndex(0).value } }
61447 },
61448 }).pushInstance({
61449 objectName: 'dataPoint',
61450 selector: null,
61451 properties: {
61452 showAllDataPoints: !!showAllDataPoints
61453 },
61454 });
61455 if (bubbleData) {
61456 for (var i = 0; i < bubbleData.length; i++) {
61457 var bubbleDataPoint = bubbleData[i];
61458 enumeration.pushInstance({
61459 objectName: 'dataPoint',
61460 displayName: bubbleDataPoint.labeltext,
61461 selector: visuals.ColorHelper.normalizeSelector(bubbleDataPoint.identity.getSelector()),
61462 properties: {
61463 fill: { solid: { color: Color.normalizeToHexString(bubbleDataPoint.fill) } }
61464 },
61465 });
61466 }
61467 }
61468 }
61469 };
61470 Map.enumerateLegend = function (enumeration, dataView, legend, legendTitle) {
61471 enumeration.pushInstance({
61472 selector: null,
61473 properties: {
61474 show: !Map.isLegendHidden(dataView),
61475 position: visuals.LegendPosition[legend.getOrientation()],
61476 showTitle: Map.isShowLegendTitle(dataView),
61477 titleText: legendTitle,
61478 fontSize: Map.getLegendFontSize(dataView)
61479 },
61480 objectName: 'legend'
61481 });
61482 };
61483 Map.prototype.onDataChanged = function (options) {
61484 var _this = this;
61485 debug.assertValue(options, 'options');
61486 this.resetBounds();
61487 this.geocodingContext = {};
61488 if (this.behavior)
61489 this.behavior.resetZoomPan();
61490 this.dataLabelsSettings = visuals.dataLabelUtils.getDefaultMapLabelSettings();
61491 this.defaultDataPointColor = null;
61492 this.showAllDataPoints = null;
61493 var dataView = this.dataView = options.dataViews[0];
61494 var isFilledMap = this.isFilledMap;
61495 var warnings = [];
61496 var data = {
61497 dataPoints: [],
61498 geocodingCategory: null,
61499 hasDynamicSeries: false,
61500 hasSize: false,
61501 };
61502 if (dataView) {
61503 // Handle object-based settings
61504 if (dataView.metadata && dataView.metadata.objects) {
61505 var objects = dataView.metadata.objects;
61506 this.defaultDataPointColor = powerbi.DataViewObjects.getFillColor(objects, visuals.mapProps.dataPoint.defaultColor);
61507 this.showAllDataPoints = powerbi.DataViewObjects.getValue(objects, visuals.mapProps.dataPoint.showAllDataPoints);
61508 this.dataLabelsSettings.showCategory = powerbi.DataViewObjects.getValue(objects, visuals.filledMapProps.categoryLabels.show, this.dataLabelsSettings.showCategory);
61509 if (isFilledMap) {
61510 this.dataLabelsSettings.precision = powerbi.DataViewObjects.getValue(objects, visuals.filledMapProps.labels.labelPrecision, this.dataLabelsSettings.precision);
61511 this.dataLabelsSettings.precision = (this.dataLabelsSettings.precision !== visuals.dataLabelUtils.defaultLabelPrecision && this.dataLabelsSettings.precision < 0) ? 0 : this.dataLabelsSettings.precision;
61512 this.dataLabelsSettings.displayUnits = powerbi.DataViewObjects.getValue(objects, visuals.filledMapProps.labels.labelDisplayUnits, this.dataLabelsSettings.displayUnits);
61513 var datalabelsObj = objects['labels'];
61514 if (datalabelsObj) {
61515 this.dataLabelsSettings.show = (datalabelsObj['show'] !== undefined) ? datalabelsObj['show'] : this.dataLabelsSettings.show;
61516 if (datalabelsObj['color'] !== undefined) {
61517 this.dataLabelsSettings.labelColor = datalabelsObj['color'].solid.color;
61518 }
61519 }
61520 }
61521 else {
61522 var categoryLabelsObj = objects['categoryLabels'];
61523 if (categoryLabelsObj)
61524 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(categoryLabelsObj, this.dataLabelsSettings);
61525 }
61526 }
61527 // Convert data
61528 var colorHelper = new visuals.ColorHelper(this.colors, visuals.mapProps.dataPoint.fill, this.defaultDataPointColor);
61529 data = Map.converter(dataView, colorHelper, this.geoTaggingAnalyzerService, isFilledMap);
61530 this.hasDynamicSeries = data.hasDynamicSeries;
61531 // Create legend
61532 this.legendData = Map.createLegendData(dataView, colorHelper);
61533 this.dataPointsToEnumerate = this.legendData.dataPoints;
61534 this.renderLegend(this.legendData);
61535 // Start geocoding or geoshaping
61536 if (data != null) {
61537 this.geocodingCategory = data.geocodingCategory;
61538 this.mapControlFactory.ensureMap(this.locale, function () {
61539 Map.removeHillShading();
61540 var params;
61541 if (isFilledMap) {
61542 params = MapShapeDataPointRenderer.getFilledMapParams(_this.geocodingCategory, data.dataPoints.length);
61543 }
61544 for (var _i = 0, _a = data.dataPoints; _i < _a.length; _i++) {
61545 var dataPoint = _a[_i];
61546 if (!dataPoint.location) {
61547 if (!_.isEmpty(dataPoint.categoryValue)) {
61548 if (isFilledMap)
61549 _this.enqueueGeoCodeAndGeoShape(dataPoint, params);
61550 else
61551 _this.enqueueGeoCode(dataPoint);
61552 }
61553 }
61554 else if (isFilledMap && !dataPoint.paths) {
61555 _this.enqueueGeoShape(dataPoint, params);
61556 }
61557 else {
61558 _this.addDataPoint(dataPoint);
61559 }
61560 }
61561 });
61562 }
61563 else {
61564 // No data from conversion, so clear data points
61565 this.clearDataPoints();
61566 }
61567 if (isFilledMap) {
61568 if (!this.geocodingCategory || !this.geoTaggingAnalyzerService.isGeoshapable(this.geocodingCategory)) {
61569 warnings.push(new visuals.FilledMapWithoutValidGeotagCategoryWarning());
61570 }
61571 }
61572 }
61573 else {
61574 this.clearDataPoints();
61575 this.renderLegend({
61576 dataPoints: [],
61577 title: undefined,
61578 });
61579 this.dataPointsToEnumerate = [];
61580 }
61581 if (!_.isEmpty(warnings))
61582 this.host.setWarnings(warnings);
61583 this.dataPointRenderer.setData(data);
61584 this.updateInternal(true /* dataChanged */, true /* redrawDataLabels */);
61585 };
61586 Map.converter = function (dataView, colorHelper, geoTaggingAnalyzerService, isFilledMap) {
61587 var reader = powerbi.data.createIDataViewCategoricalReader(dataView);
61588 var dataPoints = [];
61589 var hasDynamicSeries = reader.hasDynamicSeries();
61590 var seriesColumnIdentifier = reader.getSeriesColumnIdentityFields();
61591 var sizeQueryName = reader.getMeasureQueryName('Size');
61592 if (sizeQueryName == null)
61593 sizeQueryName = '';
61594 var hasSize = reader.hasValues('Size');
61595 var geocodingCategory = null;
61596 var formatStringProp = visuals.mapProps.general.formatString;
61597 if (reader.hasCategories()) {
61598 // Calculate category totals and range for radius calculation
61599 var categoryTotals = [];
61600 var categoryTotalRange = void 0;
61601 if (hasSize) {
61602 var categoryMin = undefined;
61603 var categoryMax = undefined;
61604 for (var categoryIndex = 0, categoryCount = reader.getCategoryCount(); categoryIndex < categoryCount; categoryIndex++) {
61605 var categoryTotal = void 0;
61606 for (var seriesIndex = 0, seriesCount = reader.getSeriesCount(); seriesIndex < seriesCount; seriesIndex++) {
61607 var currentValue = reader.getValue('Size', categoryIndex, seriesIndex);
61608 // Dont initialze categoryTotal to zero until you find a null value so that it remains undefined for categories that have no non-null values (0 is rendered by filled map while null is not)
61609 if (categoryTotal == null && currentValue != null)
61610 categoryTotal = 0;
61611 if (categoryTotal != null)
61612 categoryTotal += currentValue;
61613 }
61614 categoryTotals.push(categoryTotal);
61615 if (categoryTotal != null) {
61616 if (categoryMin === undefined || categoryTotal < categoryMin)
61617 categoryMin = categoryTotal;
61618 if (categoryMax === undefined || categoryTotal > categoryMax)
61619 categoryMax = categoryTotal;
61620 }
61621 }
61622 categoryTotalRange = (categoryMin !== undefined && categoryMax !== undefined) ? {
61623 max: categoryMax,
61624 min: categoryMin,
61625 } : undefined;
61626 }
61627 var hasLatLongGroup = reader.hasCompositeCategories() && reader.hasCategoryWithRole('X') && reader.hasCategoryWithRole('Y');
61628 var hasCategoryGroup = reader.hasCategoryWithRole('Category');
61629 geocodingCategory = Map.getGeocodingCategory(dataView.categorical, geoTaggingAnalyzerService);
61630 if (hasLatLongGroup || hasCategoryGroup) {
61631 // Create data points
61632 for (var categoryIndex = 0, categoryCount = reader.getCategoryCount(); categoryIndex < categoryCount; categoryIndex++) {
61633 // Get category information
61634 var categoryValue = undefined;
61635 // The category objects should come from whichever category exists; in the case of a composite category, the objects should be the same for
61636 // both categories, so we only need to obtain them from one role.
61637 var categoryObjects = hasCategoryGroup ? reader.getCategoryObjects('Category', categoryIndex) : reader.getCategoryObjects('Y', categoryIndex);
61638 var location_4 = void 0;
61639 var categoryTooltipItem = void 0;
61640 var latitudeTooltipItem = void 0;
61641 var longitudeTooltipItem = void 0;
61642 var seriesTooltipItem = void 0;
61643 var sizeTooltipItem = void 0;
61644 var gradientTooltipItem = void 0;
61645 if (hasCategoryGroup) {
61646 // Set category value
61647 categoryValue = reader.getCategoryValue('Category', categoryIndex);
61648 categoryTooltipItem = {
61649 displayName: reader.getCategoryDisplayName('Category'),
61650 value: visuals.converterHelper.formatFromMetadataColumn(categoryValue, reader.getCategoryMetadataColumn('Category'), formatStringProp),
61651 };
61652 // Create location from latitude and longitude if they exist as values
61653 if (reader.hasValues('Y') && reader.hasValues('X')) {
61654 var latitude = reader.getFirstNonNullValueForCategory('Y', categoryIndex);
61655 var longitude = reader.getFirstNonNullValueForCategory('X', categoryIndex);
61656 if (latitude != null && longitude != null) {
61657 location_4 = { latitude: latitude, longitude: longitude };
61658 }
61659 latitudeTooltipItem = {
61660 displayName: reader.getValueDisplayName('Y'),
61661 value: visuals.converterHelper.formatFromMetadataColumn(latitude, reader.getValueMetadataColumn('Y'), formatStringProp),
61662 };
61663 longitudeTooltipItem = {
61664 displayName: reader.getValueDisplayName('X'),
61665 value: visuals.converterHelper.formatFromMetadataColumn(longitude, reader.getValueMetadataColumn('X'), formatStringProp),
61666 };
61667 }
61668 }
61669 else {
61670 var latitude = reader.getCategoryValue('Y', categoryIndex);
61671 var longitude = reader.getCategoryValue('X', categoryIndex);
61672 if (latitude != null && longitude != null) {
61673 // Combine latitude and longitude to create the category value
61674 categoryValue = latitude + ', ' + longitude;
61675 // Create location from latitude and longitude
61676 location_4 = { latitude: latitude, longitude: longitude };
61677 latitudeTooltipItem = {
61678 displayName: reader.getCategoryDisplayName('Y'),
61679 value: visuals.converterHelper.formatFromMetadataColumn(latitude, reader.getCategoryMetadataColumn('Y'), formatStringProp),
61680 };
61681 longitudeTooltipItem = {
61682 displayName: reader.getCategoryDisplayName('X'),
61683 value: visuals.converterHelper.formatFromMetadataColumn(longitude, reader.getCategoryMetadataColumn('X'), formatStringProp),
61684 };
61685 }
61686 }
61687 var value = hasSize ? categoryTotals[categoryIndex] : undefined;
61688 // Calculate sub data points by series
61689 var subDataPoints = [];
61690 var seriesCount = reader.getSeriesCount();
61691 if (!hasSize && !hasDynamicSeries) {
61692 seriesCount = 1;
61693 }
61694 for (var seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
61695 var color = void 0;
61696 if (hasDynamicSeries) {
61697 color = colorHelper.getColorForSeriesValue(reader.getSeriesObjects(seriesIndex), seriesColumnIdentifier, (reader.getSeriesName(seriesIndex)));
61698 }
61699 else if (reader.hasCategoryWithRole('Series')) {
61700 color = colorHelper.getColorForSeriesValue(reader.getCategoryObjects('Series', categoryIndex), reader.getCategoryColumnIdentityFields('Series'), categoryValue);
61701 }
61702 else {
61703 color = colorHelper.getColorForMeasure(categoryObjects, sizeQueryName);
61704 }
61705 var colorRgb = Color.parseColorString(color);
61706 var stroke = Color.hexString(Color.darken(colorRgb, Map.StrokeDarkenColorValue));
61707 colorRgb.A = 0.6;
61708 var fill = Color.rgbString(colorRgb);
61709 var identityBuilder = new visuals.SelectionIdBuilder()
61710 .withCategory(reader.getCategoryColumn(hasCategoryGroup ? 'Category' : 'Y'), categoryIndex)
61711 .withMeasure(sizeQueryName);
61712 if (hasDynamicSeries) {
61713 identityBuilder = identityBuilder.withSeries(reader.getSeriesValueColumns(), reader.getSeriesValueColumnGroup(seriesIndex));
61714 }
61715 if (hasDynamicSeries) {
61716 seriesTooltipItem = {
61717 displayName: reader.getSeriesDisplayName(),
61718 value: visuals.converterHelper.formatFromMetadataColumn(reader.getSeriesName(seriesIndex), reader.getSeriesMetadataColumn(), formatStringProp),
61719 };
61720 }
61721 var subsliceValue = void 0;
61722 if (hasSize) {
61723 subsliceValue = reader.getValue('Size', categoryIndex, seriesIndex);
61724 sizeTooltipItem = {
61725 displayName: reader.getValueDisplayName('Size'),
61726 value: visuals.converterHelper.formatFromMetadataColumn(subsliceValue, reader.getValueMetadataColumn('Size', seriesIndex), formatStringProp),
61727 };
61728 }
61729 if (reader.hasValues('Gradient')) {
61730 gradientTooltipItem = {
61731 displayName: reader.getValueDisplayName('Gradient'),
61732 value: visuals.converterHelper.formatFromMetadataColumn(reader.getValue('Gradient', categoryIndex, seriesIndex), reader.getValueMetadataColumn('Gradient', seriesIndex), formatStringProp),
61733 };
61734 }
61735 // Combine any existing tooltip items
61736 var tooltipInfo = [];
61737 if (categoryTooltipItem)
61738 tooltipInfo.push(categoryTooltipItem);
61739 if (seriesTooltipItem)
61740 tooltipInfo.push(seriesTooltipItem);
61741 if (latitudeTooltipItem)
61742 tooltipInfo.push(latitudeTooltipItem);
61743 if (longitudeTooltipItem)
61744 tooltipInfo.push(longitudeTooltipItem);
61745 if (sizeTooltipItem)
61746 tooltipInfo.push(sizeTooltipItem);
61747 if (gradientTooltipItem)
61748 tooltipInfo.push(gradientTooltipItem);
61749 // Do not create subslices for data points with null or zero if not filled map
61750 if (subsliceValue || !hasSize || (subsliceValue === 0 && isFilledMap)) {
61751 subDataPoints.push({
61752 value: subsliceValue,
61753 fill: fill,
61754 stroke: stroke,
61755 identity: identityBuilder.createSelectionId(),
61756 tooltipInfo: tooltipInfo,
61757 });
61758 }
61759 }
61760 // Skip data points that have a null or zero if not filled map
61761 if (value || !hasSize || (value === 0 && isFilledMap)) {
61762 dataPoints.push({
61763 geocodingQuery: categoryValue,
61764 value: value,
61765 categoryValue: categoryValue,
61766 subDataPoints: subDataPoints,
61767 radius: Map.calculateRadius(categoryTotalRange, value),
61768 location: location_4,
61769 });
61770 }
61771 }
61772 }
61773 }
61774 var mapData = {
61775 dataPoints: dataPoints,
61776 geocodingCategory: geocodingCategory,
61777 hasDynamicSeries: hasDynamicSeries,
61778 hasSize: hasSize,
61779 };
61780 return mapData;
61781 };
61782 Map.createLegendData = function (dataView, colorHelper) {
61783 var reader = powerbi.data.createIDataViewCategoricalReader(dataView);
61784 var legendDataPoints = [];
61785 var legendTitle;
61786 if (reader.hasDynamicSeries()) {
61787 legendTitle = reader.getSeriesDisplayName();
61788 var seriesColumnIdentifier = reader.getSeriesColumnIdentityFields();
61789 for (var seriesIndex = 0, seriesCount = reader.getSeriesCount(); seriesIndex < seriesCount; seriesIndex++) {
61790 var color = colorHelper.getColorForSeriesValue(reader.getSeriesObjects(seriesIndex), seriesColumnIdentifier, reader.getSeriesName(seriesIndex));
61791 var identity = new visuals.SelectionIdBuilder().withSeries(reader.getSeriesValueColumns(), reader.getSeriesValueColumnGroup(seriesIndex)).createSelectionId();
61792 legendDataPoints.push({
61793 color: color,
61794 label: visuals.valueFormatter.format(reader.getSeriesName(seriesIndex)),
61795 icon: visuals.LegendIcon.Circle,
61796 identity: identity,
61797 selected: false,
61798 });
61799 }
61800 }
61801 var legendData = {
61802 dataPoints: legendDataPoints,
61803 title: legendTitle,
61804 };
61805 return legendData;
61806 };
61807 Map.prototype.swapLogoContainerChildElement = function () {
61808 // This is a workaround that allow maps to be printed from the IE and Edge browsers.
61809 // For some unknown reason, the presence of an <a> child element in the .LogoContainer
61810 // prevents dashboard map visuals from showing up when printed.
61811 // The trick is to swap out the <a> element with a <div> container.
61812 // There are no user impacts or visual changes.
61813 var logoContainer = this.element.find('.LogoContainer');
61814 if (logoContainer) {
61815 var aNode = logoContainer.find('a');
61816 if (aNode == null)
61817 return;
61818 var divNode = $('<div>');
61819 aNode.children().clone().appendTo(divNode);
61820 aNode.remove();
61821 divNode.appendTo(logoContainer);
61822 }
61823 };
61824 Map.prototype.onResizing = function (viewport) {
61825 if (this.currentViewport.width !== viewport.width || this.currentViewport.height !== viewport.height) {
61826 this.currentViewport = viewport;
61827 this.renderLegend(this.legendData);
61828 this.updateInternal(false /* dataChanged */, false);
61829 }
61830 };
61831 Map.prototype.initialize = function (container) {
61832 var _this = this;
61833 var mapOptions = {
61834 credentials: visuals.MapUtil.Settings.BingKey,
61835 showMapTypeSelector: false,
61836 enableClickableLogo: false,
61837 enableSearchLogo: false,
61838 mapTypeId: Microsoft.Maps.MapTypeId.road,
61839 customizeOverlays: true,
61840 showDashboard: false,
61841 showScalebar: false,
61842 disableKeyboardInput: true,
61843 disableZooming: this.disableZooming,
61844 disablePanning: this.disablePanning,
61845 };
61846 var divQuery = this.root = InJs.DomFactory.div().addClass(Map.MapContainer.cssClass).appendTo(container);
61847 this.mapControl = this.mapControlFactory.createMapControl(divQuery[0], mapOptions);
61848 if (this.viewChangeThrottleInterval !== undefined) {
61849 Microsoft.Maps.Events.addThrottledHandler(this.mapControl, 'viewchange', function () { _this.onViewChanged(); }, this.viewChangeThrottleInterval);
61850 }
61851 else {
61852 Microsoft.Maps.Events.addHandler(this.mapControl, 'viewchange', function () { _this.onViewChanged(); });
61853 }
61854 Microsoft.Maps.Events.addHandler(this.mapControl, "viewchangeend", function () { _this.onViewChangeEnded(); });
61855 this.dataPointRenderer.init(this.mapControl, divQuery, !!this.behavior);
61856 if (!this.pendingGeocodingRender) {
61857 this.updateInternal(true /* dataChanged */, true);
61858 }
61859 };
61860 Map.prototype.onViewChanged = function () {
61861 this.updateOffsets(false, false /* dataChanged */);
61862 if (this.behavior)
61863 this.behavior.viewChanged();
61864 this.swapLogoContainerChildElement();
61865 };
61866 Map.prototype.onViewChangeEnded = function () {
61867 this.dataPointRenderer.updateInternalDataLabels(this.currentViewport, true);
61868 };
61869 Map.prototype.getMapViewPort = function () {
61870 var currentViewport = this.currentViewport;
61871 var legendMargins = this.legend.getMargins();
61872 var mapViewport = {
61873 width: currentViewport.width - legendMargins.width,
61874 height: currentViewport.height - legendMargins.height,
61875 };
61876 return mapViewport;
61877 };
61878 Map.removeTransform3d = function (mapRoot) {
61879 // don't remove transform3d from bing maps images in safari (using applewebkit engine)
61880 var userAgent = window.navigator.userAgent.toLowerCase();
61881 if (mapRoot && userAgent.indexOf('applewebkit') === -1) {
61882 var imageTiles = mapRoot.find('img');
61883 imageTiles.css('transform', '');
61884 }
61885 };
61886 Map.prototype.updateInternal = function (dataChanged, redrawDataLabels) {
61887 if (this.mapControl) {
61888 var isLegendVisible = this.legend.isVisible();
61889 if (!isLegendVisible)
61890 this.legendData = { dataPoints: [] };
61891 var mapDiv = this.element.children(Map.MapContainer.selector);
61892 var mapViewport = this.getMapViewPort();
61893 mapDiv.height(mapViewport.height);
61894 mapDiv.width(mapViewport.width);
61895 // With the risk of double drawing, if the position updates to nearly the same, the map control won't call viewchange, so explicitly update the points
61896 this.updateOffsets(dataChanged, redrawDataLabels);
61897 // Set zoom level after we rendered that map as we need the max size of the bubbles/ pie slices to calculate it
61898 if (this.boundsHaveBeenUpdated && !(this.behavior && this.behavior.hasReceivedZoomOrPanEvent())) {
61899 var levelOfDetail = this.getOptimumLevelOfDetail(mapViewport.width, mapViewport.height);
61900 var center = this.getViewCenter(levelOfDetail);
61901 this.updateMapView(center, levelOfDetail);
61902 }
61903 }
61904 };
61905 Map.prototype.updateMapView = function (center, levelOfDetail) {
61906 this.mapControl.setView({ center: center, zoom: levelOfDetail, animate: true });
61907 };
61908 Map.prototype.updateOffsets = function (dataChanged, redrawDataLabels) {
61909 var dataView = this.dataView;
61910 var data;
61911 var viewport = this.getMapViewPort();
61912 if (dataView && dataView.categorical) {
61913 // currentViewport may not exist in UnitTests
61914 data = this.dataPointRenderer.converter(viewport, this.dataView, this.dataLabelsSettings, this.interactivityService, this.tooltipsEnabled);
61915 }
61916 else {
61917 data = {
61918 bubbleData: [],
61919 shapeData: [],
61920 sliceData: [],
61921 };
61922 }
61923 var behaviorOptions = this.dataPointRenderer.updateInternal(data, viewport, dataChanged, this.interactivityService, redrawDataLabels);
61924 visuals.Legend.positionChartArea(d3.select(this.root[0]), this.legend);
61925 if (this.interactivityService && behaviorOptions) {
61926 this.interactivityService.bind(behaviorOptions.dataPoints, this.behavior, behaviorOptions);
61927 }
61928 };
61929 Map.prototype.onClearSelection = function () {
61930 this.interactivityService.clearSelection();
61931 this.updateOffsets(false, false /* dataChanged */);
61932 };
61933 Map.prototype.clearDataPoints = function () {
61934 this.dataPointRenderer.clearDataPoints();
61935 this.legend.drawLegend({ dataPoints: [] }, this.currentViewport);
61936 };
61937 Map.prototype.getDefaultMapControlFactory = function () {
61938 return {
61939 createMapControl: function (element, options) { return new Microsoft.Maps.Map(element, options); },
61940 ensureMap: jsCommon.ensureMap,
61941 };
61942 };
61943 Map.removeHillShading = function () {
61944 Microsoft.Maps.Globals.roadUriFormat = Microsoft.Maps.Globals.roadUriFormat.replace('&shading=hill', '');
61945 };
61946 Map.MapContainer = {
61947 cssClass: 'mapControl',
61948 selector: '.mapControl'
61949 };
61950 Map.StrokeDarkenColorValue = 255 * 0.25;
61951 return Map;
61952 }());
61953 visuals.Map = Map;
61954 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
61955})(powerbi || (powerbi = {}));
61956/*
61957 * Power BI Visualizations
61958 *
61959 * Copyright (c) Microsoft Corporation
61960 * All rights reserved.
61961 * MIT License
61962 *
61963 * Permission is hereby granted, free of charge, to any person obtaining a copy
61964 * of this software and associated documentation files (the ""Software""), to deal
61965 * in the Software without restriction, including without limitation the rights
61966 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
61967 * copies of the Software, and to permit persons to whom the Software is
61968 * furnished to do so, subject to the following conditions:
61969 *
61970 * The above copyright notice and this permission notice shall be included in
61971 * all copies or substantial portions of the Software.
61972 *
61973 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61974 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61975 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61976 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
61977 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
61978 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61979 * THE SOFTWARE.
61980 */
61981var powerbi;
61982(function (powerbi) {
61983 var visuals;
61984 (function (visuals) {
61985 var getKpiImageMetadata = powerbi.visuals.KpiUtil.getKpiImageMetadata;
61986 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
61987 var PixelConverter = jsCommon.PixelConverter;
61988 var UrlUtils = jsCommon.UrlUtils;
61989 var EdgeSettings = powerbi.visuals.controls.internal.TablixUtils.EdgeSettings;
61990 var TitleFontFamily = 'wf_segoe-ui_semibold';
61991 var DefaultFontFamily = 'wf_segoe-ui_normal';
61992 var DefaultCaptionFontSizeInPt = 10;
61993 var DefaultTitleFontSizeInPt = 13;
61994 var DefaultDetailFontSizeInPt = 9;
61995 var DefaultTitleColor = '#767676';
61996 var DefaultTextColor = '#333333';
61997 var DefaultCategoryColor = '#ACACAC';
61998 var DefaultOutline = visuals.outline.none;
61999 var DefaultOutlineColor = '#E8E8E8';
62000 var DefaultOutlineWeight = 1;
62001 var DefaultBarShow = true;
62002 var DefaultBarColor = '#A6A6A6';
62003 var DefaultBarOutline = visuals.outline.leftOnly;
62004 var DefaultBarWeight = 3;
62005 var MultiRowCard = (function () {
62006 function MultiRowCard() {
62007 this.isInteractivityOverflowHidden = false;
62008 }
62009 MultiRowCard.prototype.init = function (options) {
62010 debug.assertValue(options, 'options');
62011 this.options = options;
62012 this.style = options.style;
62013 var viewport = this.currentViewport = options.viewport;
62014 var interactivity = this.interactivity = options.interactivity;
62015 if (interactivity && interactivity.overflow === 'hidden')
62016 this.isInteractivityOverflowHidden = true;
62017 var multiRowCardDiv = this.element = $('<div/>')
62018 .addClass(MultiRowCard.MultiRowCardRoot.class)
62019 .css({
62020 'height': getPixelString(viewport.height),
62021 });
62022 options.element.append(multiRowCardDiv);
62023 this.initializeCardRowSelection();
62024 };
62025 MultiRowCard.prototype.onDataChanged = function (options) {
62026 debug.assertValue(options, 'options');
62027 var dataViews = options.dataViews;
62028 if (dataViews && dataViews.length > 0) {
62029 var dataView = this.dataView = dataViews[0];
62030 var columnMetadata = dataView.table.columns;
62031 var tableRows = dataView.table.rows;
62032 var resetScrollbarPosition = options.operationKind !== powerbi.VisualDataChangeOperationKind.Append;
62033 var data_2 = this.data = MultiRowCard.converter(dataView, columnMetadata.length, tableRows.length, this.isInteractivityOverflowHidden);
62034 this.setCardDimensions();
62035 this.listView.data(data_2.dataModel, function (d) { return data_2.dataModel.indexOf(d); }, resetScrollbarPosition);
62036 }
62037 else {
62038 this.data = {
62039 dataModel: [],
62040 dataColumnCount: 0,
62041 cardTitleSettings: visuals.dataLabelUtils.getDefaultLabelSettings(true, DefaultTitleColor, DefaultTitleFontSizeInPt),
62042 categoryLabelsSettings: visuals.dataLabelUtils.getDefaultLabelSettings(true, DefaultCategoryColor, DefaultDetailFontSizeInPt),
62043 dataLabelsSettings: visuals.dataLabelUtils.getDefaultLabelSettings(true, DefaultTextColor, DefaultCaptionFontSizeInPt),
62044 cardSettings: MultiRowCard.getCardSettings(null)
62045 };
62046 }
62047 this.waitingForData = false;
62048 };
62049 MultiRowCard.getCardSettings = function (dataView) {
62050 var objects = dataView && dataView.metadata && dataView.metadata.objects ? dataView.metadata.objects : null;
62051 var outlineSettings = {
62052 outline: powerbi.DataViewObjects.getValue(objects, visuals.multiRowCardProps.card.outline, DefaultOutline),
62053 color: powerbi.DataViewObjects.getFillColor(objects, visuals.multiRowCardProps.card.outlineColor, DefaultOutlineColor),
62054 weight: powerbi.DataViewObjects.getValue(objects, visuals.multiRowCardProps.card.outlineWeight, DefaultOutlineWeight),
62055 };
62056 var barShow = powerbi.DataViewObjects.getValue(objects, visuals.multiRowCardProps.card.barShow, DefaultBarShow);
62057 var barSettings = {
62058 // If the bar is hidden, set the outline to none
62059 outline: barShow ? DefaultBarOutline : visuals.outline.none,
62060 color: powerbi.DataViewObjects.getFillColor(objects, visuals.multiRowCardProps.card.barColor, DefaultBarColor),
62061 weight: powerbi.DataViewObjects.getValue(objects, visuals.multiRowCardProps.card.barWeight, DefaultBarWeight),
62062 };
62063 var cardPadding = powerbi.DataViewObjects.getValue(objects, visuals.multiRowCardProps.card.cardPadding, MultiRowCard.DefaultStyle.row.marginBottom);
62064 var cardBackground = powerbi.DataViewObjects.getFillColor(objects, visuals.multiRowCardProps.card.cardBackground, MultiRowCard.DefaultStyle.row.background);
62065 return {
62066 outlineSettings: outlineSettings,
62067 barSettings: barSettings,
62068 cardPadding: cardPadding,
62069 cardBackground: cardBackground
62070 };
62071 };
62072 MultiRowCard.prototype.onResizing = function (viewport) {
62073 var heightNotChanged = (this.currentViewport.height === viewport.height);
62074 this.currentViewport = viewport;
62075 this.element.css('height', getPixelString(viewport.height));
62076 if (!this.dataView)
62077 return;
62078 var previousMaxColPerRow = this.maxColPerRow;
62079 this.maxColPerRow = this.getMaxColPerRow();
62080 var widthNotChanged = (previousMaxColPerRow === this.maxColPerRow);
62081 if (heightNotChanged && widthNotChanged)
62082 return;
62083 this.listView.viewport(viewport);
62084 };
62085 MultiRowCard.converter = function (dataView, columnCount, maxCards, isDashboardVisual) {
62086 if (isDashboardVisual === void 0) { isDashboardVisual = false; }
62087 var details = [];
62088 var tableDataRows = dataView.table.rows;
62089 var columnMetadata = dataView.table.columns;
62090 var cardTitleSettings, dataLabelsSettings, categoryLabelsSettings;
62091 cardTitleSettings = visuals.dataLabelUtils.getDefaultLabelSettings(true, DefaultTitleColor, DefaultTitleFontSizeInPt);
62092 dataLabelsSettings = visuals.dataLabelUtils.getDefaultLabelSettings(true, DefaultTextColor, DefaultCaptionFontSizeInPt);
62093 categoryLabelsSettings = visuals.dataLabelUtils.getDefaultLabelSettings(true, DefaultCategoryColor, DefaultDetailFontSizeInPt);
62094 if (dataView.metadata && dataView.metadata.objects) {
62095 var cardTitleLabelObjects = powerbi.DataViewObjects.getObject(dataView.metadata.objects, 'cardTitle');
62096 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(cardTitleLabelObjects, cardTitleSettings);
62097 var dataLabelObject = powerbi.DataViewObjects.getObject(dataView.metadata.objects, 'dataLabels');
62098 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(dataLabelObject, dataLabelsSettings);
62099 var categoryLabelObject = powerbi.DataViewObjects.getObject(dataView.metadata.objects, 'categoryLabels');
62100 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(categoryLabelObject, categoryLabelsSettings);
62101 }
62102 for (var i = 0, len = maxCards; i < len; i++) {
62103 var row = tableDataRows[i];
62104 var isValuePromoted = undefined;
62105 var title = undefined;
62106 var showTitleAsURL = false;
62107 var showTitleAsImage = false;
62108 var showTitleAsKPI = false;
62109 var cardData = [];
62110 for (var j = 0; j < columnCount; j++) {
62111 var column = columnMetadata[j];
62112 var statusGraphicInfo = getKpiImageMetadata(column, row[j]);
62113 var columnCaption = void 0;
62114 var statusGraphic = void 0;
62115 if (statusGraphicInfo) {
62116 columnCaption = statusGraphicInfo.class;
62117 statusGraphic = statusGraphicInfo.statusGraphic;
62118 }
62119 //TODO: seems we are duplicating this logic in many places. Consider putting it in KPIUtil
62120 if (!columnCaption)
62121 columnCaption = visuals.valueFormatter.format(row[j], visuals.valueFormatter.getFormatString(column, MultiRowCard.formatStringProp));
62122 var showKPI = statusGraphicInfo !== undefined && statusGraphicInfo.caption !== undefined;
62123 // The columnDetail represents column name. In card the column name is shown as details
62124 var columnDetail = columnMetadata[j].displayName;
62125 //Title is shown only on Canvas and only if there is one Category field.
62126 if (!isDashboardVisual && !column.type.numeric) {
62127 if (isValuePromoted === undefined) {
62128 isValuePromoted = true;
62129 title = columnCaption;
62130 showTitleAsURL = visuals.converterHelper.isWebUrlColumn(column) && UrlUtils.isValidUrl(title);
62131 showTitleAsImage = visuals.converterHelper.isImageUrlColumn(column) && UrlUtils.isValidImageUrl(columnCaption);
62132 showTitleAsKPI = showKPI;
62133 }
62134 else if (isValuePromoted) {
62135 isValuePromoted = false;
62136 }
62137 }
62138 cardData.push({
62139 caption: columnCaption,
62140 details: columnDetail,
62141 showURL: visuals.converterHelper.isWebUrlColumn(column) && UrlUtils.isValidUrl(columnCaption),
62142 showImage: visuals.converterHelper.isImageUrlColumn(column) && UrlUtils.isValidImageUrl(columnCaption),
62143 showKPI: showKPI,
62144 columnIndex: j
62145 });
62146 }
62147 details.push({
62148 title: isValuePromoted ? title : undefined,
62149 showTitleAsURL: showTitleAsURL,
62150 showTitleAsImage: showTitleAsImage,
62151 showTitleAsKPI: showTitleAsKPI,
62152 cardItemsData: isValuePromoted ? cardData.filter(function (d) { return d.caption !== title; }) : cardData
62153 });
62154 }
62155 return {
62156 dataModel: details,
62157 dataColumnCount: details[0] ? details[0].cardItemsData.length : 0,
62158 cardTitleSettings: cardTitleSettings,
62159 categoryLabelsSettings: categoryLabelsSettings,
62160 dataLabelsSettings: dataLabelsSettings,
62161 cardSettings: MultiRowCard.getCardSettings(dataView)
62162 };
62163 };
62164 MultiRowCard.getSortableRoles = function (options) {
62165 if (!options || !options.dataViewMappings || _.isEmpty(options.dataViewMappings)) {
62166 return;
62167 }
62168 for (var _i = 0, _a = options.dataViewMappings; _i < _a.length; _i++) {
62169 var dataViewMapping = _a[_i];
62170 if (dataViewMapping.table) {
62171 var rows = dataViewMapping.table.rows;
62172 if (rows && rows.for && rows.for.in && rows.for.in.items) {
62173 return [MultiRowCard.ValuesRole];
62174 }
62175 }
62176 }
62177 return;
62178 };
62179 MultiRowCard.prototype.initializeCardRowSelection = function () {
62180 var _this = this;
62181 var isDashboardVisual = this.isInteractivityOverflowHidden;
62182 var rowEnter = function (rowSelection) {
62183 var cardRow = rowSelection
62184 .append("div")
62185 .classed(MultiRowCard.Card.class, true);
62186 // The card top padding is not needed when card items are wrapped as top padding is added to each carditemcontainer when wrapped
62187 if (isDashboardVisual) {
62188 cardRow.classed('mrtile', true);
62189 }
62190 else {
62191 if (_this.cardHasTitle) {
62192 cardRow.append("div").classed(MultiRowCard.Title.class, true)
62193 .each(function (d) {
62194 if (d.showTitleAsImage)
62195 appendImage(d3.select(this));
62196 else if (d.showTitleAsURL)
62197 d3.select(this).append('a');
62198 else if (d.showTitleAsKPI)
62199 d3.select(this).append('div')
62200 .classed(MultiRowCard.KPITitle.class, true)
62201 .classed(d.title, true)
62202 .style({
62203 display: 'inline-block',
62204 verticalAlign: 'sub'
62205 });
62206 });
62207 }
62208 }
62209 var cardItem = cardRow
62210 .selectAll(MultiRowCard.CardItemContainer.selector)
62211 .data(function (d) { return d.cardItemsData; })
62212 .enter()
62213 .append('div')
62214 .classed(MultiRowCard.CardItemContainer.class, true);
62215 cardItem
62216 .append('div')
62217 .classed(MultiRowCard.Caption.class, true)
62218 .each(function (d) {
62219 if (d.showURL) {
62220 d3.select(this).append('a');
62221 }
62222 else if (d.showImage) {
62223 appendImage(d3.select(this));
62224 }
62225 else if (d.showKPI) {
62226 d3.select(this).append('div')
62227 .classed(d.caption, true)
62228 .style({
62229 display: 'inline-block',
62230 verticalAlign: 'sub'
62231 });
62232 }
62233 });
62234 cardItem
62235 .append('div')
62236 .classed(MultiRowCard.Details.class, true);
62237 };
62238 /**
62239 * Row update should:
62240 * 1. bind Data
62241 * 2. Manipulate DOM (likely just updating CSS properties) affected by data
62242 */
62243 var rowUpdate = function (rowSelection) {
62244 var style = _this.getStyle();
62245 var dataLabelHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(MultiRowCard.getTextProperties(false, style.caption.fontSize));
62246 var categoryLabelHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(MultiRowCard.getTextProperties(false, style.details.fontSize));
62247 var titleLabelHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(MultiRowCard.getTextProperties(true, style.title.fontSize));
62248 var rowBorderStyle = _this.getBorderStyles(style.row.border);
62249 rowSelection
62250 .style(rowBorderStyle)
62251 .style({
62252 'margin-bottom': isDashboardVisual ? '0px' : (_this.isSingleRowCard ? '0px' : getPixelString(style.row.marginBottom)),
62253 'background': style.row.background
62254 });
62255 if (!isDashboardVisual && _this.cardHasTitle) {
62256 rowSelection.selectAll(MultiRowCard.Title.selector)
62257 .filter(function (d) { return !d.showTitleAsImage && !d.showTitleAsKPI; })
62258 .style({
62259 'font-size': PixelConverter.fromPoint(style.title.fontSize),
62260 'line-height': PixelConverter.toString(titleLabelHeight),
62261 'color': style.title.color,
62262 });
62263 rowSelection.selectAll(MultiRowCard.Title.selector)
62264 .filter(function (d) { return !d.showTitleAsURL && !d.showTitleAsImage && !d.showTitleAsKPI; })
62265 .text(function (d) { return d.title; })
62266 .attr('title', function (d) { return d.title; });
62267 rowSelection
62268 .selectAll(MultiRowCard.TitleUrlSelector)
62269 .text(function (d) { return d.title; })
62270 .attr({
62271 'href': function (d) { return d.title; },
62272 'target': '_blank',
62273 });
62274 rowSelection
62275 .selectAll(MultiRowCard.TitleImageSelector)
62276 .attr('src', function (d) { return d.title; });
62277 setImageStyle(rowSelection.selectAll(MultiRowCard.Title.selector), style.imageTitle);
62278 rowSelection
62279 .selectAll(MultiRowCard.KPITitle.selector)
62280 .each(function (d) {
62281 var element = d3.select(this);
62282 element.classed(d.title);
62283 });
62284 }
62285 var cardSelection = rowSelection.selectAll(MultiRowCard.Card.selector);
62286 var cardBorderStyle = _this.getBorderStyles(style.card.border);
62287 cardSelection.style(cardBorderStyle);
62288 cardSelection
62289 .selectAll(MultiRowCard.Caption.selector)
62290 .filter(function (d) { return !d.showImage; })
62291 .style({
62292 'line-height': PixelConverter.toString(dataLabelHeight),
62293 'font-size': PixelConverter.fromPoint(style.caption.fontSize),
62294 })
62295 .filter(function (d) { return !d.showKPI; })
62296 .style({
62297 'color': style.caption.color,
62298 })
62299 .filter(function (d) { return !d.showURL; })
62300 .text(function (d) { return d.caption; })
62301 .attr('title', function (d) { return d.caption; });
62302 cardSelection
62303 .selectAll(MultiRowCard.CaptionImageSelector)
62304 .attr('src', function (d) { return d.caption; })
62305 .style(style.imageCaption);
62306 cardSelection
62307 .selectAll(MultiRowCard.CardItemContainer.selector)
62308 .style({
62309 'padding-right': function (d) {
62310 return _this.isLastRowItem(d.columnIndex, _this.dataView.metadata.columns.length) ? '0px' : getPixelString(style.cardItemContainer.paddingRight);
62311 },
62312 'width': function (d) {
62313 return _this.getColumnWidth(d.columnIndex, _this.data.dataColumnCount);
62314 },
62315 'display': function (d) {
62316 return (_this.hideColumn(d.columnIndex) ? 'none' : 'inline-block');
62317 },
62318 });
62319 setImageStyle(cardSelection.selectAll(MultiRowCard.Caption.selector), style.imageCaption);
62320 cardSelection
62321 .selectAll(MultiRowCard.CaptionUrlSelector)
62322 .attr({
62323 'href': function (d) { return d.caption; },
62324 'target': '_blank',
62325 })
62326 .text(function (d) { return d.caption; });
62327 if (style.details.isVisible) {
62328 cardSelection
62329 .selectAll(MultiRowCard.Details.selector)
62330 .text(function (d) { return d.details; })
62331 .style({
62332 'font-size': PixelConverter.fromPoint(style.details.fontSize),
62333 'line-height': PixelConverter.toString(categoryLabelHeight),
62334 'color': style.details.color
62335 })
62336 .attr('title', function (d) { return d.details; });
62337 }
62338 };
62339 var rowExit = function (rowSelection) {
62340 rowSelection.remove();
62341 };
62342 var listViewOptions = {
62343 rowHeight: undefined,
62344 enter: rowEnter,
62345 exit: rowExit,
62346 update: rowUpdate,
62347 loadMoreData: function () { return _this.onLoadMoreData(); },
62348 viewport: this.currentViewport,
62349 baseContainer: d3.select(this.element.get(0)),
62350 scrollEnabled: !this.isInteractivityOverflowHidden,
62351 isReadMode: function () {
62352 return (_this.options.host.getViewMode() !== 1 /* Edit */);
62353 }
62354 };
62355 this.listView = visuals.ListViewFactory.createListView(listViewOptions);
62356 };
62357 MultiRowCard.prototype.getBorderStyles = function (border) {
62358 return {
62359 'border-top': border && border.top ? border.top.getCSS() : '',
62360 'border-right': border && border.right ? border.right.getCSS() : '',
62361 'border-bottom': border && border.bottom ? border.bottom.getCSS() : '',
62362 'border-left': border && border.left ? border.left.getCSS() : ''
62363 };
62364 };
62365 MultiRowCard.prototype.getMaxColPerRow = function () {
62366 var rowWidth = this.currentViewport.width;
62367 var minColumnWidth = this.getStyle().cardItemContainer.minWidth;
62368 var columnCount = this.data.dataColumnCount;
62369 //atleast one column fits in a row
62370 var maxColumnPerRow = Math.floor(rowWidth / minColumnWidth) || 1;
62371 return Math.min(columnCount, maxColumnPerRow);
62372 };
62373 MultiRowCard.prototype.getRowIndex = function (fieldIndex) {
62374 return Math.floor((fieldIndex * 1.0) / this.getMaxColPerRow());
62375 };
62376 MultiRowCard.prototype.getStyle = function () {
62377 var defaultStyles = MultiRowCard.DefaultStyle;
62378 var customStyles = this.getCustomStyles();
62379 if (!this.isInteractivityOverflowHidden)
62380 return $.extend(true, {}, defaultStyles, customStyles);
62381 var viewportWidth = this.currentViewport.width;
62382 var overrideStyle = {};
62383 for (var _i = 0, _a = MultiRowCard.tileMediaQueries; _i < _a.length; _i++) {
62384 var currentQuery = _a[_i];
62385 if (viewportWidth <= currentQuery.maxWidth) {
62386 overrideStyle = currentQuery.style;
62387 break;
62388 }
62389 }
62390 return $.extend(true, {}, defaultStyles, customStyles, overrideStyle);
62391 };
62392 MultiRowCard.prototype.getSurroundSettings = function (outlineSettings) {
62393 var edge = new EdgeSettings(outlineSettings.weight, outlineSettings.color);
62394 var outlineProp = outlineSettings.outline;
62395 return {
62396 top: visuals.outline.showTop(outlineProp) ? edge : null,
62397 right: visuals.outline.showRight(outlineProp) ? edge : null,
62398 bottom: visuals.outline.showBottom(outlineProp) ? edge : null,
62399 left: visuals.outline.showLeft(outlineProp) ? edge : null,
62400 };
62401 };
62402 MultiRowCard.prototype.getCustomStyles = function () {
62403 var dataLabelsSettings = this.data.dataLabelsSettings;
62404 var categoryLabelSettings = this.data.categoryLabelsSettings;
62405 var titleLabelSettings = this.data.cardTitleSettings;
62406 var cardSettings = this.data.cardSettings;
62407 var customStyle = {
62408 row: {
62409 border: this.getSurroundSettings(cardSettings.outlineSettings),
62410 marginBottom: cardSettings.cardPadding,
62411 background: cardSettings.cardBackground
62412 },
62413 card: {
62414 border: this.getSurroundSettings(cardSettings.barSettings)
62415 },
62416 details: {
62417 fontSize: categoryLabelSettings.fontSize,
62418 color: categoryLabelSettings.labelColor,
62419 isVisible: categoryLabelSettings.show,
62420 },
62421 caption: {
62422 fontSize: dataLabelsSettings.fontSize,
62423 color: dataLabelsSettings.labelColor,
62424 },
62425 title: {
62426 fontSize: titleLabelSettings.fontSize,
62427 color: titleLabelSettings.labelColor,
62428 }
62429 };
62430 return customStyle;
62431 };
62432 MultiRowCard.getTextProperties = function (isTitle, fontSizeInPt) {
62433 return {
62434 fontFamily: isTitle ? TitleFontFamily : DefaultFontFamily,
62435 fontSize: PixelConverter.fromPoint(fontSizeInPt),
62436 };
62437 };
62438 MultiRowCard.prototype.hideColumn = function (fieldIndex) {
62439 //calculate the number of items apearing in the same row as the columnIndex
62440 var rowIndex = this.getRowIndex(fieldIndex);
62441 // when interactivity is disabled (pinned tile), don't wrap the row
62442 var maxRows = this.getStyle().card.maxRows;
62443 return (maxRows && rowIndex >= maxRows);
62444 };
62445 MultiRowCard.prototype.getColumnWidth = function (fieldIndex, columnCount) {
62446 //atleast one column fits in a row
62447 var maxColumnPerRow = this.getMaxColPerRow();
62448 if (maxColumnPerRow >= columnCount)
62449 //all columns fit in the same row, divide the space equaly
62450 return (100.0 / columnCount) + '%';
62451 //calculate the number of items apearing in the same row as the columnIndex
62452 var rowIndex = this.getRowIndex(fieldIndex);
62453 var totalRows = Math.ceil((columnCount * 1.0) / maxColumnPerRow);
62454 var lastRowCount = columnCount % maxColumnPerRow;
62455 if (rowIndex < totalRows || lastRowCount === 0)
62456 // items is not on the last row or last row contains max columns allowed per row
62457 return (100.0 / maxColumnPerRow) + '%';
62458 // items is on the last row
62459 return (100.0 / lastRowCount) + '%';
62460 };
62461 MultiRowCard.prototype.isLastRowItem = function (fieldIndex, columnCount) {
62462 if (fieldIndex + 1 === columnCount)
62463 return true;
62464 var maxColumnPerRow = this.getMaxColPerRow();
62465 if (maxColumnPerRow - (fieldIndex % maxColumnPerRow) === 1)
62466 return true;
62467 return false;
62468 };
62469 /**
62470 * This contains the card column wrapping logic.
62471 * Determines how many columns can be shown per each row inside a Card.
62472 * To place the fields evenly along the card,
62473 * the width of each card item is calculated based on the available viewport width.
62474 */
62475 MultiRowCard.prototype.setCardDimensions = function () {
62476 this.cardHasTitle = false;
62477 var dataModel = this.data.dataModel;
62478 if (!this.isInteractivityOverflowHidden && dataModel && dataModel.length > 0) {
62479 this.cardHasTitle = dataModel[0].title !== undefined;
62480 this.isSingleRowCard = dataModel.length === 1 ? true : false;
62481 }
62482 };
62483 MultiRowCard.prototype.onLoadMoreData = function () {
62484 if (!this.waitingForData && this.dataView.metadata && this.dataView.metadata.segment) {
62485 this.options.host.loadMoreData();
62486 this.waitingForData = true;
62487 }
62488 };
62489 MultiRowCard.getDataLabelSettingsOptions = function (enumeration, labelSettings, show) {
62490 if (show === void 0) { show = false; }
62491 return {
62492 enumeration: enumeration,
62493 dataLabelsSettings: labelSettings,
62494 show: show,
62495 fontSize: true,
62496 };
62497 };
62498 MultiRowCard.prototype.enumerateObjectInstances = function (options) {
62499 var enumeration = new visuals.ObjectEnumerationBuilder();
62500 var cardTitleSettings = this.data.cardTitleSettings;
62501 var dataLabelsSettings = this.data.dataLabelsSettings;
62502 var categoryLabelsSettings = this.data.categoryLabelsSettings;
62503 switch (options.objectName) {
62504 case 'cardTitle':
62505 //display title options only if title visible
62506 if (!this.isInteractivityOverflowHidden && this.cardHasTitle)
62507 visuals.dataLabelUtils.enumerateDataLabels(MultiRowCard.getDataLabelSettingsOptions(enumeration, cardTitleSettings));
62508 break;
62509 case 'dataLabels':
62510 visuals.dataLabelUtils.enumerateDataLabels(MultiRowCard.getDataLabelSettingsOptions(enumeration, dataLabelsSettings));
62511 break;
62512 case 'categoryLabels':
62513 visuals.dataLabelUtils.enumerateDataLabels(MultiRowCard.getDataLabelSettingsOptions(enumeration, categoryLabelsSettings, true));
62514 break;
62515 case visuals.multiRowCardProps.card.outline.objectName:
62516 this.enumerateCard(enumeration);
62517 break;
62518 }
62519 return enumeration.complete();
62520 };
62521 MultiRowCard.prototype.enumerateCard = function (enumeration) {
62522 var cardSettings = this.data.cardSettings;
62523 var propNames = visuals.multiRowCardProps.card;
62524 var properties = {};
62525 var outlineSettings = cardSettings.outlineSettings;
62526 properties[propNames.outline.propertyName] = outlineSettings.outline;
62527 if (outlineSettings.outline !== visuals.outline.none) {
62528 properties[propNames.outlineColor.propertyName] = outlineSettings.color;
62529 properties[propNames.outlineWeight.propertyName] = outlineSettings.weight;
62530 }
62531 var barSettings = cardSettings.barSettings;
62532 // The bar is shown if the outline value is not none
62533 var barShow = barSettings.outline !== visuals.outline.none;
62534 properties[propNames.barShow.propertyName] = barShow;
62535 if (barShow) {
62536 properties[propNames.barColor.propertyName] = barSettings.color;
62537 properties[propNames.barWeight.propertyName] = barSettings.weight;
62538 }
62539 properties[propNames.cardPadding.propertyName] = cardSettings.cardPadding;
62540 properties[propNames.cardBackground.propertyName] = cardSettings.cardBackground;
62541 enumeration.pushInstance({
62542 selector: null,
62543 objectName: propNames.outline.objectName,
62544 properties: properties
62545 });
62546 };
62547 /**
62548 * Note: Public for testability.
62549 */
62550 MultiRowCard.formatStringProp = {
62551 objectName: 'general',
62552 propertyName: 'formatString',
62553 };
62554 MultiRowCard.MultiRowCardRoot = createClassAndSelector('multiRowCard');
62555 MultiRowCard.Card = createClassAndSelector('card');
62556 MultiRowCard.Title = createClassAndSelector('title');
62557 MultiRowCard.CardItemContainer = createClassAndSelector('cardItemContainer');
62558 MultiRowCard.Caption = createClassAndSelector('caption');
62559 MultiRowCard.Details = createClassAndSelector('details');
62560 MultiRowCard.TitleUrlSelector = MultiRowCard.Title.selector + ' a';
62561 MultiRowCard.CaptionUrlSelector = MultiRowCard.Caption.selector + ' a';
62562 MultiRowCard.TitleImageSelector = MultiRowCard.Title.selector + ' img';
62563 MultiRowCard.CaptionImageSelector = MultiRowCard.Caption.selector + ' img';
62564 MultiRowCard.KPITitle = createClassAndSelector('kpiTitle');
62565 MultiRowCard.ValuesRole = 'Values';
62566 /**
62567 * Cards have specific styling so defined inline styles and also to support theming and improve performance.
62568 */
62569 MultiRowCard.DefaultStyle = {
62570 row: {
62571 border: null,
62572 marginBottom: 20,
62573 background: undefined
62574 },
62575 card: {
62576 border: null
62577 },
62578 cardItemContainer: {
62579 paddingRight: 20,
62580 minWidth: 120,
62581 },
62582 imageCaption: {
62583 maxHeight: 75,
62584 maxWidth: 100,
62585 },
62586 imageTitle: {
62587 maxHeight: 75,
62588 maxWidth: 100,
62589 }
62590 };
62591 // queries should be ordered by maxWidth in ascending order
62592 MultiRowCard.tileMediaQueries = [
62593 {
62594 maxWidth: 250,
62595 style: {
62596 card: {
62597 maxRows: 2,
62598 },
62599 cardItemContainer: {
62600 minWidth: 110,
62601 },
62602 imageCaption: {
62603 maxHeight: 45,
62604 }
62605 }
62606 },
62607 {
62608 maxWidth: 490,
62609 style: {
62610 card: {
62611 maxRows: 2,
62612 },
62613 cardItemContainer: {
62614 minWidth: 130,
62615 },
62616 imageCaption: {
62617 maxHeight: 52,
62618 }
62619 }
62620 },
62621 {
62622 maxWidth: 750,
62623 style: {
62624 card: {
62625 maxRows: 1,
62626 },
62627 cardItemContainer: {
62628 minWidth: 120,
62629 },
62630 imageCaption: {
62631 maxHeight: 53,
62632 }
62633 }
62634 }
62635 ];
62636 return MultiRowCard;
62637 }());
62638 visuals.MultiRowCard = MultiRowCard;
62639 function appendImage(selection) {
62640 selection
62641 .append('div')
62642 .classed('imgCon', true)
62643 .append('img');
62644 }
62645 function setImageStyle(selection, imageStyle) {
62646 selection
62647 .selectAll('.imgCon')
62648 .style({
62649 'height': getPixelString(imageStyle.maxHeight),
62650 })
62651 .selectAll('img')
62652 .style({
62653 'max-height': getPixelString(imageStyle.maxHeight),
62654 'max-width': getPixelString(imageStyle.maxWidth),
62655 });
62656 }
62657 function getPixelString(value) {
62658 return value + "px";
62659 }
62660 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
62661})(powerbi || (powerbi = {}));
62662/*
62663 * Power BI Visualizations
62664 *
62665 * Copyright (c) Microsoft Corporation
62666 * All rights reserved.
62667 * MIT License
62668 *
62669 * Permission is hereby granted, free of charge, to any person obtaining a copy
62670 * of this software and associated documentation files (the ""Software""), to deal
62671 * in the Software without restriction, including without limitation the rights
62672 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
62673 * copies of the Software, and to permit persons to whom the Software is
62674 * furnished to do so, subject to the following conditions:
62675 *
62676 * The above copyright notice and this permission notice shall be included in
62677 * all copies or substantial portions of the Software.
62678 *
62679 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62680 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62681 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62682 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62683 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62684 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
62685 * THE SOFTWARE.
62686 */
62687var powerbi;
62688(function (powerbi) {
62689 var visuals;
62690 (function (visuals) {
62691 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
62692 var KeyUtils = jsCommon.KeyUtils;
62693 var StringExtensions = jsCommon.StringExtensions;
62694 var UrlUtils = jsCommon.UrlUtils;
62695 /** Represents a rich text box that supports view & edit mode. */
62696 var Textbox = (function () {
62697 function Textbox() {
62698 }
62699 Textbox.prototype.init = function (options) {
62700 this.element = options.element;
62701 this.host = options.host;
62702 this.viewport = options.viewport;
62703 this.readOnly = (this.host.getViewMode() === 0 /* View */);
62704 this.paragraphs = [];
62705 this.refreshView();
62706 };
62707 Textbox.prototype.onResizing = function (viewport) {
62708 this.viewport = viewport;
62709 this.updateSize();
62710 };
62711 Textbox.prototype.onDataChanged = function (options) {
62712 debug.assertValue(options, 'options');
62713 var dataViews = options.dataViews;
62714 this.paragraphs = [];
62715 if (dataViews && dataViews.length > 0) {
62716 var objects = dataViews[0].metadata.objects;
62717 if (objects && objects.general)
62718 this.paragraphs = objects.general.paragraphs;
62719 }
62720 this.refreshView();
62721 };
62722 Textbox.prototype.destroy = function () {
62723 };
62724 Textbox.prototype.focus = function () {
62725 if (!this.editor)
62726 return;
62727 this.editor.focus();
62728 return true;
62729 };
62730 Textbox.prototype.onViewModeChanged = function (viewMode) {
62731 this.readOnly = (viewMode === 0 /* View */);
62732 this.refreshView();
62733 };
62734 Textbox.prototype.setSelection = function (start, end) {
62735 debug.assertValue(this.editor, 'editor');
62736 if (this.editor)
62737 this.editor.setSelection(start, end);
62738 };
62739 Textbox.prototype.refreshView = function () {
62740 var _this = this;
62741 if (this.readOnly) {
62742 // Showing just HTML, no editor.
62743 // If we are in view-mode and we have an editor, we can remove it (after saving).
62744 if (this.editor) {
62745 this.saveContents();
62746 this.editor.destroy();
62747 this.editor = null;
62748 }
62749 this.element.empty();
62750 var htmlContent = RichTextConversion.convertParagraphsToHtml(this.paragraphs);
62751 htmlContent.addClass(Textbox.ClassName);
62752 htmlContent.css({
62753 'font-family': RichText.defaultFont,
62754 'font-size': RichText.defaultFontSize,
62755 });
62756 this.element.append(htmlContent);
62757 }
62758 else {
62759 // Showing the Quill editor.
62760 // If we are in edit-mode and we don't have an editor we need to create it.
62761 if (!this.editor) {
62762 this.editor = new RichText.QuillWrapper(this.readOnly, this.host);
62763 this.editor.textChanged = function (delta, source) { return _this.saveContents(); };
62764 this.element.empty();
62765 var editorElement = this.editor.getElement();
62766 editorElement.addClass(Textbox.ClassName);
62767 editorElement.css({
62768 'font-family': RichText.defaultFont,
62769 'font-size': RichText.defaultFontSize,
62770 });
62771 this.element.append(editorElement);
62772 }
62773 this.editor.setContents(RichTextConversion.convertParagraphsToOps(this.paragraphs));
62774 }
62775 this.updateSize();
62776 };
62777 Textbox.prototype.saveContents = function () {
62778 // It's possible to get here via a throttled text-changed event after a view-mode change has occured and
62779 // we are now in view mode. Since we save changes on view-mode change it is safe to ignore this call.
62780 if (!this.editor)
62781 return;
62782 var contents = this.editor.getContents();
62783 this.paragraphs = RichTextConversion.convertDeltaToParagraphs(contents);
62784 var changes = [{
62785 objectName: 'general',
62786 properties: {
62787 paragraphs: this.paragraphs
62788 },
62789 selector: null,
62790 }];
62791 this.host.persistProperties(changes);
62792 };
62793 Textbox.prototype.updateSize = function () {
62794 if (this.editor)
62795 this.editor.resize(this.viewport);
62796 };
62797 Textbox.ClassName = 'textbox';
62798 return Textbox;
62799 }());
62800 visuals.Textbox = Textbox;
62801 var RichTextConversion;
62802 (function (RichTextConversion) {
62803 function convertDeltaToParagraphs(contents) {
62804 var paragraphs = [];
62805 var paragraph = { textRuns: [] };
62806 for (var i = 0, len = contents.ops.length; i < len; i++) {
62807 var insertOp = contents.ops[i];
62808 debug.assertValue(insertOp, "operation should be an insert");
62809 if (typeof insertOp.insert === "string") {
62810 // string insert values represent text.
62811 var text = insertOp.insert;
62812 var attributes = insertOp.attributes;
62813 if (attributes && attributes.align) {
62814 // Sometimes horizontal alignment is set after the first "insert" of the paragraph, which is likely a bug
62815 // in Quill. In any case we should never see different horizontal alignments in a single paragraph.
62816 debug.assert(paragraph.horizontalTextAlignment === undefined || paragraph.horizontalTextAlignment === attributes.align, 'paragraph should not have more than one horizontal alignment');
62817 paragraph.horizontalTextAlignment = attributes.align;
62818 }
62819 // Quill gives us back text runs that may have \n's in them. We want to create a new paragraph for each \n we see.
62820 var start = 0;
62821 var end = 0;
62822 var newParagraph = void 0;
62823 do {
62824 end = text.indexOf('\n', start);
62825 if (end < 0) {
62826 newParagraph = false;
62827 end = text.length;
62828 }
62829 else {
62830 newParagraph = true;
62831 }
62832 if (end - start > 0) {
62833 var span = text.substring(start, end);
62834 var textRun = { value: span };
62835 if (attributes) {
62836 if (attributes.link !== undefined && UrlUtils.isValidUrl(attributes.link))
62837 textRun.url = attributes.link;
62838 var textStyle = convertFormatAttributesToTextStyle(attributes);
62839 if (textStyle)
62840 textRun.textStyle = textStyle;
62841 }
62842 paragraph.textRuns.push(textRun);
62843 }
62844 // If we actually saw a '\n' then create a new paragraph
62845 if (newParagraph) {
62846 if (paragraph.textRuns.length === 0)
62847 paragraph.textRuns.push({ value: '' });
62848 paragraphs.push(paragraph);
62849 paragraph = { textRuns: [] };
62850 }
62851 start = end + 1;
62852 } while (start < text.length);
62853 }
62854 else {
62855 // numeric insert values represent embeds.
62856 debug.assertFail("embeds not supported");
62857 }
62858 }
62859 if (paragraph.textRuns.length > 0) {
62860 // Quill appears to always insert an extra '\n' at the end of the text, skip it
62861 if (paragraph.textRuns[0].value.length > 0)
62862 paragraphs.push(paragraph);
62863 }
62864 return paragraphs;
62865 }
62866 RichTextConversion.convertDeltaToParagraphs = convertDeltaToParagraphs;
62867 function convertParagraphsToHtml(paragraphs) {
62868 var $paragraphs = $();
62869 for (var paragraphIndex = 0, len = paragraphs.length; paragraphIndex < len; ++paragraphIndex) {
62870 var paragraphDef = paragraphs[paragraphIndex];
62871 var isParagraphEmpty = true;
62872 var $paragraph = $('<div>');
62873 if (paragraphDef.horizontalTextAlignment)
62874 $paragraph.css('text-align', paragraphDef.horizontalTextAlignment);
62875 for (var textRunIndex = 0, jlen = paragraphDef.textRuns.length; textRunIndex < jlen; ++textRunIndex) {
62876 var textRunDef = paragraphDef.textRuns[textRunIndex];
62877 var $textRun = $('<span>');
62878 var styleDef = textRunDef.textStyle;
62879 if (styleDef) {
62880 var css = {};
62881 if (styleDef.fontFamily) {
62882 css['font-family'] = RichText.getCssFontFamily(removeQuotes(styleDef.fontFamily));
62883 }
62884 if (styleDef.fontSize) {
62885 css['font-size'] = styleDef.fontSize;
62886 }
62887 if (styleDef.fontStyle) {
62888 css['font-style'] = styleDef.fontStyle;
62889 }
62890 if (styleDef.fontWeight) {
62891 css['font-weight'] = styleDef.fontWeight;
62892 }
62893 if (styleDef.textDecoration) {
62894 css['text-decoration'] = styleDef.textDecoration;
62895 }
62896 $textRun.css(css);
62897 }
62898 var text = textRunDef.value;
62899 if (!_.isEmpty(text))
62900 isParagraphEmpty = false;
62901 if (textRunDef.url !== undefined) {
62902 var $link = void 0;
62903 if (UrlUtils.isValidUrl(textRunDef.url)) {
62904 $link = $('<a>')
62905 .attr('href', textRunDef.url)
62906 .attr('target', '_blank')
62907 .text(text);
62908 }
62909 else {
62910 $link = $('<span>').text(text);
62911 }
62912 $textRun.append($link);
62913 }
62914 else {
62915 $textRun.text(text);
62916 }
62917 $paragraph.append($textRun);
62918 }
62919 // If the entire paragraph is empty we need to make sure we enforce a line-break.
62920 if (isParagraphEmpty)
62921 $paragraph.append($('<br>'));
62922 $paragraphs = $paragraphs.add($paragraph);
62923 }
62924 return $paragraphs;
62925 }
62926 RichTextConversion.convertParagraphsToHtml = convertParagraphsToHtml;
62927 function convertParagraphsToOps(paragraphs) {
62928 var ops = [];
62929 for (var paragraphIndex = 0, len = paragraphs.length; paragraphIndex < len; ++paragraphIndex) {
62930 var paragraphDef = paragraphs[paragraphIndex];
62931 for (var textRunIndex = 0, jlen = paragraphDef.textRuns.length; textRunIndex < jlen; ++textRunIndex) {
62932 var textRunDef = paragraphDef.textRuns[textRunIndex];
62933 var formats = {};
62934 if (paragraphDef.horizontalTextAlignment)
62935 formats.align = paragraphDef.horizontalTextAlignment;
62936 var styleDef = textRunDef.textStyle;
62937 if (styleDef) {
62938 if (styleDef.fontFamily) {
62939 formats.font = RichText.getCssFontFamily(removeQuotes(styleDef.fontFamily));
62940 }
62941 if (styleDef.fontSize) {
62942 formats.size = styleDef.fontSize;
62943 }
62944 formats.italic = (styleDef.fontStyle === 'italic');
62945 formats.bold = (styleDef.fontWeight === 'bold');
62946 formats.underline = (styleDef.textDecoration === 'underline');
62947 }
62948 var text = textRunDef.value;
62949 if (textRunDef.url && UrlUtils.isValidUrl(textRunDef.url))
62950 formats.link = textRunDef.url;
62951 var op = {
62952 insert: text,
62953 attributes: formats,
62954 };
62955 ops.push(op);
62956 // The last text run of the paragraph needs to end with '\n' to get Quill to handle the text alignment correctly.
62957 if (textRunIndex === (jlen - 1) && !StringExtensions.endsWith(text, '\n')) {
62958 ops.push({
62959 insert: '\n',
62960 attributes: formats,
62961 });
62962 }
62963 }
62964 }
62965 return ops;
62966 }
62967 RichTextConversion.convertParagraphsToOps = convertParagraphsToOps;
62968 function convertFormatAttributesToTextStyle(attributes) {
62969 var style = {};
62970 // NOTE: Align is taken care of when converting to paragraphs.
62971 if (attributes.bold) {
62972 style.fontWeight = 'bold';
62973 }
62974 if (attributes.font) {
62975 // We should always save font names without any quotes.
62976 var font = removeQuotes(attributes.font);
62977 // Convert built-in font families back into their proper font families (e.g. wf_segoe-ui_normal -> Segoe UI)
62978 font = RichText.getFontFamilyForBuiltInFont(font);
62979 style.fontFamily = font;
62980 }
62981 if (attributes.italic) {
62982 style.fontStyle = 'italic';
62983 }
62984 if (attributes.size) {
62985 style.fontSize = attributes.size;
62986 }
62987 if (attributes.underline) {
62988 style.textDecoration = 'underline';
62989 }
62990 /*
62991 TODO:
62992 if (attributes.background) {
62993 }
62994 if (attributes.color) {
62995 }
62996 */
62997 return style;
62998 }
62999 function removeQuotes(text) {
63000 if (!StringExtensions.startsWith(text, "'"))
63001 return text;
63002 debug.assert(StringExtensions.endsWith(text, "'"), "mismatched quotes");
63003 return text.slice(1, text.length - 1);
63004 }
63005 })(RichTextConversion || (RichTextConversion = {}));
63006 var RichText;
63007 (function (RichText) {
63008 /**
63009 * These fonts are embedded using CSS, or are aliases to other fonts.
63010 */
63011 var fontMap = {
63012 'Segoe (Bold)': 'wf_segoe-ui_bold',
63013 'Segoe UI': 'wf_segoe-ui_normal',
63014 'Segoe UI Light': 'wf_segoe-ui_light',
63015 'Heading': 'wf_segoe-ui_light',
63016 'Body': 'wf_segoe-ui_normal',
63017 };
63018 var fonts = [
63019 'Arial',
63020 'Arial Black',
63021 'Arial Unicode MS',
63022 'Calibri',
63023 'Cambria',
63024 'Cambria Math',
63025 'Candara',
63026 'Comic Sans MS',
63027 'Consolas',
63028 'Constantia',
63029 'Corbel',
63030 'Courier New',
63031 'Georgia',
63032 'Lucida Sans Unicode',
63033 'Segoe (Bold)',
63034 'Segoe UI',
63035 'Segoe UI Light',
63036 'Symbol',
63037 'Tahoma',
63038 'Times New Roman',
63039 'Trebuchet MS',
63040 'Verdana',
63041 'Wingdings',
63042 ].map(function (font) { return { label: font, value: getCssFontFamily(font) }; });
63043 RichText.defaultFont = getCssFontFamily('Segoe UI Light');
63044 var fontSizes = [
63045 '8', '9', '10', '10.5', '11', '12', '14', '16', '18', '20', '24', '28', '32', '36', '40', '42', '44', '54', '60', '66', '72', '80', '88', '96'
63046 ].map(function (size) { return { label: size, value: size + 'px' }; });
63047 RichText.defaultFontSize = '14px';
63048 var textAlignments = [
63049 'Left',
63050 'Center',
63051 'Right',
63052 ].map(function (alignment) { return { label: alignment, value: alignment.toLowerCase() }; });
63053 /**
63054 * Given a font family returns the value we should use for the font-family css property.
63055 */
63056 function getCssFontFamily(font) {
63057 var family = fontMap[font];
63058 if (family == null)
63059 family = font;
63060 return family;
63061 }
63062 RichText.getCssFontFamily = getCssFontFamily;
63063 /**
63064 * Convert built-in font families back into their proper font families (e.g. wf_segoe-ui_normal -> Segoe UI)
63065 */
63066 function getFontFamilyForBuiltInFont(font) {
63067 var fontFamily = _.findKey(fontMap, function (value) { return value === font; });
63068 return fontFamily || font;
63069 }
63070 RichText.getFontFamilyForBuiltInFont = getFontFamilyForBuiltInFont;
63071 var QuillWrapper = (function () {
63072 /**
63073 * JavaScript and CSS resources are typically resolved asynchronously.
63074 * This means we potentially defer certain events which typically occur
63075 * synchronously until resources are loaded.
63076 * Setting the global loadQuillResources flag to true will override
63077 * this behavior and cause the wrapper to assume these resources are already loaded
63078 * and not try to load them asynchronously (e.g. for use in unit tests).
63079 */
63080 function QuillWrapper(readOnly, host) {
63081 var _this = this;
63082 this.QuillPackage = {
63083 javaScriptFiles: QuillWrapper.quillJsFiles,
63084 cssFiles: QuillWrapper.quillCssFiles,
63085 };
63086 this.textChanged = function (d, s) { };
63087 this.host = host;
63088 this.$container = $('<div>');
63089 this.readOnly = readOnly;
63090 this.localizationProvider = {
63091 get: function (stringId) { return _this.host.getLocalizedString(stringId); },
63092 getOptional: function (stringId) { return _this.host.getLocalizedString(stringId); }
63093 };
63094 this.dependenciesLoaded = $.Deferred();
63095 if (QuillWrapper.loadQuillResources) {
63096 // Defer creation of the editor until after resources are loaded.
63097 this.initialized = false;
63098 // Note that these are called in the order registered so this will always be called before other callbacks.
63099 this.dependenciesLoaded.done(function () {
63100 _this.rebuildQuillEditor();
63101 _this.initialized = true;
63102 });
63103 jsCommon.requires(this.QuillPackage, function () { return _this.dependenciesLoaded.resolve(); });
63104 }
63105 else {
63106 this.rebuildQuillEditor();
63107 this.initialized = true;
63108 this.dependenciesLoaded.resolve();
63109 }
63110 }
63111 QuillWrapper.prototype.addModule = function (name, options) {
63112 if (this.editor)
63113 return this.editor.addModule(name, options);
63114 };
63115 QuillWrapper.prototype.getElement = function () {
63116 return this.$container;
63117 };
63118 QuillWrapper.prototype.getContents = function () {
63119 if (this.initialized)
63120 return this.editor.getContents();
63121 };
63122 QuillWrapper.prototype.setContents = function (contents) {
63123 var _this = this;
63124 // If we haven't loaded the editor yet, defer this call until we do
63125 // TODO: prevent these from stacking up?
63126 if (!this.initialized) {
63127 this.dependenciesLoaded.done(function () { return _this.setContents(contents); });
63128 return;
63129 }
63130 this.editor.setHTML('', 'api'); // Clear contents
63131 if (contents)
63132 this.editor.setContents(contents, 'api');
63133 };
63134 QuillWrapper.prototype.resize = function (viewport) {
63135 this.$container.width(viewport.width);
63136 this.$container.height(viewport.height);
63137 };
63138 QuillWrapper.prototype.setReadOnly = function (readOnly) {
63139 var readOnlyChanged = readOnly !== this.readOnly;
63140 this.readOnly = readOnly;
63141 if (this.initialized && readOnlyChanged) {
63142 this.rebuildQuillEditor();
63143 }
63144 };
63145 QuillWrapper.prototype.setSelection = function (start, end) {
63146 if (this.editor)
63147 this.editor.setSelection(start, end, 'api');
63148 };
63149 QuillWrapper.prototype.getSelection = function () {
63150 if (this.editor)
63151 return this.editor.getSelection();
63152 };
63153 QuillWrapper.prototype.focus = function () {
63154 if (!this.editor)
63155 return;
63156 if ($(document.activeElement).closest(this.$container).length === 0)
63157 this.editor.focus();
63158 };
63159 QuillWrapper.prototype.destroy = function () {
63160 this.host.setToolbar(null);
63161 this.$container.remove();
63162 this.$container = null;
63163 this.$toolbarDiv = null;
63164 this.$editorDiv = null;
63165 this.editor = null;
63166 };
63167 QuillWrapper.prototype.getSelectionAtCursor = function () {
63168 var text = this.getTextWithoutTrailingBreak();
63169 // Ensure editor has focus before selection interactions
63170 this.editor.focus();
63171 var selection = this.getSelection();
63172 if (selection && selection.start === selection.end) {
63173 return jsCommon.WordBreaker.find(selection.start, text);
63174 }
63175 return selection;
63176 };
63177 QuillWrapper.prototype.getWord = function () {
63178 var selection = this.getSelectionAtCursor();
63179 return this.getTextWithoutTrailingBreak().slice(selection.start, selection.end);
63180 };
63181 QuillWrapper.prototype.insertLinkAtCursor = function (link, index) {
63182 var endIndex = index + link.length;
63183 this.editor.insertText(index, link, 'api');
63184 this.editor.formatText(index, endIndex, 'link', link, 'api');
63185 this.setSelection(index, endIndex);
63186 this.onTextChanged(null, null);
63187 return endIndex;
63188 };
63189 QuillWrapper.prototype.getEditorContainer = function () {
63190 if (this.editor)
63191 return $(this.editor.container);
63192 };
63193 ;
63194 QuillWrapper.prototype.getTextWithoutTrailingBreak = function () {
63195 return this.editor.getText().slice(0, -1);
63196 };
63197 QuillWrapper.prototype.rebuildQuillEditor = function () {
63198 var _this = this;
63199 // Preserve contents if we already have an editor.
63200 var contents = null;
63201 if (this.editor) {
63202 this.editor.removeAllListeners();
63203 contents = this.editor.getContents();
63204 }
63205 this.$container.empty();
63206 // Prevent parent elements from handling keyboard shortcuts (e.g. ctrl+a) that have special meaning for textboxes.
63207 // Quill will also capture and prevent bubbling of some keyboard shortcuts, such as ctrl+c, ctrl+b, etc.
63208 this.$container.keydown(function (e) {
63209 if (e.ctrlKey && _.contains(QuillWrapper.preventDefaultKeys, e.which))
63210 e.stopPropagation();
63211 if (KeyUtils.isArrowKey(e.which))
63212 e.stopPropagation();
63213 });
63214 var $editorDiv = this.$editorDiv = $('<div>');
63215 // HACK: Quill does not apply the correct default styling if you clear all the content and add new content.
63216 $editorDiv.css('font-family', RichText.defaultFont);
63217 $editorDiv.css('font-size', RichText.defaultFontSize);
63218 var configs = {
63219 readOnly: this.readOnly,
63220 formats: ['bold', 'italic', 'underline', 'font', 'size', 'link', 'align',],
63221 styles: false,
63222 };
63223 this.editor = new Quill($editorDiv.get(0), configs);
63224 // If not readonly we add a toolbar and disable drag/resize
63225 if (!this.readOnly) {
63226 var $toolbarDiv = this.$toolbarDiv;
63227 if (!$toolbarDiv) {
63228 this.$toolbarDiv = $toolbarDiv = Toolbar.buildToolbar(this, this.localizationProvider);
63229 }
63230 $toolbarDiv.addClass('unselectable');
63231 this.host.setToolbar($toolbarDiv);
63232 this.editor.addModule('toolbar', { container: $toolbarDiv.get(0) });
63233 // Disable this so we can select text in the editor.
63234 $editorDiv.attr('drag-resize-disabled', 'true');
63235 }
63236 this.$container.append($editorDiv);
63237 if (contents)
63238 this.setContents(contents);
63239 // Throttle text-changed events to not more frequent than once per 200ms
63240 var textChangeThrottler = new jsCommon.ThrottleUtility(QuillWrapper.textChangeThrottle);
63241 this.editor.on('text-change', function (delta, source) {
63242 if (source !== 'api')
63243 textChangeThrottler.run(function () { return _this.onTextChanged(delta, source); });
63244 });
63245 /*
63246 Webkit browsers have a bug with regard to focus on div elements
63247 with the contenteditable attribute:
63248
63249 https://bugs.webkit.org/show_bug.cgi?id=38696
63250
63251 When we blur our rich text box editor the focus remains with the selection
63252 instead of the focused element. This allows the user to continue typing as
63253 if focus remains within the RichTextbox.
63254
63255 To fix this issue we add an event listener to the contenteditable div
63256 which listens for the 'blur' event and will properly blur our quill
63257 editor as well.
63258
63259 http://quilljs.com/docs/api/#quillprototypesetselection
63260
63261 Verified in Chrome 43.0.2357.130 m
63262
63263 In IE10+ the setSelection method explicitly sets focus to the body which
63264 causes a bug where the user must click twice when attempting to interact
63265 with a <select> element. To prevent this issue we explicitly do not call
63266 setSelection to blur if the user is changing focus to a <select> element.
63267 This issue is also present for link tooltips from the Quill module which
63268 will cause a blur onto the tooltip.
63269 */
63270 this.editor.root.addEventListener('blur', function (event) {
63271 var target = (event.relatedTarget || document.activeElement);
63272 // The browser will handle moving the cursor and setting focus properly for these types of elements.
63273 if (target &&
63274 target.tagName === 'SELECT' || target.tagName === 'INPUT' || target.getAttribute('contentEditable')) {
63275 return;
63276 }
63277 _this.setSelection(null, null);
63278 }, false);
63279 };
63280 QuillWrapper.prototype.onTextChanged = function (delta, source) {
63281 this.textChanged(delta, source);
63282 };
63283 QuillWrapper.textChangeThrottle = 200; // ms
63284 QuillWrapper.preventDefaultKeys = [
63285 jsCommon.DOMConstants.aKeyCode,
63286 jsCommon.DOMConstants.cKeyCode,
63287 jsCommon.DOMConstants.xKeyCode,
63288 jsCommon.DOMConstants.vKeyCode,
63289 ];
63290 QuillWrapper.loadQuillResources = true;
63291 // TODO: How to choose between minified/unminified?
63292 // TODO: Consider loading this from the CDN.
63293 QuillWrapper.quillJsFiles = [powerbi.build + '/externals/quill.min.js'];
63294 QuillWrapper.quillCssFiles = [powerbi.build + '/externals/quill.base.css'];
63295 return QuillWrapper;
63296 }());
63297 RichText.QuillWrapper = QuillWrapper;
63298 var Toolbar;
63299 (function (Toolbar) {
63300 var DefaultLinkInputValue = 'http://';
63301 Toolbar.selectors = {
63302 linkTooltip: createClassAndSelector('ql-link-tooltip'),
63303 toolbarUrlInput: createClassAndSelector('toolbar-url-input'),
63304 };
63305 function buildToolbar(quillWrapper, localizationProvider) {
63306 // Module for adding custom hyperlinks
63307 var linkTooltipTemplate = buildToolbarLinkInputTemplate(localizationProvider);
63308 quillWrapper.addModule('link-tooltip', { template: linkTooltipTemplate });
63309 var toolbarLinkInput = buildToolbarLinkInput(quillWrapper, getTooltip('Link', localizationProvider), localizationProvider.get('RichTextbox_Link_DefaultText'));
63310 var fontPicker = picker(getTooltip('Font', localizationProvider), fonts, 'font', RichText.defaultFont,
63311 // Show the fonts in their own font face.
63312 function ($option, option) { $option.css('font-family', option.value); return $option; });
63313 var $container = div()
63314 .addClass('toolbar ql-toolbar')
63315 .append(formatGroup()
63316 .append(label(localizationProvider.get('RichTextbox_Font_Label')))
63317 .append(fontPicker)
63318 .append(picker(getTooltip('Size', localizationProvider), fontSizes, 'size', RichText.defaultFontSize)))
63319 .append(formatGroup()
63320 .append(formatButton(getTooltip('Bold', localizationProvider), 'bold'))
63321 .append(formatButton(getTooltip('Italic', localizationProvider), 'italic'))
63322 .append(formatButton(getTooltip('Underline', localizationProvider), 'underline')))
63323 .append(formatGroup()
63324 .append(toggleGroup('Text Alignment', textAlignments, 'align', 'Left', localizationProvider)))
63325 .append(toolbarLinkInput);
63326 // Prevent mousedown from triggering subsequent blur on editor
63327 $container.on('mousedown', function (event) {
63328 var target = (event.target || document.activeElement);
63329 if (target.tagName !== 'INPUT' && target.tagName !== 'SELECT')
63330 event.preventDefault();
63331 });
63332 return $container;
63333 }
63334 Toolbar.buildToolbar = buildToolbar;
63335 function setSelectValue($select, value) {
63336 $select.val(value);
63337 // NOTE: The 'change' event is not raised when the value of the SELECT element is changed programatically,
63338 // and Quill uses it's own, non-JQuery, method to hook up to the 'change' event, therefore, we need to dispatch
63339 // this event manually on the SELECT element.
63340 var evt = document.createEvent('UIEvent');
63341 evt.initUIEvent('change', false, false, null, 0);
63342 $select.get(0).dispatchEvent(evt);
63343 }
63344 Toolbar.setSelectValue = setSelectValue;
63345 function linkTooltipTemplateGenerator(removeText, doneText) {
63346 return $("\n <a href=\"#\" class=\"url\" target=\"_blank\"></a>\n <input class=\"input\" type=\"text\">\n <span class=\"bar\">&nbsp;|&nbsp;</span>\n <a class=\"change\"></a>\n <a class=\"remove\">" + removeText + "</a>\n <a class=\"done\">" + doneText + "</a>\n ");
63347 }
63348 ;
63349 function buildToolbarLinkInputTemplate(localizationProvider) {
63350 var template = div();
63351 var doneText = localizationProvider.get('RichTextbox_Link_Done');
63352 var removeText = localizationProvider.get('RichTextbox_Link_Remove');
63353 template.append(linkTooltipTemplateGenerator(removeText, doneText));
63354 return template.html();
63355 }
63356 function formatGroup() {
63357 return span()
63358 .addClass('ql-format-group')
63359 .attr('drag-resize-disabled', 'true');
63360 }
63361 function label(text) {
63362 return $('<label>').text(text);
63363 }
63364 function div() {
63365 return $('<div>');
63366 }
63367 function span() {
63368 return $('<span>');
63369 }
63370 function toggleGroup(title, list, format, defaultValue, localizationProvider) {
63371 var tooltip = getTooltip(title, localizationProvider);
63372 var $group = span()
63373 .attr('title', tooltip)
63374 .addClass('ql-toggle-group');
63375 // Hidden selector that Quill will use to hook up change listeners.
63376 var $select = selector(tooltip, list, defaultValue)
63377 .addClass('ql-picker ql-' + format)
63378 .css('display', 'none');
63379 var $buttons = list.map(function (option) {
63380 var $button = formatButton(getTooltip(option.label, localizationProvider), 'align' + option.value)
63381 .attr('data-value', option.value)
63382 .click(function (e) { return setSelectValue($select, option.value); });
63383 return $button;
63384 });
63385 // Quill will change the value of the selector when the text selection changes, so we need to set the state of the buttons to match.
63386 $select.change(function (e) {
63387 var newValue = $select.val();
63388 for (var i = 0; i < $buttons.length; i++) {
63389 $buttons[i].toggleClass('ql-active', $buttons[i].attr('data-value') === newValue);
63390 }
63391 });
63392 $group.append($select);
63393 $group.append($buttons);
63394 return $group;
63395 }
63396 function picker(tooltip, list, format, defaultValue, optionModifier) {
63397 var $selector = selector(tooltip, list, defaultValue, optionModifier)
63398 .addClass('ql-picker ql-' + format);
63399 return $selector;
63400 }
63401 function selector(tooltip, list, defaultValue, optionModifier) {
63402 var $selector = $('<select>')
63403 .attr('title', tooltip);
63404 for (var i = 0; i < list.length; i++) {
63405 var option = list[i];
63406 var $option = $('<option>')
63407 .attr('value', option.value)
63408 .text(option.label);
63409 if (option.value === defaultValue)
63410 $option.attr('selected', 'selected');
63411 if (optionModifier !== undefined)
63412 $option = optionModifier($option, option);
63413 $selector.append($option);
63414 }
63415 return $selector;
63416 }
63417 function formatButton(tooltip, format) {
63418 var $button = span()
63419 .addClass('ql-format-button');
63420 if (tooltip != null)
63421 $button.attr('title', tooltip);
63422 if (format != null) {
63423 $button.addClass('ql-' + format);
63424 $button.addClass('powervisuals-glyph ' + format);
63425 }
63426 return $button;
63427 }
63428 function getTooltip(name, localizationProvider) {
63429 return localizationProvider.get('RichTextbox_' + name + '_ToolTip');
63430 }
63431 function clearLinkInput(linkTooltip) {
63432 linkTooltip.removeClass('editing');
63433 linkTooltip.removeClass('blank-editing');
63434 linkTooltip.find('.input').val(DefaultLinkInputValue);
63435 }
63436 function buildToolbarLinkInput(quillWrapper, buttonTooltip, defaultLinkText) {
63437 // Pull out link tooltip
63438 var linkTooltip = quillWrapper.getEditorContainer().find(Toolbar.selectors.linkTooltip.selector);
63439 // Append link tooltip to a new toolbar format group
63440 var toolbarLinkInput = formatGroup()
63441 .addClass(Toolbar.selectors.toolbarUrlInput.class)
63442 .append(formatButton(buttonTooltip, 'link').append('<div>'))
63443 .append(linkTooltip);
63444 // Special case for blank selection (no text near cursor) when enter key or done button clicked
63445 toolbarLinkInput.on('keydown mousedown', function (event) {
63446 if (event.keyCode === jsCommon.DOMConstants.enterKeyCode || event.target.classList.contains('done')) {
63447 if (!linkTooltip.hasClass('blank-editing'))
63448 return true;
63449 // Only perform these steps if tooltip was not in editing mode (special case for blank)
63450 var link = toolbarLinkInput.find('.input').val();
63451 var selection = quillWrapper.getSelectionAtCursor();
63452 var word = quillWrapper.getWord();
63453 if (!word) {
63454 // Insert the input text as a link
63455 var endCursor = quillWrapper.insertLinkAtCursor(link, selection.start);
63456 clearLinkInput(linkTooltip);
63457 quillWrapper.setSelection(endCursor, endCursor);
63458 return false;
63459 }
63460 }
63461 });
63462 toolbarLinkInput.find('.input').blur(function (event) {
63463 var blurTarget = event.relatedTarget;
63464 // Remove editing class from insert link tooltip (to hide via CSS)
63465 // only when we are not blurring to the 'done' button (tab from input field)
63466 if (blurTarget === null || blurTarget && !blurTarget.classList.contains('done'))
63467 clearLinkInput(linkTooltip);
63468 });
63469 toolbarLinkInput.find('.ql-link div')
63470 .click(function (event) {
63471 // Handle click on button before Quill removes link (default behavior)
63472 var target = event.target.parentElement;
63473 if (target && target.classList.contains('ql-active')) {
63474 toolbarLinkInput.find('.change')[0].click();
63475 return false;
63476 }
63477 // If blank selection (no text near cursor), special case for link button
63478 var word = quillWrapper.getWord();
63479 if (!word) {
63480 linkTooltip.addClass('editing blank-editing');
63481 var inputElem = toolbarLinkInput.find('.input').get(0);
63482 inputElem.value = DefaultLinkInputValue;
63483 inputElem.selectionStart = inputElem.selectionEnd = DefaultLinkInputValue.length;
63484 inputElem.focus();
63485 return false;
63486 }
63487 })
63488 .mousedown(function (event) {
63489 // Properly set selection before we handle the click
63490 var linkButton = event.target.parentElement;
63491 if (linkButton && !linkButton.classList.contains('ql-active')) {
63492 var selection = quillWrapper.getSelectionAtCursor();
63493 quillWrapper.setSelection(selection.start, selection.end);
63494 }
63495 });
63496 return toolbarLinkInput;
63497 }
63498 })(Toolbar || (Toolbar = {}));
63499 })(RichText = visuals.RichText || (visuals.RichText = {}));
63500 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
63501})(powerbi || (powerbi = {}));
63502/*
63503* Power BI Visualizations
63504*
63505* Copyright (c) Microsoft Corporation
63506* All rights reserved.
63507* MIT License
63508*
63509* Permission is hereby granted, free of charge, to any person obtaining a copy
63510* of this software and associated documentation files (the ""Software""), to deal
63511* in the Software without restriction, including without limitation the rights
63512* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
63513* copies of the Software, and to permit persons to whom the Software is
63514* furnished to do so, subject to the following conditions:
63515*
63516* The above copyright notice and this permission notice shall be included in
63517* all copies or substantial portions of the Software.
63518*
63519* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63520* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63521* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63522* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63523* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63524* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63525* THE SOFTWARE.
63526*/
63527var powerbi;
63528(function (powerbi) {
63529 var visuals;
63530 (function (visuals) {
63531 var SelectionManager = visuals.utility.SelectionManager;
63532 visuals.cheerMeterProps = {
63533 dataPoint: {
63534 defaultColor: {
63535 objectName: 'dataPoint',
63536 propertyName: 'defaultColor'
63537 },
63538 fill: {
63539 objectName: 'dataPoint',
63540 propertyName: 'fill'
63541 },
63542 },
63543 };
63544 var CheerMeter = (function () {
63545 function CheerMeter() {
63546 this.isFirstTime = true;
63547 }
63548 CheerMeter.converter = function (dataView) {
63549 if (!dataView.categorical || !dataView.categorical.categories)
63550 return null;
63551 var cat = dataView.categorical.categories[0];
63552 if (!cat)
63553 return null;
63554 var catValues = cat.values;
63555 if (!catValues || _.isEmpty(dataView.categorical.values))
63556 return null;
63557 var values = dataView.categorical.values[0].values;
63558 var objects = dataView.categorical.categories[0].objects;
63559 var object1 = objects && objects.length > 0 ? objects[0] : undefined;
63560 var object2 = objects && objects.length > 1 ? objects[1] : undefined;
63561 var metadataObjects = dataView.metadata.objects;
63562 var backgroundColor = CheerMeter.DefaultBackgroundColor;
63563 if (metadataObjects) {
63564 var general = metadataObjects['general'];
63565 if (general) {
63566 var fill = general['fill'];
63567 if (fill) {
63568 backgroundColor = fill.solid.color;
63569 }
63570 }
63571 }
63572 var color1 = powerbi.DataViewObjects.getFillColor(object1, visuals.cheerMeterProps.dataPoint.fill, CheerMeter.DefaultFontColor);
63573 var color2 = powerbi.DataViewObjects.getFillColor(object2, visuals.cheerMeterProps.dataPoint.fill, CheerMeter.DefaultFontColor);
63574 var idn1 = visuals.SelectionIdBuilder.builder()
63575 .withCategory(cat, 0)
63576 .createSelectionId();
63577 var idn2 = visuals.SelectionIdBuilder.builder()
63578 .withCategory(cat, 1)
63579 .createSelectionId();
63580 var data = {
63581 teamA: {
63582 name: catValues[0],
63583 value: values[0],
63584 color: color1,
63585 identity: idn1
63586 },
63587 teamB: {
63588 name: catValues[1],
63589 value: values[1],
63590 color: color2,
63591 identity: idn2
63592 },
63593 background: backgroundColor
63594 };
63595 return data;
63596 };
63597 CheerMeter.prototype.init = function (options) {
63598 this.selectionManager = new SelectionManager({ hostServices: options.host });
63599 var svg = this.svg = d3.select(options.element.get(0)).append('svg');
63600 this.textOne = svg.append('text')
63601 .style('font-family', CheerMeter.DefaultFontFamily);
63602 this.textTwo = svg.append('text')
63603 .style('font-family', CheerMeter.DefaultFontFamily);
63604 };
63605 CheerMeter.prototype.update = function (options) {
63606 if (!options.dataViews[0]) {
63607 return;
63608 }
63609 var data = this.data = CheerMeter.converter(options.dataViews[0]);
63610 if (!data)
63611 return;
63612 var duration = options.suppressAnimations ? 0 : visuals.AnimatorCommon.MinervaAnimationDuration;
63613 this.draw(data, duration, options.viewport);
63614 };
63615 CheerMeter.prototype.getRecomendedFontProperties = function (text1, text2, parentViewport) {
63616 var textProperties = {
63617 fontSize: '',
63618 fontFamily: CheerMeter.DefaultFontFamily,
63619 text: text1 + text2
63620 };
63621 var min = 1;
63622 var max = 1000;
63623 var i;
63624 var maxWidth = parentViewport.width;
63625 var width = 0;
63626 while (min <= max) {
63627 i = (min + max) / 2 | 0;
63628 textProperties.fontSize = i + 'px';
63629 width = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
63630 if (maxWidth > width)
63631 min = i + 1;
63632 else if (maxWidth < width)
63633 max = i - 1;
63634 else
63635 break;
63636 }
63637 textProperties.fontSize = i + 'px';
63638 width = powerbi.TextMeasurementService.measureSvgTextWidth(textProperties);
63639 if (width > maxWidth) {
63640 i--;
63641 textProperties.fontSize = i + 'px';
63642 }
63643 return textProperties;
63644 };
63645 CheerMeter.prototype.calculateLayout = function (data, viewport) {
63646 var text1 = data.teamA.name;
63647 var text2 = data.teamB.name;
63648 var avaliableViewport = {
63649 height: viewport.height,
63650 width: viewport.width - CheerMeter.PaddingBetweenText
63651 };
63652 var recomendedFontProperties = this.getRecomendedFontProperties(text1, text2, avaliableViewport);
63653 recomendedFontProperties.text = text1;
63654 var width1 = powerbi.TextMeasurementService.measureSvgTextWidth(recomendedFontProperties) | 0;
63655 recomendedFontProperties.text = text2;
63656 var width2 = powerbi.TextMeasurementService.measureSvgTextWidth(recomendedFontProperties) | 0;
63657 var padding = ((viewport.width - width1 - width2 - CheerMeter.PaddingBetweenText) / 2) | 0;
63658 recomendedFontProperties.text = text1 + text2;
63659 var offsetHeight = (powerbi.TextMeasurementService.measureSvgTextHeight(recomendedFontProperties)) | 0;
63660 var max = data.teamA.value + data.teamB.value;
63661 var availableHeight = viewport.height - offsetHeight;
63662 var y1 = (((max - data.teamA.value) / max) * availableHeight + offsetHeight / 2) | 0;
63663 var y2 = (((max - data.teamB.value) / max) * availableHeight + offsetHeight / 2) | 0;
63664 return {
63665 x1: padding,
63666 x2: padding + width1 + CheerMeter.PaddingBetweenText,
63667 y1: y1,
63668 y2: y2,
63669 fontSize: recomendedFontProperties.fontSize
63670 };
63671 };
63672 CheerMeter.prototype.ensureStartState = function (layout, viewport) {
63673 if (this.isFirstTime) {
63674 this.isFirstTime = false;
63675 var startY = viewport.height / 2;
63676 this.textOne.attr({
63677 'x': layout.x1,
63678 'y': startY
63679 });
63680 this.textTwo.attr({
63681 'x': layout.x2,
63682 'y': startY
63683 });
63684 }
63685 };
63686 CheerMeter.prototype.clearSelection = function () {
63687 var _this = this;
63688 this.selectionManager.clear().then(function () {
63689 _this.clearSelectionUI();
63690 });
63691 };
63692 CheerMeter.prototype.clearSelectionUI = function () {
63693 this.textOne.style('stroke', '#FFF').style('stroke-width', 0);
63694 this.textTwo.style('stroke', '#FFF').style('stroke-width', 0);
63695 };
63696 CheerMeter.prototype.updateSelectionUI = function (ids) {
63697 this.textOne.style('stroke', '#FFF').style('stroke-width', SelectionManager.containsSelection(ids, this.data.teamA.identity) ? '2px' : '0px');
63698 this.textTwo.style('stroke', '#FFF').style('stroke-width', SelectionManager.containsSelection(ids, this.data.teamB.identity) ? '2px' : '0px');
63699 };
63700 CheerMeter.prototype.draw = function (data, duration, viewport) {
63701 var _this = this;
63702 var easeName = 'back';
63703 var textOne = this.textOne;
63704 var textTwo = this.textTwo;
63705 this.svg
63706 .attr({
63707 'height': viewport.height,
63708 'width': viewport.width
63709 })
63710 .on('click', function () {
63711 _this.clearSelection();
63712 })
63713 .style('background-color', data.background);
63714 var layout = this.calculateLayout(data, viewport);
63715 this.ensureStartState(layout, viewport);
63716 textOne
63717 .style('font-size', layout.fontSize)
63718 .style('fill', data.teamA.color)
63719 .on('click', function () {
63720 _this.selectionManager.select(data.teamA.identity, d3.event.ctrlKey).then(function (ids) {
63721 _this.updateSelectionUI(ids);
63722 });
63723 d3.event.stopPropagation();
63724 })
63725 .text(data.teamA.name);
63726 textTwo
63727 .style('font-size', layout.fontSize)
63728 .style('fill', data.teamB.color)
63729 .on('click', function () {
63730 _this.selectionManager.select(data.teamB.identity, d3.event.ctrlKey).then(function (ids) {
63731 _this.updateSelectionUI(ids);
63732 });
63733 d3.event.stopPropagation();
63734 })
63735 .text(data.teamB.name);
63736 textOne.transition()
63737 .duration(duration)
63738 .ease(easeName)
63739 .attr({
63740 y: layout.y1,
63741 x: layout.x1
63742 });
63743 textTwo.transition()
63744 .duration(duration)
63745 .ease(easeName)
63746 .attr({
63747 y: layout.y2,
63748 x: layout.x2
63749 });
63750 };
63751 CheerMeter.prototype.destroy = function () {
63752 this.svg = null;
63753 this.textOne = this.textTwo = null;
63754 };
63755 CheerMeter.prototype.enumerateObjectInstances = function (options) {
63756 var instances = [];
63757 var data = this.data;
63758 switch (options.objectName) {
63759 case 'dataPoint':
63760 if (data) {
63761 var teams = [data.teamA, data.teamB];
63762 for (var i = 0; i < teams.length; i++) {
63763 var slice = teams[i];
63764 var color = slice.color;
63765 var selector = slice.identity;
63766 var dataPointInstance = {
63767 objectName: 'dataPoint',
63768 displayName: slice.name,
63769 selector: selector,
63770 properties: {
63771 fill: { solid: { color: color } }
63772 },
63773 };
63774 instances.push(dataPointInstance);
63775 }
63776 ;
63777 }
63778 break;
63779 case 'general':
63780 var general = {
63781 objectName: 'general',
63782 displayName: 'General',
63783 selector: null,
63784 properties: {
63785 fill: { solid: { color: data ? data.background : CheerMeter.DefaultBackgroundColor } }
63786 }
63787 };
63788 instances.push(general);
63789 break;
63790 }
63791 return instances;
63792 };
63793 CheerMeter.capabilities = {
63794 dataRoles: [
63795 {
63796 displayName: 'Category',
63797 name: 'Category',
63798 kind: powerbi.VisualDataRoleKind.Grouping,
63799 },
63800 {
63801 displayName: 'Noise Measure',
63802 name: 'Y',
63803 kind: powerbi.VisualDataRoleKind.Measure,
63804 },
63805 ],
63806 dataViewMappings: [{
63807 categorical: {
63808 categories: {
63809 for: { in: 'Category' },
63810 },
63811 values: {
63812 select: [{ bind: { to: 'Y' } }]
63813 },
63814 },
63815 }],
63816 objects: {
63817 dataPoint: {
63818 displayName: powerbi.data.createDisplayNameGetter('Visual_DataPoint'),
63819 description: powerbi.data.createDisplayNameGetter('Visual_DataPointDescription'),
63820 properties: {
63821 fill: {
63822 displayName: powerbi.data.createDisplayNameGetter('Visual_Fill'),
63823 type: { fill: { solid: { color: true } } }
63824 },
63825 width: {
63826 displayName: '',
63827 type: { numeric: true }
63828 }
63829 }
63830 },
63831 general: {
63832 displayName: 'General',
63833 properties: {
63834 fill: {
63835 displayName: 'Background color',
63836 type: { fill: { solid: { color: true } } }
63837 },
63838 }
63839 }
63840 }
63841 };
63842 CheerMeter.DefaultFontFamily = 'cursive';
63843 CheerMeter.DefaultFontColor = 'rgb(165, 172, 175)';
63844 CheerMeter.DefaultBackgroundColor = '#243C18';
63845 CheerMeter.PaddingBetweenText = 15;
63846 return CheerMeter;
63847 }());
63848 visuals.CheerMeter = CheerMeter;
63849 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
63850})(powerbi || (powerbi = {}));
63851/*
63852 * Power BI Visualizations
63853 *
63854 * Copyright (c) Microsoft Corporation
63855 * All rights reserved.
63856 * MIT License
63857 *
63858 * Permission is hereby granted, free of charge, to any person obtaining a copy
63859 * of this software and associated documentation files (the ""Software""), to deal
63860 * in the Software without restriction, including without limitation the rights
63861 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
63862 * copies of the Software, and to permit persons to whom the Software is
63863 * furnished to do so, subject to the following conditions:
63864 *
63865 * The above copyright notice and this permission notice shall be included in
63866 * all copies or substantial portions of the Software.
63867 *
63868 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63869 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63870 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63871 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63872 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63873 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63874 * THE SOFTWARE.
63875 */
63876var powerbi;
63877(function (powerbi) {
63878 var visuals;
63879 (function (visuals) {
63880 var Color = jsCommon.Color;
63881 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
63882 var PixelConverter = jsCommon.PixelConverter;
63883 var DataRoleHelper = powerbi.data.DataRoleHelper;
63884 var ScatterChart = (function () {
63885 function ScatterChart(options) {
63886 if (options) {
63887 this.tooltipsEnabled = options.tooltipsEnabled;
63888 this.interactivityService = options.interactivityService;
63889 this.animator = options.animator;
63890 }
63891 this.renderer = new SvgRenderer();
63892 }
63893 ScatterChart.prototype.init = function (options) {
63894 this.options = options;
63895 this.element = options.element;
63896 this.currentViewport = options.viewport;
63897 this.style = options.style;
63898 this.host = options.host;
63899 this.colors = this.style.colorPalette.dataColors;
63900 this.interactivity = options.interactivity;
63901 this.cartesianVisualHost = options.cartesianHost;
63902 this.isMobileChart = options.interactivity && options.interactivity.isInteractiveLegend;
63903 var svg = this.svg = options.svg;
63904 // TODO: should we always be adding the playchart class name?
63905 svg.classed(ScatterChart.ClassName + ' ' + visuals.PlayChart.ClassName, true);
63906 this.renderer.init(svg, options.labelsContext, this.isMobileChart, this.tooltipsEnabled);
63907 };
63908 ScatterChart.getAdditionalTelemetry = function (dataView) {
63909 var telemetry = {
63910 hasSize: DataRoleHelper.hasRoleInDataView(dataView, 'Size'),
63911 hasPlayAxis: DataRoleHelper.hasRoleInDataView(dataView, 'Play'),
63912 };
63913 return telemetry;
63914 };
63915 ScatterChart.getObjectProperties = function (dataView, dataLabelsSettings) {
63916 var objects;
63917 if (dataView && dataView.metadata && dataView.metadata.objects)
63918 objects = dataView.metadata.objects;
63919 else
63920 objects = {};
63921 var objectProperties = {};
63922 objectProperties.defaultDataPointColor = powerbi.DataViewObjects.getFillColor(objects, visuals.columnChartProps.dataPoint.defaultColor);
63923 objectProperties.showAllDataPoints = powerbi.DataViewObjects.getValue(objects, visuals.columnChartProps.dataPoint.showAllDataPoints, false);
63924 var labelsObj = objects['categoryLabels'];
63925 if (labelsObj && dataLabelsSettings)
63926 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelsObj, dataLabelsSettings);
63927 // NOTE: "fill point" defaults to on when we have a gradient role.
63928 var hasGradient = dataView && visuals.GradientUtils.hasGradientRole(dataView.categorical);
63929 objectProperties.fillPoint = powerbi.DataViewObjects.getValue(objects, visuals.scatterChartProps.fillPoint.show, hasGradient);
63930 objectProperties.colorBorder = powerbi.DataViewObjects.getValue(objects, visuals.scatterChartProps.colorBorder.show, false);
63931 objectProperties.colorByCategory = powerbi.DataViewObjects.getValue(objects, visuals.scatterChartProps.colorByCategory.show, false);
63932 return objectProperties;
63933 };
63934 ScatterChart.converter = function (dataView, options, playFrameInfo, tooltipsEnabled) {
63935 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
63936 var reader = powerbi.data.createIDataViewCategoricalReader(dataView);
63937 var categoryValues, categoryFormatter, categoryObjects, categoryIdentities, categoryQueryName;
63938 var currentViewport = options.viewport;
63939 var colorPalette = options.colors;
63940 var interactivityService = options.interactivityService;
63941 var categoryAxisProperties = options.categoryAxisProperties;
63942 var valueAxisProperties = options.valueAxisProperties;
63943 var dataViewCategorical = dataView.categorical;
63944 var gradientValueColumn = visuals.GradientUtils.getGradientValueColumn(dataViewCategorical);
63945 if (dataViewCategorical.categories && dataViewCategorical.categories.length > 0) {
63946 categoryValues = dataViewCategorical.categories[0].values;
63947 categoryFormatter = visuals.valueFormatter.create({ format: visuals.valueFormatter.getFormatString(dataViewCategorical.categories[0].source, visuals.scatterChartProps.general.formatString), value: categoryValues[0], value2: categoryValues[categoryValues.length - 1] });
63948 categoryIdentities = dataViewCategorical.categories[0].identity;
63949 categoryObjects = dataViewCategorical.categories[0].objects;
63950 categoryQueryName = dataViewCategorical.categories[0].source.queryName;
63951 }
63952 else {
63953 categoryValues = [null];
63954 // creating default formatter for null value (to get the right string of empty value from the locale)
63955 categoryFormatter = visuals.valueFormatter.createDefaultFormatter(null);
63956 }
63957 var categories = dataViewCategorical.categories;
63958 var dataValues = dataViewCategorical.values;
63959 var hasDynamicSeries = !!dataValues.source;
63960 var grouped = dataValues.grouped();
63961 var dvSource = dataValues.source;
63962 var scatterMetadata = ScatterChart.getMetadata(grouped, dvSource);
63963 var dataLabelsSettings = visuals.dataLabelUtils.getDefaultPointLabelSettings();
63964 var sizeRange = ScatterChart.getSizeRangeForGroups(grouped, scatterMetadata.idx.size);
63965 var objProps = ScatterChart.getObjectProperties(dataView, dataLabelsSettings);
63966 var dataPointSeries = ScatterChart.createDataPointSeries(reader, dataValues, scatterMetadata, categories, categoryValues, categoryFormatter, categoryIdentities, categoryObjects, colorPalette, currentViewport, hasDynamicSeries, dataLabelsSettings, gradientValueColumn, objProps.defaultDataPointColor, categoryQueryName, objProps.colorByCategory, playFrameInfo, tooltipsEnabled);
63967 var dataPoints = _.reduce(dataPointSeries, function (a, s) { return a.concat(s.dataPoints); }, []);
63968 var legendItems = hasDynamicSeries
63969 ? ScatterChart.createSeriesLegend(dataValues, colorPalette, dataValues, visuals.valueFormatter.getFormatString(dvSource, visuals.scatterChartProps.general.formatString), objProps.defaultDataPointColor)
63970 : [];
63971 var legendTitle = dataValues && dvSource ? dvSource.displayName : "";
63972 if (!legendTitle) {
63973 legendTitle = categories && categories.length > 0 && categories[0].source.displayName ? categories[0].source.displayName : "";
63974 }
63975 if (categoryAxisProperties && categoryAxisProperties["showAxisTitle"] !== null && categoryAxisProperties["showAxisTitle"] === false) {
63976 scatterMetadata.axesLabels.x = null;
63977 }
63978 if (valueAxisProperties && valueAxisProperties["showAxisTitle"] !== null && valueAxisProperties["showAxisTitle"] === false) {
63979 scatterMetadata.axesLabels.y = null;
63980 }
63981 if (interactivityService) {
63982 interactivityService.applySelectionStateToData(dataPoints);
63983 interactivityService.applySelectionStateToData(legendItems);
63984 }
63985 return {
63986 xCol: scatterMetadata.cols.x,
63987 yCol: scatterMetadata.cols.y,
63988 dataPoints: dataPoints,
63989 dataPointSeries: dataPointSeries,
63990 legendData: { title: legendTitle, dataPoints: legendItems },
63991 axesLabels: scatterMetadata.axesLabels,
63992 size: scatterMetadata.cols.size,
63993 sizeRange: sizeRange,
63994 dataLabelsSettings: dataLabelsSettings,
63995 defaultDataPointColor: objProps.defaultDataPointColor,
63996 hasDynamicSeries: hasDynamicSeries,
63997 showAllDataPoints: objProps.showAllDataPoints,
63998 fillPoint: objProps.fillPoint,
63999 colorBorder: objProps.colorBorder,
64000 colorByCategory: objProps.colorByCategory,
64001 };
64002 };
64003 ScatterChart.getSizeRangeForGroups = function (dataViewValueGroups, sizeColumnIndex) {
64004 var result = {};
64005 if (dataViewValueGroups) {
64006 dataViewValueGroups.forEach(function (group) {
64007 var sizeColumn = ScatterChart.getMeasureValue(sizeColumnIndex, group.values);
64008 var currentRange = visuals.AxisHelper.getRangeForColumn(sizeColumn);
64009 if (result.min == null || result.min > currentRange.min) {
64010 result.min = currentRange.min;
64011 }
64012 if (result.max == null || result.max < currentRange.max) {
64013 result.max = currentRange.max;
64014 }
64015 });
64016 }
64017 return result;
64018 };
64019 ScatterChart.createDataPointSeries = function (reader, dataValues, metadata, categories, categoryValues, categoryFormatter, categoryIdentities, categoryObjects, colorPalette, viewport, hasDynamicSeries, labelSettings, gradientValueColumn, defaultDataPointColor, categoryQueryName, colorByCategory, playFrameInfo, tooltipsEnabled) {
64020 var hasX = reader.hasValues("X");
64021 var hasY = reader.hasValues("Y");
64022 if (!hasX && !hasY) {
64023 return [];
64024 }
64025 var dataPointSeries = [], indicies = metadata.idx, formatStringProp = visuals.scatterChartProps.general.formatString, dataValueSource = dataValues.source, grouped = dataValues.grouped();
64026 var colorHelper = new visuals.ColorHelper(colorPalette, visuals.scatterChartProps.dataPoint.fill, defaultDataPointColor);
64027 for (var seriesIndex = 0, len = grouped.length; seriesIndex < len; seriesIndex++) {
64028 var grouping = grouped[seriesIndex];
64029 var seriesValues = grouping.values;
64030 var measureX = ScatterChart.getMeasureValue(indicies.x, seriesValues);
64031 var measureY = ScatterChart.getMeasureValue(indicies.y, seriesValues);
64032 var measureSize = ScatterChart.getMeasureValue(indicies.size, seriesValues);
64033 var seriesColor = void 0;
64034 if (hasDynamicSeries) {
64035 seriesColor = colorHelper.getColorForSeriesValue(grouping.objects, dataValues.identityFields, grouping.name);
64036 }
64037 else if (!colorByCategory && !categoryObjects) {
64038 // If we have no Size measure then use a blank query name
64039 var measureSource = (measureSize != null)
64040 ? measureSize.source.queryName
64041 : '';
64042 seriesColor = colorHelper.getColorForMeasure(null, measureSource);
64043 }
64044 var series = {
64045 identityKey: (grouping && grouping.identity && grouping.identity.key) || "",
64046 dataPoints: [],
64047 hasSize: !!(measureSize && measureSize.values),
64048 fill: seriesColor,
64049 };
64050 dataPointSeries.push(series);
64051 for (var categoryIndex = 0, ilen = categoryValues.length; categoryIndex < ilen; categoryIndex++) {
64052 var categoryValue = categoryValues[categoryIndex];
64053 // Zero out X and Y if the role doesn't exist, so you still get a set of vertical/horizontal dots
64054 var xVal = hasX ? visuals.AxisHelper.normalizeNonFiniteNumber(reader.getValue("X", categoryIndex, seriesIndex)) : 0;
64055 var yVal = hasY ? visuals.AxisHelper.normalizeNonFiniteNumber(reader.getValue("Y", categoryIndex, seriesIndex)) : 0;
64056 // Undefined size is handled later if we don't have a size role, so this is fine to just be undefined
64057 var size = visuals.AxisHelper.normalizeNonFiniteNumber(reader.getValue("Size", categoryIndex, seriesIndex));
64058 // Do not render a dot if X or Y are null
64059 if (xVal == null || yVal == null)
64060 continue;
64061 var color = void 0;
64062 if (hasDynamicSeries) {
64063 color = colorHelper.getColorForSeriesValue(grouping.objects, dataValues.identityFields, grouping.name);
64064 }
64065 else if (colorByCategory) {
64066 color = colorHelper.getColorForSeriesValue(categoryObjects && categoryObjects[categoryIndex], dataValues.identityFields, categoryValue);
64067 }
64068 else {
64069 // If we have no Size measure then use a blank query name
64070 var measureSource = (measureSize != null)
64071 ? measureSize.source.queryName
64072 : '';
64073 color = colorHelper.getColorForMeasure(categoryObjects && categoryObjects[categoryIndex], measureSource);
64074 }
64075 var category = !_.isEmpty(categories) ? categories[0] : null;
64076 var identity = visuals.SelectionIdBuilder.builder()
64077 .withCategory(category, categoryIndex)
64078 .withSeries(dataValues, grouping)
64079 .createSelectionId();
64080 var tooltipInfo = void 0;
64081 if (tooltipsEnabled) {
64082 tooltipInfo = [];
64083 if (category) {
64084 tooltipInfo.push({
64085 displayName: category.source.displayName,
64086 value: visuals.converterHelper.formatFromMetadataColumn(categoryValue, category.source, formatStringProp),
64087 });
64088 }
64089 if (hasDynamicSeries) {
64090 // Dynamic series
64091 if (!category || category.source !== dataValueSource) {
64092 tooltipInfo.push({
64093 displayName: dataValueSource.displayName,
64094 value: visuals.converterHelper.formatFromMetadataColumn(grouping.name, dataValueSource, formatStringProp),
64095 });
64096 }
64097 }
64098 if (measureX && xVal != null) {
64099 tooltipInfo.push({
64100 displayName: measureX.source.displayName,
64101 value: visuals.converterHelper.formatFromMetadataColumn(xVal, measureX.source, formatStringProp),
64102 });
64103 }
64104 if (measureY && yVal != null) {
64105 tooltipInfo.push({
64106 displayName: measureY.source.displayName,
64107 value: visuals.converterHelper.formatFromMetadataColumn(yVal, measureY.source, formatStringProp),
64108 });
64109 }
64110 if (measureSize && measureSize.values[categoryIndex] != null) {
64111 tooltipInfo.push({
64112 displayName: measureSize.source.displayName,
64113 value: visuals.converterHelper.formatFromMetadataColumn(measureSize.values[categoryIndex], measureSize.source, formatStringProp),
64114 });
64115 }
64116 if (gradientValueColumn && gradientValueColumn.values[categoryIndex] != null) {
64117 tooltipInfo.push({
64118 displayName: gradientValueColumn.source.displayName,
64119 value: visuals.converterHelper.formatFromMetadataColumn(gradientValueColumn.values[categoryIndex], gradientValueColumn.source, formatStringProp),
64120 });
64121 }
64122 if (playFrameInfo) {
64123 tooltipInfo.push({
64124 displayName: playFrameInfo.column.displayName,
64125 value: visuals.converterHelper.formatFromMetadataColumn(playFrameInfo.label, playFrameInfo.column, formatStringProp),
64126 });
64127 }
64128 }
64129 var dataPoint = {
64130 x: xVal,
64131 y: yVal,
64132 size: size,
64133 radius: { sizeMeasure: measureSize, index: categoryIndex },
64134 fill: color,
64135 formattedCategory: ScatterChart.createLazyFormattedCategory(categoryFormatter, categories != null ? categoryValue : grouping.name),
64136 selected: false,
64137 identity: identity,
64138 tooltipInfo: tooltipInfo,
64139 labelFill: labelSettings.labelColor,
64140 };
64141 series.dataPoints.push(dataPoint);
64142 }
64143 }
64144 return dataPointSeries;
64145 };
64146 ScatterChart.createLazyFormattedCategory = function (formatter, value) {
64147 return new jsCommon.Lazy(function () { return formatter.format(value); });
64148 };
64149 ScatterChart.createSeriesLegend = function (dataValues, colorPalette, categorical, formatString, defaultDataPointColor) {
64150 var grouped = dataValues.grouped();
64151 var colorHelper = new visuals.ColorHelper(colorPalette, visuals.scatterChartProps.dataPoint.fill, defaultDataPointColor);
64152 var legendItems = [];
64153 for (var i = 0, len = grouped.length; i < len; i++) {
64154 var grouping = grouped[i];
64155 var color = colorHelper.getColorForSeriesValue(grouping.objects, dataValues.identityFields, grouping.name);
64156 legendItems.push({
64157 color: color,
64158 icon: visuals.LegendIcon.Circle,
64159 label: visuals.valueFormatter.format(grouping.name, formatString),
64160 identity: grouping.identity ? visuals.SelectionId.createWithId(grouping.identity) : visuals.SelectionId.createNull(),
64161 selected: false
64162 });
64163 }
64164 return legendItems;
64165 };
64166 ScatterChart.getBubbleRadius = function (radiusData, sizeRange, viewport) {
64167 var actualSizeDataRange = null;
64168 var bubblePixelAreaSizeRange = null;
64169 var measureSize = radiusData.sizeMeasure;
64170 if (!measureSize)
64171 return ScatterChart.BubbleRadius;
64172 var minSize = sizeRange.min ? sizeRange.min : 0;
64173 var maxSize = sizeRange.max ? sizeRange.max : 0;
64174 var min = Math.min(minSize, 0);
64175 var max = Math.max(maxSize, 0);
64176 actualSizeDataRange = {
64177 minRange: min,
64178 maxRange: max,
64179 delta: max - min
64180 };
64181 bubblePixelAreaSizeRange = ScatterChart.getBubblePixelAreaSizeRange(viewport, ScatterChart.MinSizeRange, ScatterChart.MaxSizeRange);
64182 if (measureSize.values) {
64183 var sizeValue = measureSize.values[radiusData.index];
64184 if (sizeValue != null) {
64185 return ScatterChart.projectSizeToPixels(sizeValue, actualSizeDataRange, bubblePixelAreaSizeRange) / 2;
64186 }
64187 }
64188 return ScatterChart.BubbleRadius;
64189 };
64190 ScatterChart.getMeasureValue = function (measureIndex, seriesValues) {
64191 if (measureIndex >= 0)
64192 return seriesValues[measureIndex];
64193 return null;
64194 };
64195 ScatterChart.getMetadata = function (grouped, source) {
64196 var xIndex = DataRoleHelper.getMeasureIndexOfRole(grouped, 'X');
64197 var yIndex = DataRoleHelper.getMeasureIndexOfRole(grouped, 'Y');
64198 var sizeIndex = DataRoleHelper.getMeasureIndexOfRole(grouped, 'Size');
64199 var xCol;
64200 var yCol;
64201 var sizeCol;
64202 var xAxisLabel = "";
64203 var yAxisLabel = "";
64204 if (grouped && grouped.length) {
64205 var firstGroup = grouped[0];
64206 if (xIndex >= 0) {
64207 xCol = firstGroup.values[xIndex].source;
64208 xAxisLabel = firstGroup.values[xIndex].source.displayName;
64209 }
64210 if (yIndex >= 0) {
64211 yCol = firstGroup.values[yIndex].source;
64212 yAxisLabel = firstGroup.values[yIndex].source.displayName;
64213 }
64214 if (sizeIndex >= 0) {
64215 sizeCol = firstGroup.values[sizeIndex].source;
64216 }
64217 }
64218 return {
64219 idx: {
64220 x: xIndex,
64221 y: yIndex,
64222 size: sizeIndex,
64223 },
64224 cols: {
64225 x: xCol,
64226 y: yCol,
64227 size: sizeCol,
64228 },
64229 axesLabels: {
64230 x: xAxisLabel,
64231 y: yAxisLabel
64232 }
64233 };
64234 };
64235 /** Create a new viewmodel with default data. */
64236 ScatterChart.getDefaultData = function () {
64237 return {
64238 xCol: undefined,
64239 yCol: undefined,
64240 dataPoints: [],
64241 dataPointSeries: [],
64242 legendData: { dataPoints: [] },
64243 axesLabels: { x: '', y: '' },
64244 sizeRange: [],
64245 dataLabelsSettings: visuals.dataLabelUtils.getDefaultPointLabelSettings(),
64246 defaultDataPointColor: null,
64247 hasDynamicSeries: false,
64248 };
64249 };
64250 ScatterChart.prototype.renderAtFrame = function (data) {
64251 this.data = data;
64252 this.cartesianVisualHost.triggerRender(false);
64253 };
64254 ScatterChart.prototype.setData = function (dataViews) {
64255 var _this = this;
64256 this.data = ScatterChart.getDefaultData();
64257 if (dataViews.length > 0) {
64258 var dataView = dataViews[0] || dataViews[1];
64259 if (dataView) {
64260 this.categoryAxisProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataView.metadata, true);
64261 this.valueAxisProperties = visuals.CartesianHelper.getValueAxisProperties(dataView.metadata, true);
64262 this.dataView = dataView;
64263 var converterOptions_1 = {
64264 viewport: this.currentViewport,
64265 colors: this.colors,
64266 interactivityService: this.interactivityService,
64267 categoryAxisProperties: this.categoryAxisProperties,
64268 valueAxisProperties: this.valueAxisProperties,
64269 };
64270 if (visuals.PlayChart.isDataViewPlayable(dataView)) {
64271 if (!this.playAxis) {
64272 this.playAxis = new visuals.PlayAxis({
64273 animator: this.animator,
64274 interactivityService: this.interactivityService,
64275 isScrollable: false,
64276 });
64277 this.playAxis.init(this.options);
64278 }
64279 var playData = this.playAxis.setData(dataView, function (dataView, playFrameInfo) {
64280 return ScatterChart.converter(dataView, converterOptions_1, playFrameInfo, _this.tooltipsEnabled);
64281 });
64282 this.mergeSizeRanges(playData);
64283 this.data = playData.currentViewModel;
64284 this.playAxis.setRenderFunction(function (data) { return _this.renderAtFrame(data); });
64285 }
64286 else {
64287 if (this.playAxis) {
64288 this.playAxis.remove();
64289 this.playAxis = null;
64290 }
64291 if (dataView.categorical && dataView.categorical.values) {
64292 this.data = ScatterChart.converter(dataView, converterOptions_1, undefined, this.tooltipsEnabled);
64293 }
64294 }
64295 }
64296 }
64297 else if (this.playAxis) {
64298 this.playAxis.remove();
64299 this.playAxis = null;
64300 }
64301 };
64302 ScatterChart.prototype.mergeSizeRanges = function (playData) {
64303 if (playData && playData.currentViewModel) {
64304 var mergedSizeRange = playData.currentViewModel.sizeRange;
64305 for (var _i = 0, _a = playData.allViewModels; _i < _a.length; _i++) {
64306 var data_3 = _a[_i];
64307 var sizeRange = data_3.sizeRange;
64308 if (sizeRange.min != null)
64309 mergedSizeRange.min = Math.min(mergedSizeRange.min, sizeRange.min);
64310 if (sizeRange.max != null)
64311 mergedSizeRange.max = Math.max(mergedSizeRange.max, sizeRange.max);
64312 }
64313 for (var _b = 0, _c = playData.allViewModels; _b < _c.length; _b++) {
64314 var data_4 = _c[_b];
64315 data_4.sizeRange = mergedSizeRange;
64316 }
64317 }
64318 };
64319 ScatterChart.prototype.calculateLegend = function () {
64320 return this.data && this.data.legendData;
64321 };
64322 ScatterChart.prototype.hasLegend = function () {
64323 return this.data && this.data.hasDynamicSeries;
64324 };
64325 ScatterChart.prototype.enumerateObjectInstances = function (enumeration, options) {
64326 switch (options.objectName) {
64327 case 'colorByCategory':
64328 if (this.data) {
64329 // Color by Legend takes precedent during render. Hide the slice but keep the colorByCategory value unchanged in case they remove the Legend field.
64330 if (!this.data.hasDynamicSeries) {
64331 enumeration.pushInstance({
64332 objectName: 'colorByCategory',
64333 selector: null,
64334 properties: {
64335 show: this.data.colorByCategory,
64336 },
64337 });
64338 }
64339 }
64340 break;
64341 case 'dataPoint':
64342 // TODO: DataViewMatix (for PlayAxis) doesn't support category- or series-specific properties yet.
64343 if (!this.playAxis) {
64344 var categoricalDataView = this.dataView && this.dataView.categorical ? this.dataView.categorical : null;
64345 if (!visuals.GradientUtils.hasGradientRole(categoricalDataView))
64346 return this.enumerateDataPoints(enumeration);
64347 }
64348 break;
64349 case 'categoryAxis':
64350 enumeration.pushInstance({
64351 selector: null,
64352 properties: {
64353 showAxisTitle: !this.categoryAxisProperties || this.categoryAxisProperties["showAxisTitle"] == null ? true : this.categoryAxisProperties["showAxisTitle"]
64354 },
64355 objectName: 'categoryAxis'
64356 });
64357 break;
64358 case 'valueAxis':
64359 enumeration.pushInstance({
64360 selector: null,
64361 properties: {
64362 showAxisTitle: !this.valueAxisProperties || this.valueAxisProperties["showAxisTitle"] == null ? true : this.valueAxisProperties["showAxisTitle"]
64363 },
64364 objectName: 'valueAxis'
64365 });
64366 break;
64367 case 'categoryLabels':
64368 if (this.data)
64369 visuals.dataLabelUtils.enumerateCategoryLabels(enumeration, this.data.dataLabelsSettings, true);
64370 else
64371 visuals.dataLabelUtils.enumerateCategoryLabels(enumeration, null, true);
64372 break;
64373 case 'fillPoint':
64374 // Check if the card should be shown or not based on the existence of size measure
64375 if (this.hasSizeMeasure())
64376 return;
64377 enumeration.pushInstance({
64378 objectName: 'fillPoint',
64379 selector: null,
64380 properties: {
64381 show: this.data.fillPoint,
64382 },
64383 });
64384 break;
64385 case 'colorBorder':
64386 // Check if the card should be shown or not based on the existence of size measure
64387 if (this.hasSizeMeasure())
64388 enumeration.pushInstance({
64389 objectName: 'colorBorder',
64390 selector: null,
64391 properties: {
64392 show: this.data.colorBorder,
64393 },
64394 });
64395 break;
64396 }
64397 };
64398 ScatterChart.prototype.hasSizeMeasure = function () {
64399 var sizeRange = this.data.sizeRange;
64400 return sizeRange && sizeRange.min !== undefined;
64401 };
64402 ScatterChart.prototype.enumerateDataPoints = function (enumeration) {
64403 var data = this.data;
64404 if (!data)
64405 return;
64406 var seriesCount = data.dataPoints.length;
64407 if (!data.hasDynamicSeries) {
64408 enumeration.pushInstance({
64409 objectName: 'dataPoint',
64410 selector: null,
64411 properties: {
64412 defaultColor: { solid: { color: data.defaultDataPointColor || this.colors.getColorByIndex(0).value } }
64413 }
64414 }).pushInstance({
64415 objectName: 'dataPoint',
64416 selector: null,
64417 properties: {
64418 showAllDataPoints: !!data.showAllDataPoints
64419 }
64420 });
64421 for (var i = 0; i < seriesCount; i++) {
64422 var seriesDataPoints = data.dataPoints[i];
64423 enumeration.pushInstance({
64424 objectName: 'dataPoint',
64425 displayName: seriesDataPoints.formattedCategory.getValue(),
64426 selector: visuals.ColorHelper.normalizeSelector(seriesDataPoints.identity.getSelector(), /*isSingleSeries*/ true),
64427 properties: {
64428 fill: { solid: { color: seriesDataPoints.fill } }
64429 },
64430 });
64431 }
64432 }
64433 else {
64434 var legendDataPointLength = data.legendData.dataPoints.length;
64435 for (var i = 0; i < legendDataPointLength; i++) {
64436 var series = data.legendData.dataPoints[i];
64437 enumeration.pushInstance({
64438 objectName: 'dataPoint',
64439 displayName: series.label,
64440 selector: visuals.ColorHelper.normalizeSelector(series.identity.getSelector()),
64441 properties: {
64442 fill: { solid: { color: series.color } }
64443 },
64444 });
64445 }
64446 }
64447 };
64448 ScatterChart.prototype.supportsTrendLine = function () {
64449 var data = this.data;
64450 if (!data)
64451 return false;
64452 return !this.hasSizeMeasure() && data.dataPointSeries.length > 0;
64453 };
64454 ScatterChart.getExtents = function (data) {
64455 var dps = data.dataPoints;
64456 if (_.isEmpty(dps)) {
64457 return {
64458 minY: 0,
64459 maxY: 0,
64460 minX: 0,
64461 maxX: 0,
64462 };
64463 }
64464 return {
64465 minY: d3.min(dps, function (d) { return d.y; }),
64466 maxY: d3.max(dps, function (d) { return d.y; }),
64467 minX: d3.min(dps, function (d) { return d.x; }),
64468 maxX: d3.max(dps, function (d) { return d.x; }),
64469 };
64470 };
64471 ScatterChart.prototype.calculateAxesProperties = function (options) {
64472 var data = this.data;
64473 var viewport = this.currentViewport = options.viewport;
64474 var margin = options.margin;
64475 this.currentViewport = viewport;
64476 this.margin = margin;
64477 var width = viewport.width - (margin.left + margin.right);
64478 var height = viewport.height - (margin.top + margin.bottom);
64479 var extents = {
64480 minY: 0,
64481 maxY: 10,
64482 minX: 0,
64483 maxX: 10
64484 };
64485 if (this.playAxis) {
64486 extents = this.playAxis.getCartesianExtents(extents, ScatterChart.getExtents);
64487 this.playAxis.setPlayControlPosition(options.playAxisControlLayout);
64488 }
64489 else if (!_.isEmpty(data.dataPoints)) {
64490 extents = ScatterChart.getExtents(data);
64491 }
64492 var xDomain = [extents.minX, extents.maxX];
64493 var combinedXDomain = visuals.AxisHelper.combineDomain(options.forcedXDomain, xDomain, options.ensureXDomain);
64494 this.xAxisProperties = visuals.AxisHelper.createAxis({
64495 pixelSpan: width,
64496 dataDomain: combinedXDomain,
64497 metaDataColumn: data.xCol,
64498 formatString: visuals.valueFormatter.getFormatString(data.xCol, visuals.scatterChartProps.general.formatString),
64499 outerPadding: 0,
64500 isScalar: true,
64501 isVertical: false,
64502 forcedTickCount: options.forcedTickCount,
64503 useTickIntervalForDisplayUnits: true,
64504 isCategoryAxis: true,
64505 scaleType: options.categoryAxisScaleType,
64506 axisDisplayUnits: options.categoryAxisDisplayUnits,
64507 axisPrecision: options.categoryAxisPrecision
64508 });
64509 this.xAxisProperties.axis.tickSize(-height, 0);
64510 this.xAxisProperties.axisLabel = this.data.axesLabels.x;
64511 var combinedDomain = visuals.AxisHelper.combineDomain(options.forcedYDomain, [extents.minY, extents.maxY], options.ensureYDomain);
64512 this.yAxisProperties = visuals.AxisHelper.createAxis({
64513 pixelSpan: height,
64514 dataDomain: combinedDomain,
64515 metaDataColumn: data.yCol,
64516 formatString: visuals.valueFormatter.getFormatString(data.yCol, visuals.scatterChartProps.general.formatString),
64517 outerPadding: 0,
64518 isScalar: true,
64519 isVertical: true,
64520 forcedTickCount: options.forcedTickCount,
64521 useTickIntervalForDisplayUnits: true,
64522 isCategoryAxis: false,
64523 scaleType: options.valueAxisScaleType,
64524 axisDisplayUnits: options.valueAxisDisplayUnits,
64525 axisPrecision: options.valueAxisPrecision
64526 });
64527 this.yAxisProperties.axisLabel = this.data.axesLabels.y;
64528 // TODO: these should be passed into the render method.
64529 return [this.xAxisProperties, this.yAxisProperties];
64530 };
64531 ScatterChart.prototype.overrideXScale = function (xProperties) {
64532 this.xAxisProperties = xProperties;
64533 };
64534 ScatterChart.prototype.render = function (suppressAnimations, resizeMode) {
64535 if (!this.data)
64536 return;
64537 var data = this.data;
64538 var margin = this.margin;
64539 var viewport = this.currentViewport;
64540 var hasSelection = this.interactivityService && this.interactivityService.hasSelection();
64541 var plotArea = {
64542 width: viewport.width - (margin.left + margin.right),
64543 height: viewport.height - (margin.top + margin.bottom)
64544 };
64545 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
64546 if (this.playAxis && this.playAxis.isCurrentlyPlaying() && (this.isMobileChart || duration > 0)) {
64547 duration = visuals.PlayChart.FrameAnimationDuration;
64548 }
64549 var easeType = this.playAxis ? 'linear' : 'cubic-in-out'; // cubic-in-out is the d3.ease default
64550 var fillMarkers = (!data.sizeRange || !data.sizeRange.min) && data.fillPoint;
64551 var drawBubbles = this.hasSizeMeasure();
64552 var suppressDataPointRendering = resizeMode === 1 /* Resizing */ && data.dataPoints && data.dataPoints.length > ScatterChart.NoRenderResizeThreshold;
64553 var viewModel = {
64554 data: data,
64555 drawBubbles: drawBubbles,
64556 isPlay: !!this.playAxis,
64557 xAxisProperties: this.xAxisProperties,
64558 yAxisProperties: this.yAxisProperties,
64559 viewport: plotArea,
64560 hasSelection: hasSelection,
64561 animationDuration: duration,
64562 animationOptions: this.options.animation,
64563 fillMarkers: fillMarkers,
64564 easeType: easeType,
64565 suppressDataPointRendering: suppressDataPointRendering,
64566 };
64567 if (drawBubbles) {
64568 // Bubbles must be drawn from largest to smallest.
64569 var sortedData = data.dataPoints.sort(ScatterChart.sortBubbles);
64570 viewModel.data = powerbi.Prototype.inherit(viewModel.data);
64571 viewModel.data.dataPoints = sortedData;
64572 }
64573 var labelDataPoints = [];
64574 if (data.dataLabelsSettings && data.dataLabelsSettings.show || data.dataLabelsSettings.showCategory) {
64575 labelDataPoints = ScatterChartDataLabels.createLabelDataPoints(viewModel);
64576 }
64577 var behaviorOptions = this.renderer.render(viewModel, this.interactivityService);
64578 if (this.isMobileChart) {
64579 behaviorOptions = {
64580 data: behaviorOptions.data,
64581 dataPointsSelection: behaviorOptions.dataPointsSelection,
64582 eventGroup: behaviorOptions.eventGroup,
64583 plotContext: behaviorOptions.plotContext,
64584 host: this.cartesianVisualHost,
64585 root: this.svg,
64586 visualInitOptions: this.options,
64587 xAxisProperties: this.xAxisProperties,
64588 yAxisProperties: this.yAxisProperties,
64589 background: d3.select(this.element.get(0)),
64590 };
64591 }
64592 var playRenderResult;
64593 if (this.playAxis) {
64594 playRenderResult = this.playAxis.render(suppressAnimations, viewModel, viewport, margin);
64595 if (this.interactivityService) {
64596 var playBehaviorOptions = {
64597 traceLineRenderer: this.renderer.createTraceLineRenderer(playRenderResult.viewModel),
64598 };
64599 if (hasSelection) {
64600 visuals.PlayChart.renderTraceLines(playRenderResult.allDataPoints, playBehaviorOptions.traceLineRenderer, !suppressAnimations);
64601 }
64602 behaviorOptions.playOptions = playBehaviorOptions;
64603 }
64604 }
64605 return {
64606 dataPoints: playRenderResult ? playRenderResult.allDataPoints : data.dataPoints,
64607 behaviorOptions: behaviorOptions,
64608 labelDataPoints: labelDataPoints,
64609 labelsAreNumeric: false,
64610 };
64611 };
64612 ScatterChart.getStrokeFill = function (d, colorBorder) {
64613 if (d.size != null && colorBorder) {
64614 var colorRgb = Color.parseColorString(d.fill);
64615 return Color.hexString(Color.darken(colorRgb, ScatterChart.StrokeDarkenColorValue));
64616 }
64617 return d.fill;
64618 };
64619 ScatterChart.getBubblePixelAreaSizeRange = function (viewPort, minSizeRange, maxSizeRange) {
64620 var ratio = 1.0;
64621 if (viewPort.height > 0 && viewPort.width > 0) {
64622 var minSize = Math.min(viewPort.height, viewPort.width);
64623 ratio = (minSize * minSize) / ScatterChart.AreaOf300By300Chart;
64624 }
64625 var minRange = Math.round(minSizeRange * ratio);
64626 var maxRange = Math.round(maxSizeRange * ratio);
64627 return {
64628 minRange: minRange,
64629 maxRange: maxRange,
64630 delta: maxRange - minRange
64631 };
64632 };
64633 ScatterChart.project = function (value, actualSizeDataRange, bubblePixelAreaSizeRange) {
64634 if (actualSizeDataRange.delta === 0 || bubblePixelAreaSizeRange.delta === 0) {
64635 return (ScatterChart.rangeContains(actualSizeDataRange, value)) ? bubblePixelAreaSizeRange.minRange : null;
64636 }
64637 var relativeX = (value - actualSizeDataRange.minRange) / actualSizeDataRange.delta;
64638 return bubblePixelAreaSizeRange.minRange + relativeX * bubblePixelAreaSizeRange.delta;
64639 };
64640 ScatterChart.projectSizeToPixels = function (size, actualSizeDataRange, bubblePixelAreaSizeRange) {
64641 var projectedSize = 0;
64642 if (actualSizeDataRange) {
64643 // Project value on the required range of bubble area sizes
64644 projectedSize = bubblePixelAreaSizeRange.maxRange;
64645 if (actualSizeDataRange.delta !== 0) {
64646 var value = Math.min(Math.max(size, actualSizeDataRange.minRange), actualSizeDataRange.maxRange);
64647 projectedSize = ScatterChart.project(value, actualSizeDataRange, bubblePixelAreaSizeRange);
64648 }
64649 projectedSize = Math.sqrt(projectedSize / Math.PI) * 2;
64650 }
64651 return Math.round(projectedSize);
64652 };
64653 ScatterChart.rangeContains = function (range, value) {
64654 return range.minRange <= value && value <= range.maxRange;
64655 };
64656 ScatterChart.getMarkerFillOpacity = function (hasSize, shouldEnableFill, hasSelection, isSelected) {
64657 if (hasSize || shouldEnableFill) {
64658 if (hasSelection && !isSelected) {
64659 return ScatterChart.DimmedBubbleOpacity;
64660 }
64661 return ScatterChart.DefaultBubbleOpacity;
64662 }
64663 else {
64664 return 0;
64665 }
64666 };
64667 ScatterChart.getMarkerStrokeOpacity = function (hasSize, colorBorder, hasSelection, isSelected) {
64668 if (hasSize && colorBorder) {
64669 return 1;
64670 }
64671 else {
64672 if (hasSelection && !isSelected) {
64673 return ScatterChart.DimmedBubbleOpacity;
64674 }
64675 return ScatterChart.DefaultBubbleOpacity;
64676 }
64677 };
64678 ScatterChart.getMarkerStrokeFill = function (hasSize, colorBorder, fill) {
64679 if (hasSize && colorBorder) {
64680 var colorRgb = Color.parseColorString(fill);
64681 return Color.hexString(Color.darken(colorRgb, ScatterChart.StrokeDarkenColorValue));
64682 }
64683 return fill;
64684 };
64685 ScatterChart.getMarkerStyle = function (d, colorBorder, hasSelection, fillMarkers) {
64686 return {
64687 'stroke-opacity': ScatterChart.getMarkerStrokeOpacity(d.size != null, colorBorder, hasSelection, d.selected),
64688 stroke: ScatterChart.getMarkerStrokeFill(d.size != null, colorBorder, d.fill),
64689 fill: d.fill,
64690 'fill-opacity': ScatterChart.getMarkerFillOpacity(d.size != null, fillMarkers, hasSelection, d.selected),
64691 };
64692 };
64693 ScatterChart.getSeriesStyle = function (hasSize, colorBorder, hasSelection, fillMarkers, fill) {
64694 return {
64695 'stroke-opacity': ScatterChart.getMarkerStrokeOpacity(hasSize, colorBorder, hasSelection, false),
64696 stroke: ScatterChart.getMarkerStrokeFill(hasSize, colorBorder, fill),
64697 fill: fill,
64698 'fill-opacity': ScatterChart.getMarkerFillOpacity(hasSize, fillMarkers, hasSelection, false),
64699 };
64700 };
64701 ScatterChart.getBubbleOpacity = function (d, hasSelection) {
64702 if (hasSelection && !d.selected) {
64703 return ScatterChart.DimmedBubbleOpacity;
64704 }
64705 return ScatterChart.DefaultBubbleOpacity;
64706 };
64707 ScatterChart.prototype.onClearSelection = function () {
64708 if (this.interactivityService)
64709 this.interactivityService.clearSelection();
64710 };
64711 ScatterChart.prototype.getSupportedCategoryAxisType = function () {
64712 return visuals.axisType.scalar;
64713 };
64714 ScatterChart.sortBubbles = function (a, b) {
64715 var diff = (b.radius.sizeMeasure.values[b.radius.index] - a.radius.sizeMeasure.values[a.radius.index]);
64716 if (diff !== 0)
64717 return diff;
64718 // Tie-break equal size bubbles using identity.
64719 return b.identity.getKey().localeCompare(a.identity.getKey());
64720 };
64721 ScatterChart.BubbleRadius = 3 * 2;
64722 ScatterChart.DefaultBubbleOpacity = 0.85;
64723 ScatterChart.DimmedBubbleOpacity = 0.4;
64724 ScatterChart.StrokeDarkenColorValue = 255 * 0.25;
64725 //label layout settings
64726 ScatterChart.dataLabelLayoutStartingOffset = 2;
64727 ScatterChart.dataLabelLayoutOffsetIterationDelta = 6;
64728 ScatterChart.dataLabelLayoutMaximumOffset = ScatterChart.dataLabelLayoutStartingOffset + (2 * ScatterChart.dataLabelLayoutOffsetIterationDelta);
64729 // Chart Area and size range values as defined by PV charts
64730 ScatterChart.AreaOf300By300Chart = 90000;
64731 ScatterChart.MinSizeRange = 200;
64732 ScatterChart.MaxSizeRange = 3000;
64733 ScatterChart.ClassName = 'scatterChart';
64734 // Animated rendering threshold - if more than this number of data points, rendering is grouped by series and not animated
64735 ScatterChart.NoAnimationThreshold = 1000;
64736 // No render resize threshold - if more than this number of data points, rendering is suppressed during resize
64737 ScatterChart.NoRenderResizeThreshold = 1000;
64738 return ScatterChart;
64739 }());
64740 visuals.ScatterChart = ScatterChart;
64741 var SvgRenderer = (function () {
64742 function SvgRenderer() {
64743 }
64744 SvgRenderer.prototype.init = function (element, labelsContext, isMobileChart, tooltipsEnabled) {
64745 this.mainGraphicsG = element.append('g')
64746 .classed(SvgRenderer.MainGraphicsContext.class, true);
64747 this.isMobileChart = isMobileChart;
64748 if (isMobileChart) {
64749 // The backgroundRect catch user interactions when clicking/dragging on the background of the chart.
64750 this.mainGraphicsBackgroundRect = this.mainGraphicsG
64751 .append("rect")
64752 .classed("backgroundRect", true)
64753 .attr({ width: "100%", height: "100%" });
64754 }
64755 this.mainGraphicsContext = this.mainGraphicsG.append('svg');
64756 this.labelGraphicsContext = labelsContext;
64757 this.tooltipsEnabled = tooltipsEnabled;
64758 // common rendering attributes
64759 this.mainGraphicsContext.attr('stroke-width', "1");
64760 };
64761 SvgRenderer.prototype.render = function (viewModel, interactivityService) {
64762 var viewport = viewModel.viewport;
64763 this.mainGraphicsContext
64764 .attr({
64765 'width': viewport.width,
64766 'height': viewport.height
64767 });
64768 var scatterMarkers;
64769 if (viewModel.suppressDataPointRendering) {
64770 scatterMarkers = this.removeScatterMarkers();
64771 }
64772 else if (viewModel.animationDuration > 0 && viewModel.data.dataPoints.length <= ScatterChart.NoAnimationThreshold) {
64773 scatterMarkers = this.drawScatterMarkers(viewModel);
64774 }
64775 else {
64776 scatterMarkers = this.drawScatterMarkersNoAnimation(viewModel, viewModel.drawBubbles);
64777 }
64778 if (viewModel.drawBubbles)
64779 scatterMarkers.order();
64780 if (this.tooltipsEnabled) {
64781 visuals.TooltipManager.addTooltip(this.mainGraphicsContext, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
64782 }
64783 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(viewModel.animationOptions);
64784 return {
64785 dataPointsSelection: scatterMarkers,
64786 eventGroup: this.mainGraphicsG,
64787 data: viewModel.data,
64788 plotContext: this.mainGraphicsContext,
64789 };
64790 };
64791 SvgRenderer.prototype.createTraceLineRenderer = function (viewModel) {
64792 return new ScatterTraceLineRenderer(viewModel, this.mainGraphicsContext, this.tooltipsEnabled);
64793 };
64794 SvgRenderer.prototype.removeScatterMarkers = function () {
64795 this.mainGraphicsContext.selectAll(SvgRenderer.ScatterMarkerSeriesGroup.selector)
64796 .remove();
64797 return this.mainGraphicsContext.selectAll(SvgRenderer.DotClass.selector);
64798 };
64799 SvgRenderer.prototype.drawScatterMarkers = function (viewModel) {
64800 var data = viewModel.data;
64801 var xScale = viewModel.xAxisProperties.scale;
64802 var yScale = viewModel.yAxisProperties.scale;
64803 // put all the markers in a single fake group. keeps the dom structure consistent between
64804 // drawScatterMarkers and drawScatterMarkersGrouped.
64805 var fakeDataPointSeries = [
64806 {
64807 identityKey: "",
64808 dataPoints: data.dataPoints,
64809 },
64810 ];
64811 var fakeSeriesGroups = this.mainGraphicsContext.selectAll(SvgRenderer.ScatterMarkerSeriesGroup.selector)
64812 .data(fakeDataPointSeries, function (s) { return s.identityKey; });
64813 fakeSeriesGroups.enter()
64814 .append('g')
64815 .classed(SvgRenderer.ScatterMarkerSeriesGroup.class, true);
64816 // groups for real series may have been inserted by drawScatterMarkersGrouped, remove them
64817 fakeSeriesGroups.exit()
64818 .remove();
64819 var markers = fakeSeriesGroups.selectAll(SvgRenderer.DotClass.selector)
64820 .data(function (s) { return s.dataPoints; }, function (d) { return d.identity.getKey(); });
64821 markers.enter().append('circle')
64822 .classed(SvgRenderer.DotClass.class, true)
64823 .style('opacity', 0) // Fade new bubbles into visibility
64824 .attr('r', 0);
64825 markers
64826 .style({
64827 'stroke-opacity': function (d) { return ScatterChart.getMarkerStrokeOpacity(d.size != null, data.colorBorder, viewModel.hasSelection, d.selected); },
64828 'stroke': function (d) { return ScatterChart.getStrokeFill(d, data.colorBorder); },
64829 'fill': function (d) { return d.fill; },
64830 'fill-opacity': function (d) { return ScatterChart.getMarkerFillOpacity(d.size != null, viewModel.fillMarkers, viewModel.hasSelection, d.selected); },
64831 })
64832 .transition()
64833 .ease(viewModel.easeType)
64834 .duration(viewModel.animationDuration)
64835 .style('opacity', 1) // Fill-opacity is used for selected / highlight changes, opacity is for enter/exit fadein/fadeout
64836 .attr({
64837 r: function (d) { return ScatterChart.getBubbleRadius(d.radius, data.sizeRange, viewModel.viewport); },
64838 cx: function (d) { return xScale(d.x); },
64839 cy: function (d) { return yScale(d.y); },
64840 });
64841 markers
64842 .exit()
64843 .transition()
64844 .ease(viewModel.easeType)
64845 .duration(viewModel.animationDuration)
64846 .style('opacity', 0) // Fade out bubbles that are removed
64847 .attr('r', 0)
64848 .remove();
64849 return markers;
64850 };
64851 SvgRenderer.prototype.drawScatterMarkersNoAnimation = function (viewModel, isBubble) {
64852 var data = viewModel.data;
64853 var xScale = viewModel.xAxisProperties.scale;
64854 var yScale = viewModel.yAxisProperties.scale;
64855 var seriesGroups;
64856 if (isBubble) {
64857 var fakeDataPointSeries = [
64858 {
64859 identityKey: "",
64860 dataPoints: data.dataPoints,
64861 },
64862 ];
64863 seriesGroups = this.mainGraphicsContext.selectAll(SvgRenderer.ScatterMarkerSeriesGroup.selector)
64864 .data(fakeDataPointSeries, function (s) { return s.identityKey; });
64865 }
64866 else {
64867 seriesGroups = this.mainGraphicsContext.selectAll(SvgRenderer.ScatterMarkerSeriesGroup.selector).data(data.dataPointSeries, function (s) { return s.identityKey; });
64868 }
64869 // a group for each series
64870 seriesGroups.enter()
64871 .append('g')
64872 .classed(SvgRenderer.ScatterMarkerSeriesGroup.class, true);
64873 // this will also remove the fake group that might have been created by drawScatterMarkers
64874 seriesGroups.exit()
64875 .remove();
64876 seriesGroups
64877 .each(function (s) {
64878 var seriesStyle = ScatterChart.getSeriesStyle(s.hasSize, data.colorBorder, viewModel.hasSelection, viewModel.fillMarkers, s.fill);
64879 var g = d3.select(this);
64880 SvgRenderer.applyStyle(this, seriesStyle);
64881 var markers = g.selectAll(SvgRenderer.DotClass.selector).data(s.dataPoints, function (m) { return m.identity.getKey(); });
64882 markers.enter()
64883 .append('circle')
64884 .classed(SvgRenderer.DotClass.class, true);
64885 markers.exit()
64886 .remove();
64887 markers.each(function (d) {
64888 var style = ScatterChart.getMarkerStyle(d, data.colorBorder, viewModel.hasSelection, viewModel.fillMarkers);
64889 SvgRenderer.styleException(style, seriesStyle);
64890 SvgRenderer.applyStyle(this, style);
64891 });
64892 markers.attr({
64893 r: function (d) { return ScatterChart.getBubbleRadius(d.radius, data.sizeRange, viewModel.viewport); },
64894 cx: function (d) { return xScale(d.x); },
64895 cy: function (d) { return yScale(d.y); },
64896 });
64897 });
64898 return this.mainGraphicsContext.selectAll(SvgRenderer.DotClass.selector);
64899 };
64900 SvgRenderer.styleException = function (elementStyle, seriesStyle) {
64901 if (seriesStyle) {
64902 for (var name_1 in elementStyle) {
64903 if (elementStyle[name_1] === seriesStyle[name_1]) {
64904 elementStyle[name_1] = null;
64905 }
64906 }
64907 }
64908 };
64909 SvgRenderer.applyStyle = function (element, style) {
64910 for (var name_2 in style) {
64911 var elementValue = element.style[name_2];
64912 var styleValue = style[name_2];
64913 if (styleValue == null) {
64914 if (elementValue === "")
64915 continue;
64916 }
64917 else {
64918 styleValue = styleValue.toString();
64919 if (styleValue === elementValue)
64920 continue;
64921 }
64922 element.style[name_2] = styleValue;
64923 }
64924 };
64925 SvgRenderer.DotClass = createClassAndSelector('dot');
64926 SvgRenderer.MainGraphicsContext = createClassAndSelector('mainGraphicsContext');
64927 SvgRenderer.ScatterMarkerSeriesGroup = createClassAndSelector('scatterMarkerSeriesGroup');
64928 return SvgRenderer;
64929 }());
64930 var ScatterChartDataLabels;
64931 (function (ScatterChartDataLabels) {
64932 var validLabelPositions = [
64933 2 /* Below */,
64934 1 /* Above */,
64935 8 /* Right */,
64936 4 /* Left */,
64937 16 /* BelowRight */,
64938 32 /* BelowLeft */,
64939 64 /* AboveRight */,
64940 128 /* AboveLeft */
64941 ];
64942 function createLabelDataPoints(viewModel) {
64943 var xScale = viewModel.xAxisProperties.scale;
64944 var yScale = viewModel.yAxisProperties.scale;
64945 var sizeRange = viewModel.data.sizeRange;
64946 var labelDataPoints = [];
64947 var dataPoints = viewModel.data.dataPoints;
64948 var labelSettings = viewModel.data.dataLabelsSettings;
64949 var preferredLabelsKeys = getPreferredLabelsKeys(viewModel);
64950 for (var _i = 0, dataPoints_5 = dataPoints; _i < dataPoints_5.length; _i++) {
64951 var dataPoint = dataPoints_5[_i];
64952 var text = dataPoint.formattedCategory.getValue();
64953 var properties = {
64954 text: text,
64955 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
64956 fontSize: PixelConverter.fromPoint(labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt),
64957 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
64958 };
64959 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
64960 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties);
64961 labelDataPoints.push({
64962 isPreferred: preferredLabelsKeys ? isLabelPreferred(dataPoint.identity.getKey(), preferredLabelsKeys) : false,
64963 text: text,
64964 textSize: {
64965 width: textWidth,
64966 height: textHeight,
64967 },
64968 outsideFill: labelSettings.labelColor ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultLabelColor,
64969 insideFill: visuals.NewDataLabelUtils.defaultInsideLabelColor,
64970 parentType: 0 /* Point */,
64971 parentShape: {
64972 point: {
64973 x: xScale(dataPoint.x),
64974 y: yScale(dataPoint.y),
64975 },
64976 radius: ScatterChart.getBubbleRadius(dataPoint.radius, sizeRange, viewModel.viewport),
64977 validPositions: validLabelPositions,
64978 },
64979 identity: dataPoint.identity,
64980 fontSize: labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt,
64981 });
64982 }
64983 return labelDataPoints;
64984 }
64985 ScatterChartDataLabels.createLabelDataPoints = createLabelDataPoints;
64986 function getPreferredLabelsKeys(viewModel) {
64987 var width = viewModel.viewport.width;
64988 var height = viewModel.viewport.height;
64989 var visualCenter = new visuals.Point(width / 2, height / 2);
64990 var quadrantsCenters = getQuadrantsCenters(width, height);
64991 return getCandidateLabels(visualCenter, quadrantsCenters, viewModel);
64992 }
64993 function getQuadrantsCenters(visualWidth, visualHeight) {
64994 var quadrantsCenters = [];
64995 var quarterWidth = visualWidth / 4;
64996 var quarterHeight = visualHeight / 4;
64997 quadrantsCenters.push(new visuals.Point(quarterWidth, quarterHeight));
64998 quadrantsCenters.push(new visuals.Point(quarterWidth * 3, quarterHeight));
64999 quadrantsCenters.push(new visuals.Point(quarterWidth, quarterHeight * 3));
65000 quadrantsCenters.push(new visuals.Point(quarterWidth * 3, quarterHeight * 3));
65001 return quadrantsCenters;
65002 }
65003 function getCandidateLabels(visualCenter, quadrantsCenters, viewModel) {
65004 var minDistances = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE];
65005 var ids = [];
65006 var xScale = viewModel.xAxisProperties.scale;
65007 var yScale = viewModel.yAxisProperties.scale;
65008 var distance;
65009 for (var _i = 0, _a = viewModel.data.dataPoints; _i < _a.length; _i++) {
65010 var dp = _a[_i];
65011 var x = xScale(dp.x);
65012 var y = yScale(dp.y);
65013 var quadrantNumber = getPointQuadrantNumber(x, y, visualCenter);
65014 if (viewModel.drawBubbles) {
65015 // Since the array is sorted by size the preferred label will be the first label in the quadrant
65016 if (!ids[quadrantNumber])
65017 ids[quadrantNumber] = dp.identity;
65018 }
65019 else {
65020 distance = getDistanceBetweenPoints(quadrantsCenters[quadrantNumber].x, quadrantsCenters[quadrantNumber].y, x, y);
65021 if (distance < minDistances[quadrantNumber]) {
65022 ids[quadrantNumber] = dp.identity;
65023 minDistances[quadrantNumber] = distance;
65024 }
65025 }
65026 }
65027 var preferredLabelsKeys = [];
65028 for (var _b = 0, ids_1 = ids; _b < ids_1.length; _b++) {
65029 var id = ids_1[_b];
65030 if (id)
65031 preferredLabelsKeys.push(id.getKey());
65032 }
65033 return preferredLabelsKeys;
65034 }
65035 function getPointQuadrantNumber(x, y, centerPoint) {
65036 if (x > centerPoint.x && y <= centerPoint.y)
65037 return 0 /* First */;
65038 if (x <= centerPoint.x && y <= centerPoint.y)
65039 return 1 /* Second */;
65040 if (x <= centerPoint.x && y > centerPoint.y)
65041 return 2 /* Third */;
65042 else
65043 return 3 /* Fourth */;
65044 }
65045 function getDistanceBetweenPoints(x1, y1, x2, y2) {
65046 return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
65047 }
65048 function isLabelPreferred(key, preferredLabelsKeys) {
65049 for (var _i = 0, preferredLabelsKeys_1 = preferredLabelsKeys; _i < preferredLabelsKeys_1.length; _i++) {
65050 var preferredLabel = preferredLabelsKeys_1[_i];
65051 if (key.localeCompare(preferredLabel) === 0)
65052 return true;
65053 }
65054 return false;
65055 }
65056 })(ScatterChartDataLabels || (ScatterChartDataLabels = {}));
65057 var ScatterTraceLineRenderer = (function () {
65058 function ScatterTraceLineRenderer(viewModel, element, tooltipsEnabled) {
65059 this.viewModel = viewModel;
65060 this.element = element;
65061 this.tooltipsEnabled = tooltipsEnabled;
65062 }
65063 ScatterTraceLineRenderer.prototype.remove = function () {
65064 this.element.selectAll(ScatterTraceLineRenderer.TraceLine.selector).remove();
65065 this.element.selectAll(ScatterTraceLineRenderer.TraceBubble.selector).remove();
65066 };
65067 ScatterTraceLineRenderer.prototype.render = function (selectedPoints, shouldAnimate) {
65068 var viewModel = this.viewModel;
65069 var scatterViewModel = viewModel.viewModel;
65070 var seriesPoints = [];
65071 if (!_.isEmpty(selectedPoints) && !scatterViewModel.suppressDataPointRendering) {
65072 var currentFrameIndex_1 = viewModel.data.currentFrameIndex;
65073 // filter to the selected identity, only up to and including the current frame. Add frames during play.
65074 var hasBubbleAtCurrentFrame = [];
65075 for (var selectedIndex = 0, selectedLen = selectedPoints.length; selectedIndex < selectedLen; selectedIndex++) {
65076 seriesPoints[selectedIndex] = [];
65077 hasBubbleAtCurrentFrame[selectedIndex] = false;
65078 for (var frameIndex = 0, frameLen = viewModel.data.allViewModels.length; frameIndex < frameLen && frameIndex <= currentFrameIndex_1; frameIndex++) {
65079 var value = _.find(viewModel.data.allViewModels[frameIndex].dataPoints, function (value, index) {
65080 return value.identity.getKey() === selectedPoints[selectedIndex].identity.getKey();
65081 });
65082 if (value != null) {
65083 // TODO: Revisit this, we should be able to keep track without modifying Scatter's data points.
65084 value.frameIndex = frameIndex;
65085 seriesPoints[selectedIndex].push(value);
65086 if (frameIndex === currentFrameIndex_1)
65087 hasBubbleAtCurrentFrame[selectedIndex] = true;
65088 }
65089 }
65090 }
65091 var xScale_1 = scatterViewModel.xAxisProperties.scale;
65092 var yScale_1 = scatterViewModel.yAxisProperties.scale;
65093 var line_1 = d3.svg.line()
65094 .x(function (d) { return xScale_1(d.x); })
65095 .y(function (d) { return yScale_1(d.y); })
65096 .defined(function (d) { return d.x !== null && d.y !== null; });
65097 // Render Lines
65098 var traceLines = this.element.selectAll(ScatterTraceLineRenderer.TraceLine.selector)
65099 .data(selectedPoints, function (sp) { return sp.identity.getKey(); });
65100 traceLines.enter()
65101 .append('path')
65102 .classed(ScatterTraceLineRenderer.TraceLine.class, true);
65103 // prepare array of new/previous lengths
65104 // NOTE: can't use lambda because we need the "this" context to be the DOM Element associated with the .each()
65105 var previousLengths_1 = [], newLengths_1 = [];
65106 var reverse_1 = false;
65107 traceLines.each(function (d, i) {
65108 var existingPath = this;
65109 var previousLength = existingPath.hasAttribute('d') ? existingPath.getTotalLength() : 0;
65110 previousLengths_1.push(previousLength);
65111 // create offline SVG for new path measurement
65112 var tempSvgPath = $('<svg><path></path></svg>');
65113 var tempPath = $('path', tempSvgPath);
65114 tempPath.attr('d', line_1(seriesPoints[i]));
65115 var newLength = seriesPoints[i].length > 0 ? tempPath.get()[0].getTotalLength() : 0;
65116 newLengths_1.push(newLength);
65117 reverse_1 = reverse_1 || (newLength < previousLength);
65118 });
65119 // animate using stroke-dash* trick
65120 if (!reverse_1) {
65121 // growing line
65122 traceLines
65123 .style('stroke', function (d) { return ScatterChart.getStrokeFill(d, true); })
65124 .attr({
65125 'd': function (d, i) {
65126 return line_1(seriesPoints[i]);
65127 },
65128 'stroke-dasharray': function (d, i) { return newLengths_1[i] + " " + newLengths_1[i]; },
65129 'stroke-dashoffset': function (d, i) { return newLengths_1[i] - previousLengths_1[i]; },
65130 });
65131 if (shouldAnimate) {
65132 traceLines
65133 .transition()
65134 .ease('linear')
65135 .duration(visuals.PlayChart.FrameAnimationDuration)
65136 .attr('stroke-dashoffset', 0);
65137 }
65138 else {
65139 traceLines.attr('stroke-dashoffset', 0);
65140 }
65141 }
65142 else {
65143 // shrinking line
65144 if (shouldAnimate) {
65145 traceLines
65146 .transition()
65147 .ease('linear')
65148 .duration(visuals.PlayChart.FrameAnimationDuration)
65149 .attr('stroke-dashoffset', function (d, i) { return previousLengths_1[i] - newLengths_1[i]; })
65150 .transition()
65151 .ease('linear')
65152 .duration(1) // animate the shrink first, then update with new line properties
65153 .delay(visuals.PlayChart.FrameAnimationDuration)
65154 .style('stroke', function (d) { return ScatterChart.getStrokeFill(d, true); })
65155 .attr({
65156 'd': function (d, i) {
65157 return line_1(seriesPoints[i]);
65158 },
65159 'stroke-dasharray': function (d, i) { return newLengths_1[i] + " " + newLengths_1[i]; },
65160 'stroke-dashoffset': 0,
65161 });
65162 }
65163 else {
65164 traceLines
65165 .style('stroke', function (d) { return ScatterChart.getStrokeFill(d, true); })
65166 .attr({
65167 'd': function (d, i) {
65168 return line_1(seriesPoints[i]);
65169 },
65170 'stroke-dasharray': function (d, i) { return newLengths_1[i] + " " + newLengths_1[i]; },
65171 'stroke-dashoffset': 0,
65172 });
65173 }
65174 }
65175 traceLines.exit()
65176 .remove();
65177 // Render circles
65178 var circlePoints = [];
65179 for (var selectedIndex_1 = 0; selectedIndex_1 < seriesPoints.length; selectedIndex_1++) {
65180 var points = seriesPoints[selectedIndex_1];
65181 // slice to length-1 because we draw lines to the current bubble but we don't need to draw the current frame's bubble
65182 var newPoints = hasBubbleAtCurrentFrame[selectedIndex_1] ? points.slice(0, points.length - 1) : points;
65183 circlePoints = circlePoints.concat(newPoints);
65184 }
65185 var circles = this.element.selectAll(ScatterTraceLineRenderer.TraceBubble.selector)
65186 .data(circlePoints, function (d) { return d.identity.getKey() + d.x + d.y + d.size; });
65187 circles.enter()
65188 .append('circle')
65189 .style('opacity', 0) //fade new bubbles into visibility
65190 .classed(ScatterTraceLineRenderer.TraceBubble.class, true);
65191 circles
65192 .attr('cx', function (d) { return xScale_1(d.x); })
65193 .attr('cy', function (d) { return yScale_1(d.y); })
65194 .attr('r', function (d) { return ScatterChart.getBubbleRadius(d.radius, viewModel.data.currentViewModel.sizeRange, viewModel.viewport); })
65195 .style({
65196 'stroke-opacity': function (d) { return ScatterChart.getBubbleOpacity(d, true); },
65197 'stroke': function (d) { return ScatterChart.getStrokeFill(d, viewModel.data.currentViewModel.colorBorder); },
65198 'fill': function (d) { return d.fill; },
65199 // vary the opacity along the traceline from 0.20 to 0.80, with 0.85 left for the circle already drawn by scatterChart
65200 'fill-opacity': function (d) { return d.size != null ? 0.20 + (d.frameIndex / currentFrameIndex_1) * 0.60 : 0; },
65201 })
65202 .transition()
65203 .ease('linear')
65204 .duration(visuals.PlayChart.FrameAnimationDuration)
65205 .style('opacity', 1);
65206 circles.exit()
65207 .transition()
65208 .ease('linear')
65209 .duration(visuals.PlayChart.FrameAnimationDuration)
65210 .style('opacity', 0) // fade exiting bubbles out
65211 .remove();
65212 if (this.tooltipsEnabled) {
65213 visuals.TooltipManager.addTooltip(circles, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
65214 }
65215 // sort the z-order, smallest size on top
65216 circles.sort(function (d1, d2) { return d2.size - d1.size; });
65217 }
65218 else {
65219 this.remove();
65220 }
65221 };
65222 ScatterTraceLineRenderer.TraceLine = createClassAndSelector('traceLine');
65223 ScatterTraceLineRenderer.TraceBubble = createClassAndSelector('traceBubble');
65224 return ScatterTraceLineRenderer;
65225 }());
65226 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
65227})(powerbi || (powerbi = {}));
65228/*
65229 * Power BI Visualizations
65230 *
65231 * Copyright (c) Microsoft Corporation
65232 * All rights reserved.
65233 * MIT License
65234 *
65235 * Permission is hereby granted, free of charge, to any person obtaining a copy
65236 * of this software and associated documentation files (the ""Software""), to deal
65237 * in the Software without restriction, including without limitation the rights
65238 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
65239 * copies of the Software, and to permit persons to whom the Software is
65240 * furnished to do so, subject to the following conditions:
65241 *
65242 * The above copyright notice and this permission notice shall be included in
65243 * all copies or substantial portions of the Software.
65244 *
65245 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65246 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65247 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65248 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65249 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65250 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
65251 * THE SOFTWARE.
65252 */
65253var powerbi;
65254(function (powerbi) {
65255 var visuals;
65256 (function (visuals) {
65257 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
65258 var createDataViewScopeIdentity = powerbi.data.createDataViewScopeIdentity;
65259 var DataViewConcatenateCategoricalColumns = powerbi.data.DataViewConcatenateCategoricalColumns;
65260 var DataViewMatrixUtils = powerbi.data.utils.DataViewMatrixUtils;
65261 var SQExprBuilder = powerbi.data.SQExprBuilder;
65262 ;
65263 ;
65264 var PlayAxis = (function () {
65265 function PlayAxis(options) {
65266 if (options) {
65267 this.interactivityService = options.interactivityService;
65268 }
65269 }
65270 PlayAxis.prototype.init = function (options) {
65271 var _this = this;
65272 debug.assertValue(options, 'options');
65273 this.element = options.element;
65274 this.svg = options.svg;
65275 this.host = options.host;
65276 this.isMobileChart = options.interactivity && options.interactivity.isInteractiveLegend;
65277 if (this.interactivityService) {
65278 this.playControl = new PlayControl(this.element, function (frameIndex) { return _this.moveToFrameAndRender(frameIndex); }, this.isMobileChart);
65279 this.playControl.onPlay(function () { return _this.play(); });
65280 }
65281 };
65282 PlayAxis.prototype.setData = function (dataView, visualConverter) {
65283 if (dataView) {
65284 if (this.ridiculousFlagForPersistProperties && dataView.metadata) {
65285 // BUG FIX: customer feedback has been strong that we should always default to show the last frame.
65286 // This is essential for dashboard tiles to refresh properly.
65287 // Only copy frameIndex since it is the only property using persistProperties
65288 //let objectProps = getObjectProperties(dataView.metadata);
65289 //playData.currentFrameIndex = objectProps.currentFrameIndex;
65290 // Turn off the flag that was set by our persistProperties call
65291 this.ridiculousFlagForPersistProperties = false;
65292 return this.playData;
65293 }
65294 else if (dataView.matrix || dataView.categorical) {
65295 this.playData = PlayChart.converter(dataView, visualConverter);
65296 }
65297 else {
65298 this.playData = PlayChart.getDefaultPlayData();
65299 }
65300 }
65301 else {
65302 this.playData = PlayChart.getDefaultPlayData();
65303 }
65304 // Next render should be a full one.
65305 this.lastViewport = undefined;
65306 return this.playData;
65307 };
65308 PlayAxis.prototype.render = function (suppressAnimations, viewModel, viewport, margin) {
65309 var playData = this.playData;
65310 var resized = !this.lastViewport || (this.lastViewport.height !== viewport.height || this.lastViewport.width !== viewport.width);
65311 this.lastViewport = viewport;
65312 if (resized)
65313 this.stop();
65314 if (!playData)
65315 return;
65316 var playViewModel = {
65317 data: this.playData,
65318 viewModel: viewModel,
65319 viewport: viewport,
65320 };
65321 var hasSelection = false;
65322 if (this.interactivityService) {
65323 var data_5 = playData.currentViewModel;
65324 this.interactivityService.applySelectionStateToData(data_5.dataPoints);
65325 hasSelection = this.interactivityService.hasSelection();
65326 }
65327 this.updateCallout(viewport, margin);
65328 if (this.playControl && resized) {
65329 this.playControl.rebuild(playData, viewport);
65330 }
65331 var allDataPoints = playData.allViewModels.map(function (vm) { return vm.dataPoints; });
65332 var flatAllDataPoints = _.flatten(allDataPoints);
65333 // NOTE: Return data points to keep track of current selected bubble even if it drops out for a few frames
65334 return {
65335 allDataPoints: flatAllDataPoints,
65336 viewModel: playViewModel,
65337 };
65338 };
65339 PlayAxis.prototype.updateCallout = function (viewport, margin) {
65340 var playData = this.playData;
65341 var frameData = playData.frameData;
65342 var currentFrameIndex = playData.currentFrameIndex;
65343 var height = viewport.height;
65344 var plotAreaHeight = height - margin.top - margin.bottom;
65345 var width = viewport.width;
65346 var plotAreaWidth = width - margin.left - margin.right;
65347 var calloutDimension = Math.min(height, width * 1.3); //1.3 to compensate for tall, narrow-width viewport
65348 var fontSize = Math.max(12, Math.round(calloutDimension / 7));
65349 fontSize = Math.min(fontSize, 70);
65350 var textProperties = {
65351 fontSize: jsCommon.PixelConverter.toString(fontSize),
65352 text: frameData[currentFrameIndex].text || "",
65353 fontFamily: "wf_segoe-ui_normal",
65354 };
65355 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(textProperties) - powerbi.TextMeasurementService.estimateSvgTextBaselineDelta(textProperties);
65356 var calloutData = [];
65357 if (currentFrameIndex < frameData.length && currentFrameIndex >= 0 && textHeight < plotAreaHeight) {
65358 var maxTextWidth = plotAreaWidth - (2 * PlayAxis.calloutOffsetMultiplier * textHeight);
65359 var calloutText = powerbi.TextMeasurementService.getTailoredTextOrDefault(textProperties, maxTextWidth);
65360 calloutData = [calloutText];
65361 }
65362 var callout = this.svg.selectAll(PlayAxis.PlayCallout.selector).data(calloutData);
65363 callout.enter()
65364 .append('text')
65365 .classed(PlayAxis.PlayCallout.class, true);
65366 callout
65367 .text(function (d) { return d; })
65368 .attr({
65369 x: plotAreaWidth - PlayAxis.calloutOffsetMultiplier * textHeight,
65370 y: function () { return textHeight; },
65371 })
65372 .style({
65373 'font-size': fontSize + 'px',
65374 'text-anchor': 'end',
65375 });
65376 callout.exit().remove();
65377 };
65378 PlayAxis.prototype.play = function () {
65379 var playData = this.playData;
65380 if (this.isPlaying) {
65381 this.stop();
65382 }
65383 else if (this.playControl) {
65384 this.isPlaying = true;
65385 this.playControl.play();
65386 var indexToShow = Math.round(this.playControl.getCurrentIndex());
65387 if (indexToShow >= playData.allViewModels.length - 1) {
65388 playData.currentFrameIndex = -1;
65389 }
65390 else {
65391 playData.currentFrameIndex = indexToShow - 1;
65392 }
65393 this.playNextFrame(playData);
65394 }
65395 };
65396 PlayAxis.prototype.playNextFrame = function (playData, startFrame, endFrame) {
65397 var _this = this;
65398 if (!this.isPlaying) {
65399 this.stop();
65400 return;
65401 }
65402 var nextFrame = playData.currentFrameIndex + 1;
65403 if (startFrame != null && endFrame != null) {
65404 nextFrame = Math.abs(endFrame - startFrame + 1);
65405 startFrame = nextFrame;
65406 }
65407 if (nextFrame < playData.allViewModels.length && nextFrame > -1) {
65408 playData.currentFrameIndex = nextFrame;
65409 playData.currentViewModel = playData.allViewModels[nextFrame];
65410 this.renderDelegate(playData.currentViewModel);
65411 this.playControl.setFrame(nextFrame);
65412 if (nextFrame < playData.allViewModels.length) {
65413 window.setTimeout(function () {
65414 _this.playNextFrame(playData, startFrame, endFrame);
65415 }, PlayChart.FrameStepDuration);
65416 }
65417 }
65418 else {
65419 this.stop();
65420 }
65421 };
65422 PlayAxis.prototype.stop = function () {
65423 if (this.playControl)
65424 this.playControl.pause();
65425 this.isPlaying = false;
65426 };
65427 PlayAxis.prototype.remove = function () {
65428 if (this.playControl)
65429 this.playControl.remove();
65430 d3.selectAll(PlayAxis.PlayCallout.selector).remove();
65431 // TODO: remove any tracelines
65432 };
65433 PlayAxis.prototype.setRenderFunction = function (fn) {
65434 this.renderDelegate = fn;
65435 };
65436 PlayAxis.prototype.getCartesianExtents = function (existingExtents, getExtents) {
65437 if (this.playData && this.playData.allViewModels && this.playData.allViewModels.length > 0) {
65438 return PlayChart.getMinMaxForAllFrames(this.playData, getExtents);
65439 }
65440 return existingExtents;
65441 };
65442 PlayAxis.prototype.setPlayControlPosition = function (playControlLayout) {
65443 if (this.playControl) {
65444 var container = this.playControl.getContainer();
65445 container.css('left', playControlLayout.left ? playControlLayout.left + 'px' : '');
65446 container.css('top', playControlLayout.top ? playControlLayout.top + 'px' : '');
65447 }
65448 };
65449 PlayAxis.prototype.moveToFrameAndRender = function (frameIndex) {
65450 var playData = this.playData;
65451 this.isPlaying = false;
65452 if (playData && frameIndex >= 0 && frameIndex < playData.allViewModels.length && frameIndex !== playData.currentFrameIndex) {
65453 playData.currentFrameIndex = frameIndex;
65454 var data_6 = playData.allViewModels[frameIndex];
65455 playData.currentViewModel = data_6;
65456 this.renderDelegate(data_6);
65457 }
65458 };
65459 PlayAxis.prototype.isCurrentlyPlaying = function () {
65460 return this.isPlaying;
65461 };
65462 PlayAxis.PlayCallout = createClassAndSelector('play-callout');
65463 PlayAxis.calloutOffsetMultiplier = 0.3;
65464 return PlayAxis;
65465 }());
65466 visuals.PlayAxis = PlayAxis;
65467 var PlayControl = (function () {
65468 function PlayControl(element, renderDelegate, isMobileChart) {
65469 this.isMobileChart = isMobileChart;
65470 this.createSliderDOM(element);
65471 this.renderDelegate = renderDelegate;
65472 }
65473 PlayControl.prototype.getContainer = function () {
65474 return this.playAxisContainer;
65475 };
65476 PlayControl.prototype.remove = function () {
65477 if (this.playAxisContainer)
65478 this.playAxisContainer.remove();
65479 };
65480 PlayControl.prototype.pause = function () {
65481 this.playButton.removeClass('pause').addClass('play');
65482 };
65483 PlayControl.prototype.play = function () {
65484 this.playButton.removeClass('play').addClass('pause');
65485 };
65486 PlayControl.prototype.getCurrentIndex = function () {
65487 // TODO: round() necessary?
65488 return Math.round(this.noUiSlider.get());
65489 };
65490 PlayControl.prototype.onPlay = function (handler) {
65491 this.playButtonCircle.off('click');
65492 this.playButtonCircle.on('click', handler);
65493 };
65494 PlayControl.prototype.setFrame = function (frameIndex) {
65495 this.noUiSlider.set([frameIndex]);
65496 };
65497 ;
65498 PlayControl.prototype.rebuild = function (playData, viewport) {
65499 var _this = this;
65500 var slider = this.slider;
65501 // re-create the slider
65502 if (this.noUiSlider)
65503 this.noUiSlider.destroy();
65504 var labelData = playData.labelData;
65505 var sliderSize = PlayControl.calucalateSliderSize(labelData, viewport.width);
65506 var container = this.getContainer();
65507 if (sliderSize.marginLeft > PlayControl.SliderMarginLeft) {
65508 container.css("padding-left", sliderSize.marginLeft - PlayControl.SliderMarginLeft + "px");
65509 container.css("box-sizing", "border-box");
65510 }
65511 var skipStep = this.updateSliderControl(playData, sliderSize.width);
65512 var width = PlayControl.adjustWidthRegardingLastItem(labelData, skipStep, sliderSize.width);
65513 this.slider.css('width', width + 'px');
65514 this.noUiSlider.on('slide', function () {
65515 var indexToShow = _this.getCurrentIndex();
65516 _this.renderDelegate(indexToShow);
65517 });
65518 var nextLabelIndex = 0;
65519 // update the width and margin-left to center up each label
65520 $('.noUi-value', slider).each(function (idx, elem) {
65521 var actualWidth = labelData.labelInfo[nextLabelIndex].labelWidth;
65522 $(elem).width(actualWidth);
65523 $(elem).css('margin-left', -actualWidth / 2 + 'px');
65524 nextLabelIndex += skipStep;
65525 });
65526 };
65527 /**
65528 * Updates slider control regarding new data.
65529 * @param playData {PlayChartData<T>} Data for the slider.
65530 * @param sliderWidth {number} Slider width.
65531 * @returns {number} skip mode for the slider.
65532 */
65533 PlayControl.prototype.updateSliderControl = function (playData, sliderWidth) {
65534 var labelData = playData.labelData;
65535 var sliderElement = this.slider.get(0);
65536 var numFrames = playData.frameData.length;
65537 var options = {
65538 start: numFrames === 0 ? 0 : playData.currentFrameIndex,
65539 step: 1,
65540 range: {
65541 min: 0,
65542 max: numFrames === 0 ? 0 : numFrames - 1
65543 }
65544 };
65545 var pipOptions = null;
65546 var skipMode = 0;
65547 if (numFrames > 0) {
65548 var filterPipLabels = PlayControl.createPipsFilterFn(playData, sliderWidth, labelData);
65549 skipMode = filterPipLabels.skipStep;
65550 pipOptions = {
65551 mode: 'steps',
65552 density: Math.ceil(100 / numFrames),
65553 format: {
65554 to: function (index) { return playData.frameData[index].escapedText; },
65555 from: function (value) { return playData.frameData.indexOf(value); },
65556 },
65557 filter: filterPipLabels.filter,
65558 };
65559 }
65560 options.pips = pipOptions;
65561 noUiSlider.create(sliderElement, options);
65562 this.noUiSlider = sliderElement.noUiSlider;
65563 return skipMode;
65564 };
65565 PlayControl.createPipsFilterFn = function (playData, sliderWidth, labelData) {
65566 var maxLabelWidth = _.max(_.map(labelData.labelInfo, function (l) { return l.labelWidth; }));
65567 var pipSize = 1; //0=hide, 1=large, 2=small
65568 var skipMode = 1;
65569 var maxAllowedLabelWidth = playData.frameData.length > 1 ? sliderWidth / (playData.frameData.length - 1) : sliderWidth;
65570 var widthRatio = maxLabelWidth / maxAllowedLabelWidth;
65571 if (widthRatio > 1.25) {
65572 skipMode = Math.ceil(widthRatio);
65573 pipSize = 2;
65574 }
65575 else if (widthRatio > 1.0 || labelData.anyWordBreaks) {
65576 // wordbreak line wrapping is automatic, and we don't reserve enough space to show two lines of text with the larger font
65577 pipSize = 2;
65578 }
65579 var filterPipLabels = function (index, type) {
65580 // noUiSlider will word break / wrap to new lines, so max width is the max word length
65581 if (index % skipMode === 0) {
65582 return pipSize;
65583 }
65584 return 0; //hide
65585 };
65586 return { filter: filterPipLabels, skipStep: skipMode };
65587 };
65588 /**
65589 * Adjusts width regarding the last visible label size.
65590 * @param labelData label data for chart.
65591 * @param skipMode skip factor.
65592 * @param sliderWidth current width of slider.
65593 */
65594 PlayControl.adjustWidthRegardingLastItem = function (labelData, skipMode, sliderWidth) {
65595 var labelLenth = labelData.labelInfo.length;
65596 var lastVisibleItemIndex = Math.floor((labelLenth - 1) / skipMode) * skipMode;
65597 var distanceToEnd = sliderWidth + PlayControl.SliderMarginRight - (sliderWidth / labelLenth * (lastVisibleItemIndex + 1));
65598 var lastItemWidth = labelData.labelInfo[lastVisibleItemIndex].labelWidth;
65599 var requiredWidth = lastItemWidth / 2 - distanceToEnd;
65600 if (requiredWidth > 0) {
65601 var maxMargin = PlayControl.SliderMaxMargin - PlayControl.SliderMarginRight;
65602 requiredWidth = requiredWidth > maxMargin ? maxMargin : requiredWidth;
65603 return sliderWidth - requiredWidth;
65604 }
65605 return sliderWidth;
65606 };
65607 PlayControl.prototype.createSliderDOM = function (element) {
65608 this.playAxisContainer = $('<div class="play-axis-container"></div>')
65609 .appendTo(element)
65610 .css('height', PlayControl.PlayControlHeight + 'px');
65611 this.playButtonCircle = $('<div class="button-container"></div>')
65612 .appendTo(this.playAxisContainer);
65613 if (this.isMobileChart) {
65614 this.playButtonCircle.addClass('mobile-button-container');
65615 }
65616 this.playButton = $('<div class="play"></div>')
65617 .appendTo(this.playButtonCircle);
65618 this.slider = $('<div class="sliders"></div>')
65619 .appendTo(this.playAxisContainer);
65620 };
65621 PlayControl.calucalateSliderSize = function (labelData, viewportWidth) {
65622 var leftMargin = 0;
65623 if (!_.isEmpty(labelData.labelInfo)) {
65624 leftMargin = _.first(labelData.labelInfo).labelWidth / 2;
65625 }
65626 var sliderLeftMargin = Math.max(leftMargin, PlayControl.SliderMarginLeft);
65627 sliderLeftMargin = Math.min(PlayControl.SliderMaxMargin, sliderLeftMargin);
65628 var sliderWidth = Math.max((viewportWidth - sliderLeftMargin - PlayControl.SliderMarginRight), 1);
65629 return { width: sliderWidth, marginLeft: sliderLeftMargin };
65630 };
65631 PlayControl.SliderMarginLeft = 24 + 10 * 2; // playButton width + playButton margin * 2
65632 PlayControl.SliderMarginRight = 20;
65633 PlayControl.SliderMaxMargin = 100;
65634 PlayControl.PlayControlHeight = 80; //tuned for two rows of label text to be perfectly clipped before the third row. Dependent on current font sizes in noui-pips.css
65635 return PlayControl;
65636 }());
65637 var PlayChart;
65638 (function (PlayChart) {
65639 // TODO: add speed control to property pane
65640 // NOTE: current noUiSlider speed is a CSS property of the class .noUi-state-tap, and also is hard-coded in noUiSlider.js. We'll need to add a new create param for transition time.
65641 // 800ms matches Silverlight frame speed
65642 PlayChart.FrameStepDuration = 800;
65643 PlayChart.FrameAnimationDuration = 750; //leave 50ms for the traceline animation - to avoid being cancelled. TODO: add a proper wait impl.
65644 PlayChart.ClassName = 'playChart';
65645 function convertMatrixToCategorical(sourceDataView, frame) {
65646 debug.assert(sourceDataView && sourceDataView.metadata && !!sourceDataView.matrix, 'sourceDataView && sourceDataView.metadata && !!sourceDataView.matrix');
65647 var matrix = sourceDataView.matrix;
65648 var categorical = {
65649 categories: [],
65650 values: powerbi.data.DataViewTransform.createValueColumns()
65651 };
65652 // If we don't have enough fields, just return early. We need at least:
65653 // 2 rows and 1 column: (play->category, measures)
65654 // or:
65655 // 1 row and 2 columns: (play, series->measures)
65656 if ((_.isEmpty(matrix.columns.levels)) || (matrix.rows.levels.length < 2 && matrix.columns.levels.length < 2)) {
65657 return { metadata: sourceDataView.metadata, categorical: categorical };
65658 }
65659 var CategoryRowLevelsStartingIndex = 1;
65660 var categories = [];
65661 // Ignore the play field (first row level); the Category field(s) starts from the second row group (play->category) or we don't use this variable (categories)
65662 // Note related to VSTS 6986788 and 6885783: there are multiple levels for category during drilldown and expand.
65663 for (var i_2 = CategoryRowLevelsStartingIndex, ilen = matrix.rows.levels.length; i_2 < ilen; i_2++) {
65664 // Consider: Change the following debug.assert() to retail.assert() when the infrastructure is ready.
65665 debug.assert(matrix.rows.levels[i_2].sources.length > 0, 'The sources is always expected to contain at least one metadata column.');
65666 var sourceColumn = matrix.rows.levels[i_2].sources[0];
65667 categories.push({
65668 source: sourceColumn,
65669 values: [],
65670 identity: [],
65671 objects: undefined,
65672 });
65673 }
65674 // Matrix shape for Play:
65675 //
65676 // Series1 | Series2 | ...
65677 // --------- --------
65678 // Play1 | Category1 | values | values
65679 // | Category2 | values | values
65680 // | ...
65681 // Play2 | Category1 | values | values
65682 // | Category2 | values | values
65683 // ...
65684 // Or, with drilldown / expand on Category (e.g. expand Country -> Region):
65685 // Series1 | Series2 | ...
65686 // --------- --------
65687 // Play1 | Country1 | Region1 | values | values
65688 // | | Region2 | values | values
65689 // | Country2 | Region3 | values | values
65690 // | | Region4 | values | values
65691 // | ...
65692 // Play2 | Country1 | Region1 | values | values
65693 // | | Region2 | values | values
65694 // | Country2 | Region3 | values | values
65695 // | | Region4 | values | values
65696 // we are guaranteed at least one row (it will be the Play field)
65697 var hasRowChildren = !_.isEmpty(matrix.rows.root.children);
65698 var hasColChildren = !_.isEmpty(matrix.columns.root.children);
65699 var hasSeries = matrix.columns.levels.length > 1 && hasColChildren;
65700 var hasPlayAndCategory = matrix.rows.levels.length > 1 && hasRowChildren;
65701 if (hasSeries && !hasPlayAndCategory) {
65702 // set categories to undefined
65703 categorical.categories = undefined;
65704 var node = matrix.columns.root;
65705 categorical.values.source = matrix.columns.levels[0].sources[0];
65706 var columnLength_1 = matrix.valueSources.length;
65707 for (var i_3 = 0, len_1 = node.children.length; i_3 < len_1; i_3++) {
65708 // add all the value sources for each series
65709 var columnNode = node.children[i_3];
65710 for (var j = 0; j < columnLength_1; j++) {
65711 // DEFECT 6547170: groupName must be null to turn into (Blank), undefined will use the field name
65712 var source = _.create(matrix.valueSources[j], { groupName: columnNode.value === undefined ? null : columnNode.value });
65713 var dataViewColumn = {
65714 identity: columnNode.identity,
65715 values: [],
65716 source: source
65717 };
65718 categorical.values.push(dataViewColumn);
65719 }
65720 }
65721 // Copying the values from matrix intersection to the categorical values columns...
65722 // Given that this is the case without category levels, the matrix intersection values are stored in playFrameNode.values
65723 var playFrameNode = matrix.rows.root.children[frame];
65724 var matrixIntersectionValues = playFrameNode.values;
65725 for (var i = 0, len = node.children.length; i < len; i++) {
65726 for (var j = 0; j < columnLength_1; j++) {
65727 categorical.values[i * columnLength_1 + j].values.push(matrixIntersectionValues[i * columnLength_1 + j].value);
65728 }
65729 }
65730 }
65731 else if (hasSeries && hasRowChildren) {
65732 // series and categories
65733 var playFrameNode = matrix.rows.root.children[frame];
65734 // create the categories first
65735 DataViewMatrixUtils.forEachLeafNode(playFrameNode.children, function (categoryGroupLeafNode, index, categoryHierarchicalGroupNodes) {
65736 addMatrixHierarchicalGroupToCategories(categoryHierarchicalGroupNodes, categories);
65737 });
65738 categorical.categories = categories;
65739 // now add the series info
65740 categorical.values.source = matrix.columns.levels[0].sources[0];
65741 var nodeQueue = [];
65742 var columnNode = matrix.columns.root;
65743 var seriesIndex_1 = -1;
65744 while (columnNode) {
65745 if (columnNode.children && columnNode.children[0].children) {
65746 for (var j = 0, jlen = columnNode.children.length; j < jlen; j++) {
65747 // each of these is a "series"
65748 nodeQueue.push(columnNode.children[j]);
65749 }
65750 }
65751 else if (columnNode.children && playFrameNode.children) {
65752 // Processing a single series under here, push all the value sources for every series.
65753 var columnLength = columnNode.children.length;
65754 for (var j = 0; j < columnLength; j++) {
65755 var source = _.create(matrix.valueSources[j], { groupName: columnNode.value });
65756 var dataViewColumn = {
65757 identity: columnNode.identity,
65758 values: [],
65759 source: source,
65760 };
65761 categorical.values.push(dataViewColumn);
65762 }
65763 // Copying the values from matrix intersection to the categorical values columns...
65764 DataViewMatrixUtils.forEachLeafNode(playFrameNode.children, function (leafNode) {
65765 for (var j = 0; j < columnLength; j++) {
65766 categorical.values[seriesIndex_1 * columnLength + j].values.push(leafNode.values[seriesIndex_1 * columnLength + j].value);
65767 }
65768 });
65769 }
65770 if (nodeQueue.length > 0) {
65771 columnNode = nodeQueue[0];
65772 nodeQueue = nodeQueue.splice(1);
65773 seriesIndex_1++;
65774 }
65775 else
65776 columnNode = undefined;
65777 }
65778 }
65779 else if (hasPlayAndCategory) {
65780 // no series, just play and category
65781 var playFrameNode = matrix.rows.root.children[frame];
65782 var measureLength_1 = matrix.valueSources.length;
65783 for (var j = 0; j < measureLength_1; j++) {
65784 var dataViewColumn = {
65785 identity: undefined,
65786 values: [],
65787 source: matrix.valueSources[j]
65788 };
65789 categorical.values.push(dataViewColumn);
65790 }
65791 DataViewMatrixUtils.forEachLeafNode(playFrameNode.children, function (categoryGroupLeafNode, index, categoryHierarchicalGroupNodes) {
65792 addMatrixHierarchicalGroupToCategories(categoryHierarchicalGroupNodes, categories);
65793 // Copying the values from matrix intersection to the categorical values columns...
65794 for (var j = 0; j < measureLength_1; j++) {
65795 categorical.values[j].values.push(categoryGroupLeafNode.values[j].value);
65796 }
65797 });
65798 categorical.categories = categories;
65799 }
65800 // the visual code today expects only 1 category column, hence apply DataViewConcatenateCategoricalColumns
65801 return DataViewConcatenateCategoricalColumns.applyToPlayChartCategorical(sourceDataView.metadata, visuals.scatterChartCapabilities.objects, 'Category', categorical);
65802 }
65803 PlayChart.convertMatrixToCategorical = convertMatrixToCategorical;
65804 function addMatrixHierarchicalGroupToCategories(sourceCategoryHierarchicalGroupNodes, destinationCategories) {
65805 debug.assertNonEmpty(sourceCategoryHierarchicalGroupNodes, 'sourceCategoryHierarchicalGroupNodes');
65806 debug.assertNonEmpty(destinationCategories, 'destinationCategories');
65807 debug.assert(sourceCategoryHierarchicalGroupNodes.length === destinationCategories.length, 'pre-condition: there should be one category column per matrix row level for Category.');
65808 // Note: Before the Categorical concatenation logic got added to this playChart logic, the code did NOT populate
65809 // the ***DataViewCategoryColumn.identityFields*** property, and the playChart visual code does not seem to need it.
65810 // If we do want to populate that property, we might want to do reuse data.ISQExpr[] across nodes as much as possible
65811 // because all the child nodes under a given parent will have the exact same identityFields value, and a lot of
65812 // DataViewCategory objects can get created for a given playChart.
65813 var identity = sourceCategoryHierarchicalGroupNodes[0].identity;
65814 if (sourceCategoryHierarchicalGroupNodes.length > 1) {
65815 // if the hierarchical group has more than 1 level, create a composite identity from the nodes
65816 var identityExpr = identity.expr;
65817 for (var i = 1, ilen = sourceCategoryHierarchicalGroupNodes.length; i < ilen; i++) {
65818 var identityExprToAdd = sourceCategoryHierarchicalGroupNodes[i].identity.expr;
65819 identityExpr = SQExprBuilder.and(identityExpr, identityExprToAdd);
65820 }
65821 identity = createDataViewScopeIdentity(identityExpr);
65822 }
65823 // add the Category value of each matrix node into its respective category column
65824 for (var j = 0, jlen = destinationCategories.length; j < jlen; j++) {
65825 destinationCategories[j].identity.push(identity);
65826 var node = sourceCategoryHierarchicalGroupNodes[j];
65827 destinationCategories[j].values.push(node.value);
65828 }
65829 }
65830 function getObjectProperties(dataViewMetadata, dataLabelsSettings) {
65831 var objectProperties = {};
65832 if (dataViewMetadata && dataViewMetadata.objects) {
65833 var objects = dataViewMetadata.objects;
65834 // TODO: remove?
65835 objectProperties.currentFrameIndex = powerbi.DataViewObjects.getValue(objects, visuals.scatterChartProps.currentFrameIndex.index, null);
65836 }
65837 return objectProperties;
65838 }
65839 function converter(dataView, visualConverter) {
65840 var dataViewMetadata = dataView.metadata;
65841 var dataLabelsSettings = visuals.dataLabelUtils.getDefaultPointLabelSettings();
65842 var objectProperties = getObjectProperties(dataViewMetadata, dataLabelsSettings);
65843 var allViewModels = [];
65844 var frameKeys = [];
65845 var convertedData = undefined;
65846 var matrixRows = dataView.matrix.rows;
65847 var rowChildrenLength = matrixRows.root.children ? matrixRows.root.children.length : 0;
65848 var keySourceColumn;
65849 if (dataView.matrix && rowChildrenLength > 0 && !_.isEmpty(matrixRows.levels) && !_.isEmpty(matrixRows.levels[0].sources)) {
65850 keySourceColumn = matrixRows.levels[0].sources[0];
65851 // TODO: this should probably defer to the visual which knows how to format the categories.
65852 var formatString = visuals.valueFormatter.getFormatString(keySourceColumn, visuals.scatterChartProps.general.formatString);
65853 var keyFormatter = void 0;
65854 if (keySourceColumn.type.numeric) {
65855 // use value range, not actual values
65856 var valueRange = Math.abs(matrixRows.root.children[rowChildrenLength - 1].value - matrixRows.root.children[0].value);
65857 keyFormatter = visuals.valueFormatter.create({
65858 format: formatString,
65859 value: valueRange,
65860 value2: 0,
65861 });
65862 }
65863 else {
65864 keyFormatter = visuals.valueFormatter.createDefaultFormatter(formatString, true);
65865 }
65866 for (var i = 0, len = rowChildrenLength; i < len; i++) {
65867 var key = matrixRows.root.children[i];
65868 var frameLabelText = keyFormatter.format(key.value);
65869 // escaped html
65870 var frameLabelHtml = $("<div/>").text(frameLabelText).html();
65871 frameKeys.push({ escapedText: frameLabelHtml, text: frameLabelText });
65872 var dataViewCategorical = convertMatrixToCategorical(dataView, i);
65873 var frameInfo = { label: frameLabelHtml, column: keySourceColumn };
65874 convertedData = visualConverter(dataViewCategorical, frameInfo);
65875 allViewModels.push(convertedData);
65876 }
65877 }
65878 else {
65879 var dataViewCategorical = convertMatrixToCategorical(dataView, 0);
65880 convertedData = visualConverter(dataViewCategorical);
65881 allViewModels.push(convertedData);
65882 }
65883 // NOTE: currentViewModel is already set to the last frame
65884 objectProperties.currentFrameIndex = frameKeys.length - 1;
65885 return {
65886 allViewModels: allViewModels,
65887 currentViewModel: convertedData,
65888 frameData: frameKeys,
65889 currentFrameIndex: objectProperties.currentFrameIndex,
65890 labelData: getLabelData(frameKeys, keySourceColumn),
65891 };
65892 }
65893 PlayChart.converter = converter;
65894 function getDefaultPlayData() {
65895 var defaultData = {
65896 frameData: [],
65897 allViewModels: [],
65898 currentFrameIndex: 0,
65899 currentViewModel: undefined,
65900 labelData: {
65901 anyWordBreaks: false,
65902 labelInfo: [],
65903 },
65904 };
65905 return defaultData;
65906 }
65907 PlayChart.getDefaultPlayData = getDefaultPlayData;
65908 function getMinMaxForAllFrames(playData, getExtents) {
65909 var extents = {
65910 minY: 0,
65911 maxY: 10,
65912 minX: 0,
65913 maxX: 10,
65914 };
65915 if (playData.allViewModels && playData.allViewModels.length > 0) {
65916 extents.minY = extents.minX = Number.MAX_VALUE;
65917 extents.maxY = extents.maxX = Number.MIN_VALUE;
65918 for (var i = 0, len = playData.allViewModels.length; i < len; i++) {
65919 var data_7 = playData.allViewModels[i];
65920 var e = getExtents(data_7);
65921 // NOTE: D3.min/max handle undefined and NaN nicely, as opposed to Math.min/max
65922 extents = {
65923 minY: d3.min([e.minY, extents.minY]),
65924 maxY: d3.max([e.maxY, extents.maxY]),
65925 minX: d3.min([e.minX, extents.minX]),
65926 maxX: d3.max([e.maxX, extents.maxX]),
65927 };
65928 }
65929 }
65930 return extents;
65931 }
65932 PlayChart.getMinMaxForAllFrames = getMinMaxForAllFrames;
65933 function getLabelData(keys, keyColumn) {
65934 var textProperties = {
65935 fontFamily: 'wf_segoe-ui_normal',
65936 fontSize: jsCommon.PixelConverter.toString(14),
65937 };
65938 var labelInfo = [];
65939 var anyWordBreaks = false;
65940 for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
65941 var key = keys_1[_i];
65942 var labelWidth = jsCommon.WordBreaker.getMaxWordWidth(key.escapedText, powerbi.TextMeasurementService.measureSvgTextWidth, textProperties);
65943 // TODO: Why isn't this last part included in hasBreakers()?
65944 anyWordBreaks = anyWordBreaks || jsCommon.WordBreaker.hasBreakers(key.escapedText) || (key.escapedText).indexOf('-') > -1;
65945 labelInfo.push({ label: key.escapedText, labelWidth: labelWidth });
65946 }
65947 return {
65948 labelInfo: labelInfo,
65949 anyWordBreaks: anyWordBreaks,
65950 labelFieldName: keyColumn && keyColumn.displayName,
65951 };
65952 }
65953 function isDataViewPlayable(dataView, playRole) {
65954 if (playRole === void 0) { playRole = 'Play'; }
65955 debug.assertValue(dataView, 'dataView');
65956 var firstRowSourceRoles = dataView.matrix &&
65957 dataView.matrix.rows &&
65958 dataView.matrix.rows.levels &&
65959 dataView.matrix.rows.levels[0] &&
65960 dataView.matrix.rows.levels[0].sources &&
65961 dataView.matrix.rows.levels[0].sources[0] &&
65962 dataView.matrix.rows.levels[0].sources[0].roles;
65963 return firstRowSourceRoles && firstRowSourceRoles[playRole];
65964 }
65965 PlayChart.isDataViewPlayable = isDataViewPlayable;
65966 /** Render trace-lines for selected data points. */
65967 function renderTraceLines(allDataPoints, traceLineRenderer, shouldAnimate) {
65968 var selectedDataPoints = _.filter(allDataPoints, function (d) { return d.selected; });
65969 selectedDataPoints = _.uniq(selectedDataPoints, function (d) { return d.identity.getKey(); });
65970 traceLineRenderer.render(selectedDataPoints, shouldAnimate);
65971 }
65972 PlayChart.renderTraceLines = renderTraceLines;
65973 })(PlayChart = visuals.PlayChart || (visuals.PlayChart = {}));
65974 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
65975})(powerbi || (powerbi = {}));
65976/*
65977 * Power BI Visualizations
65978 *
65979 * Copyright (c) Microsoft Corporation
65980 * All rights reserved.
65981 * MIT License
65982 *
65983 * Permission is hereby granted, free of charge, to any person obtaining a copy
65984 * of this software and associated documentation files (the ""Software""), to deal
65985 * in the Software without restriction, including without limitation the rights
65986 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
65987 * copies of the Software, and to permit persons to whom the Software is
65988 * furnished to do so, subject to the following conditions:
65989 *
65990 * The above copyright notice and this permission notice shall be included in
65991 * all copies or substantial portions of the Software.
65992 *
65993 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65994 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65995 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65996 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65997 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65998 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
65999 * THE SOFTWARE.
66000 */
66001var powerbi;
66002(function (powerbi) {
66003 var visuals;
66004 (function (visuals) {
66005 var PixelConverter = jsCommon.PixelConverter;
66006 var VerticalSlicerRenderer = (function () {
66007 function VerticalSlicerRenderer(options) {
66008 this.textProperties = {
66009 'fontFamily': 'wf_segoe-ui_normal, helvetica, arial, sans-serif',
66010 'fontSize': '14px',
66011 };
66012 if (options) {
66013 this.behavior = options.behavior;
66014 }
66015 this.domHelper = options.domHelper;
66016 }
66017 // SlicerDefaultValueHandler
66018 VerticalSlicerRenderer.prototype.getDefaultValue = function () {
66019 if (this.data && this.data.defaultValue)
66020 return this.data.defaultValue.value;
66021 };
66022 VerticalSlicerRenderer.prototype.getIdentityFields = function () {
66023 return visuals.SlicerUtil.DefaultValueHandler.getIdentityFields(this.dataView);
66024 };
66025 VerticalSlicerRenderer.prototype.init = function (slicerInitOptions) {
66026 var _this = this;
66027 this.element = slicerInitOptions.visualInitOptions.element;
66028 this.currentViewport = slicerInitOptions.visualInitOptions.viewport;
66029 var hostServices = this.hostServices = slicerInitOptions.visualInitOptions.host;
66030 var settings = this.settings = visuals.Slicer.DefaultStyleProperties();
66031 var domHelper = this.domHelper;
66032 var bodyViewport = domHelper.getSlicerBodyViewport(this.currentViewport, settings, this.textProperties);
66033 var interactivityService;
66034 if (this.behavior)
66035 interactivityService = visuals.createInteractivityService(hostServices);
66036 var containerDiv = document.createElement('div');
66037 containerDiv.className = Selectors.Container.class;
66038 var container = this.container = d3.select(containerDiv);
66039 var header = domHelper.createSlicerHeader(hostServices);
66040 containerDiv.appendChild(header);
66041 this.header = d3.select(header);
66042 this.body = container.append('div').classed(visuals.SlicerUtil.Selectors.Body.class, true)
66043 .style({
66044 'height': PixelConverter.toString(bodyViewport.height),
66045 'width': PixelConverter.toString(bodyViewport.width),
66046 });
66047 var rowEnter = function (rowSelection) {
66048 _this.onEnterSelection(rowSelection);
66049 };
66050 var rowUpdate = function (rowSelection) {
66051 _this.onUpdateSelection(rowSelection, interactivityService);
66052 };
66053 var rowExit = function (rowSelection) {
66054 rowSelection.remove();
66055 };
66056 var listViewOptions = {
66057 rowHeight: domHelper.getRowHeight(settings, this.textProperties),
66058 enter: rowEnter,
66059 exit: rowExit,
66060 update: rowUpdate,
66061 loadMoreData: function () { return slicerInitOptions.loadMoreData(); },
66062 scrollEnabled: true,
66063 viewport: domHelper.getSlicerBodyViewport(this.currentViewport, settings, this.textProperties),
66064 baseContainer: this.body,
66065 isReadMode: function () {
66066 return (_this.hostServices.getViewMode() !== 1 /* Edit */);
66067 }
66068 };
66069 this.listView = visuals.ListViewFactory.createListView(listViewOptions);
66070 // Append container to DOM
66071 this.element.get(0).appendChild(containerDiv);
66072 return interactivityService;
66073 };
66074 VerticalSlicerRenderer.prototype.render = function (options) {
66075 var data = this.data = options.data;
66076 this.currentViewport = options.viewport;
66077 var dataView = options.dataView;
66078 if (!dataView || !data) {
66079 this.listView.empty();
66080 return;
66081 }
66082 this.dataView = dataView;
66083 var settings = this.settings = data.slicerSettings;
66084 var domHelper = this.domHelper;
66085 domHelper.updateSlicerBodyDimensions(this.currentViewport, this.body, settings);
66086 this.updateSelectionStyle();
66087 this.listView
66088 .viewport(domHelper.getSlicerBodyViewport(this.currentViewport, settings, this.textProperties))
66089 .rowHeight(domHelper.getRowHeight(settings, this.textProperties))
66090 .data(data.slicerDataPoints, function (d) { return $.inArray(d, data.slicerDataPoints); }, options.resetScrollbarPosition);
66091 };
66092 VerticalSlicerRenderer.prototype.updateSelectionStyle = function () {
66093 var settings = this.settings;
66094 this.container.classed('isMultiSelectEnabled', settings && settings.selection && !settings.selection.singleSelect);
66095 };
66096 VerticalSlicerRenderer.prototype.onEnterSelection = function (rowSelection) {
66097 var settings = this.settings;
66098 var listItemElement = rowSelection.append('li')
66099 .classed(Selectors.ItemContainer.class, true);
66100 var labelElement = listItemElement.append('div')
66101 .classed(Selectors.Input.class, true);
66102 labelElement.append('input')
66103 .attr('type', 'checkbox');
66104 labelElement.append('span')
66105 .classed(Selectors.Checkbox.class, true);
66106 listItemElement.each(function (d, i) {
66107 var item = d3.select(this);
66108 if (d.isImage) {
66109 item.append('img')
66110 .classed(visuals.SlicerUtil.Selectors.LabelImage.class, true);
66111 }
66112 else {
66113 item.append('span')
66114 .classed(visuals.SlicerUtil.Selectors.LabelText.class, true);
66115 }
66116 if (d.count != null) {
66117 item.append('span')
66118 .classed(visuals.SlicerUtil.Selectors.CountText.class, true)
66119 .style('font-size', PixelConverter.fromPoint(settings.slicerText.textSize));
66120 }
66121 });
66122 };
66123 VerticalSlicerRenderer.prototype.onUpdateSelection = function (rowSelection, interactivityService) {
66124 var settings = this.settings;
66125 var data = this.data;
66126 if (data && settings) {
66127 // Style Slicer Header
66128 var domHelper = this.domHelper;
66129 domHelper.styleSlicerHeader(this.header, settings, data.categorySourceName);
66130 this.header.attr('title', data.categorySourceName);
66131 var labelText = rowSelection.selectAll(visuals.SlicerUtil.Selectors.LabelText.selector);
66132 labelText.text(function (d) {
66133 return d.value;
66134 }).attr('title', function (d) {
66135 return d.tooltip;
66136 });
66137 domHelper.setSlicerTextStyle(labelText, settings);
66138 var labelImage = rowSelection.selectAll(visuals.SlicerUtil.Selectors.LabelImage.selector);
66139 if (!labelImage.empty()) {
66140 labelImage.attr('src', function (d) {
66141 return d.value;
66142 });
66143 }
66144 var countText = rowSelection.selectAll(visuals.SlicerUtil.Selectors.CountText.selector);
66145 if (!countText.empty()) {
66146 countText.text(function (d) { return d.count; });
66147 domHelper.setSlicerTextStyle(countText, settings);
66148 }
66149 if (interactivityService && this.body) {
66150 var body = this.body.attr('width', this.currentViewport.width);
66151 var slicerItemContainers = body.selectAll(Selectors.ItemContainer.selector);
66152 var slicerItemLabels = body.selectAll(visuals.SlicerUtil.Selectors.LabelText.selector);
66153 var slicerItemInputs = body.selectAll(Selectors.Input.selector);
66154 var slicerClear = this.header.select(visuals.SlicerUtil.Selectors.Clear.selector);
66155 var behaviorOptions = {
66156 dataPoints: data.slicerDataPoints,
66157 slicerContainer: this.container,
66158 itemContainers: slicerItemContainers,
66159 itemLabels: slicerItemLabels,
66160 itemInputs: slicerItemInputs,
66161 clear: slicerClear,
66162 interactivityService: interactivityService,
66163 settings: data.slicerSettings,
66164 };
66165 var orientationBehaviorOptions = {
66166 behaviorOptions: behaviorOptions,
66167 orientation: 0 /* Vertical */,
66168 };
66169 interactivityService.bind(data.slicerDataPoints, this.behavior, orientationBehaviorOptions, { overrideSelectionFromData: true, hasSelectionOverride: data.hasSelectionOverride, slicerDefaultValueHandler: this });
66170 visuals.SlicerWebBehavior.styleSlicerItems(rowSelection.select(Selectors.Input.selector), data.hasSelectionOverride, interactivityService.isSelectionModeInverted());
66171 }
66172 else {
66173 visuals.SlicerWebBehavior.styleSlicerItems(rowSelection.select(Selectors.Input.selector), false, false);
66174 }
66175 }
66176 };
66177 return VerticalSlicerRenderer;
66178 }());
66179 visuals.VerticalSlicerRenderer = VerticalSlicerRenderer;
66180 var Selectors;
66181 (function (Selectors) {
66182 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
66183 Selectors.Container = createClassAndSelector('slicerContainer');
66184 Selectors.ItemContainer = createClassAndSelector('slicerItemContainer');
66185 Selectors.Input = createClassAndSelector('slicerCheckbox');
66186 Selectors.Checkbox = createClassAndSelector('checkbox');
66187 })(Selectors || (Selectors = {}));
66188 var CheckboxSprite;
66189 (function (CheckboxSprite) {
66190 CheckboxSprite.MinimumSize = 8;
66191 CheckboxSprite.Size = 13;
66192 CheckboxSprite.SizeRange = CheckboxSprite.Size - CheckboxSprite.MinimumSize;
66193 })(CheckboxSprite || (CheckboxSprite = {}));
66194 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
66195})(powerbi || (powerbi = {}));
66196/*
66197 * Power BI Visualizations
66198 *
66199 * Copyright (c) Microsoft Corporation
66200 * All rights reserved.
66201 * MIT License
66202 *
66203 * Permission is hereby granted, free of charge, to any person obtaining a copy
66204 * of this software and associated documentation files (the ""Software""), to deal
66205 * in the Software without restriction, including without limitation the rights
66206 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66207 * copies of the Software, and to permit persons to whom the Software is
66208 * furnished to do so, subject to the following conditions:
66209 *
66210 * The above copyright notice and this permission notice shall be included in
66211 * all copies or substantial portions of the Software.
66212 *
66213 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66214 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66215 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
66216 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66217 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66218 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
66219 * THE SOFTWARE.
66220 */
66221var powerbi;
66222(function (powerbi) {
66223 var visuals;
66224 (function (visuals) {
66225 var PixelConverter = jsCommon.PixelConverter;
66226 var ItemWidthSampleSize = 50;
66227 var MinTextWidth = 80;
66228 var LoadMoreDataThreshold = 0.8; // The value indicates the percentage of data already shown that triggers a loadMoreData call.
66229 var DefaultStyleProperties = {
66230 labelText: {
66231 marginRight: 2,
66232 paddingLeft: 8,
66233 paddingRight: 8,
66234 },
66235 };
66236 var HorizontalSlicerRenderer = (function () {
66237 function HorizontalSlicerRenderer(options) {
66238 this.textProperties = {
66239 fontFamily: 'wf_segoe-ui_normal',
66240 fontSize: '14px'
66241 };
66242 if (options) {
66243 this.behavior = options.behavior;
66244 }
66245 this.domHelper = options.domHelper;
66246 this.dataStartIndex = 0;
66247 }
66248 // SlicerDefaultValueHandler
66249 HorizontalSlicerRenderer.prototype.getDefaultValue = function () {
66250 if (this.data && this.data.defaultValue)
66251 return this.data.defaultValue.value;
66252 };
66253 HorizontalSlicerRenderer.prototype.getIdentityFields = function () {
66254 return visuals.SlicerUtil.DefaultValueHandler.getIdentityFields(this.dataView);
66255 };
66256 HorizontalSlicerRenderer.prototype.init = function (slicerInitOptions) {
66257 this.element = slicerInitOptions.visualInitOptions.element;
66258 this.currentViewport = slicerInitOptions.visualInitOptions.viewport;
66259 var hostServices = this.hostServices = slicerInitOptions.visualInitOptions.host;
66260 if (this.behavior) {
66261 this.interactivityService = visuals.createInteractivityService(hostServices);
66262 }
66263 this.loadMoreData = function () { return slicerInitOptions.loadMoreData(); };
66264 var containerDiv = document.createElement('div');
66265 containerDiv.className = Selectors.container.class;
66266 var container = this.container = d3.select(containerDiv);
66267 var header = this.domHelper.createSlicerHeader(this.hostServices);
66268 containerDiv.appendChild(header);
66269 this.header = d3.select(header);
66270 var body = this.body = container.append('div').classed(visuals.SlicerUtil.Selectors.Body.class + " " + Selectors.FlexDisplay.class, true);
66271 this.leftNavigationArrow = body.append("button")
66272 .classed(Selectors.NavigationArrow.class + " " + Selectors.LeftNavigationArrow.class, true);
66273 this.itemsContainer = body.append("div")
66274 .classed(Selectors.ItemsContainer.class + " " + Selectors.FlexDisplay.class, true);
66275 this.rightNavigationArrow = body.append("button")
66276 .classed(Selectors.NavigationArrow.class + " " + Selectors.RightNavigationArrow.class, true);
66277 // Append container to DOM
66278 this.element.get(0).appendChild(containerDiv);
66279 this.bindNavigationEvents();
66280 return this.interactivityService;
66281 };
66282 HorizontalSlicerRenderer.prototype.render = function (options) {
66283 var data = options.data;
66284 var dataView = options.dataView;
66285 if (!dataView || !data) {
66286 this.itemsContainer.selectAll("*").remove();
66287 return;
66288 }
66289 this.data = data;
66290 this.dataView = dataView;
66291 var resized = this.currentViewport && options.viewport
66292 && (this.currentViewport.height !== options.viewport.height || this.currentViewport.width !== options.viewport.width);
66293 if (!(this.isMaxWidthCalculated() && resized)) {
66294 // Max width calculation is not required during resize, but required on data changes like changes to formatting properties fontSize, outline, outline weight, etc...
66295 // So calculating only on data updates
66296 this.calculateAndSetMaxItemWidth();
66297 this.calculateAndSetTotalItemWidth();
66298 }
66299 this.currentViewport = options.viewport;
66300 this.updateStyle();
66301 var availableWidthForItemsContainer = this.element.find(Selectors.ItemsContainer.selector).width();
66302 this.itemsToDisplay = this.getNumberOfItemsToDisplay(availableWidthForItemsContainer);
66303 if (this.itemsToDisplay === 0)
66304 return;
66305 this.renderCore();
66306 };
66307 HorizontalSlicerRenderer.prototype.renderCore = function () {
66308 var data = this.data;
66309 if (!data || !data.slicerDataPoints)
66310 return;
66311 this.normalizePosition(data.slicerDataPoints);
66312 var itemsToDisplay = this.itemsToDisplay;
66313 var dataStartIndex = this.dataStartIndex;
66314 // Update Navigation Arrows
66315 this.container.classed(Selectors.CanScrollRight.class, dataStartIndex + this.itemsToDisplay <= data.slicerDataPoints.length - 1);
66316 this.container.classed(Selectors.CanScrollLeft.class, dataStartIndex > 0);
66317 // Manipulate DOM
66318 this.renderItems(data.slicerSettings);
66319 // Bind Interactivity Service
66320 this.bindInteractivityService();
66321 // Load More Data
66322 if (dataStartIndex + itemsToDisplay >= data.slicerDataPoints.length * LoadMoreDataThreshold) {
66323 this.loadMoreData();
66324 }
66325 };
66326 HorizontalSlicerRenderer.prototype.updateStyle = function () {
66327 var viewport = this.currentViewport;
66328 var data = this.data;
66329 var defaultSettings = data.slicerSettings;
66330 var domHelper = this.domHelper;
66331 this.container
66332 .classed(Selectors.MultiSelectEnabled.class, !defaultSettings.selection.singleSelect)
66333 .style({
66334 "width": PixelConverter.toString(viewport.width),
66335 "height": PixelConverter.toString(viewport.height),
66336 });
66337 // Style Slicer Header
66338 domHelper.styleSlicerHeader(this.header, defaultSettings, data.categorySourceName);
66339 var headerTextProperties = domHelper.getHeaderTextProperties(defaultSettings);
66340 this.header.attr('title', data.categorySourceName);
66341 // Update body width and height
66342 var bodyViewport = this.bodyViewport = domHelper.getSlicerBodyViewport(viewport, defaultSettings, headerTextProperties);
66343 this.body.style({
66344 "height": PixelConverter.toString(bodyViewport.height),
66345 "width": PixelConverter.toString(bodyViewport.width),
66346 });
66347 };
66348 HorizontalSlicerRenderer.prototype.renderItems = function (defaultSettings) {
66349 var _this = this;
66350 var itemsToDisplay = this.itemsToDisplay;
66351 debug.assert(itemsToDisplay > 0, 'items to display should be greater than zero');
66352 var dataStartIndex = this.dataStartIndex;
66353 var materializedDataPoints = this.data.slicerDataPoints.slice(dataStartIndex, dataStartIndex + itemsToDisplay);
66354 var items = this.itemsContainer
66355 .selectAll(visuals.SlicerUtil.Selectors.LabelText.selector)
66356 .data(materializedDataPoints, function (d) { return _.indexOf(_this.data.slicerDataPoints, d); });
66357 items
66358 .enter()
66359 .append("div")
66360 .classed(visuals.SlicerUtil.Selectors.LabelText.class + " " + Selectors.FlexDisplay.class, true);
66361 items.order();
66362 items
66363 .style({
66364 "font-family": this.textProperties.fontFamily,
66365 "padding-left": PixelConverter.toString(DefaultStyleProperties.labelText.paddingLeft),
66366 "padding-right": PixelConverter.toString(DefaultStyleProperties.labelText.paddingRight),
66367 "margin-right": function (d, i) { return _this.isLastRowItem(i, itemsToDisplay) ? "0px" : PixelConverter.toString(DefaultStyleProperties.labelText.marginRight); },
66368 });
66369 // Default style settings from formatting pane settings
66370 this.domHelper.setSlicerTextStyle(items, defaultSettings);
66371 items.exit().remove();
66372 window.setTimeout(function () {
66373 items
66374 .attr("title", function (d) { return d.tooltip; })
66375 .text(function (d) { return d.value; });
66376 // Wrap long text into multiple columns based on height availbale
66377 var labels = _this.element.find(visuals.SlicerUtil.Selectors.LabelText.selector);
66378 var item = labels.first();
66379 var itemWidth = item.width();
66380 var itemHeight = item.height();
66381 labels.each(function (i, element) {
66382 powerbi.TextMeasurementService.wordBreakOverflowingText(element, itemWidth, itemHeight);
66383 });
66384 });
66385 };
66386 HorizontalSlicerRenderer.prototype.bindInteractivityService = function () {
66387 if (this.interactivityService && this.body) {
66388 var body = this.body;
66389 var itemsContainer = body.selectAll(Selectors.ItemsContainer.selector);
66390 var itemLabels = body.selectAll(visuals.SlicerUtil.Selectors.LabelText.selector);
66391 var clear = this.header.select(visuals.SlicerUtil.Selectors.Clear.selector);
66392 var data_8 = this.data;
66393 var behaviorOptions = {
66394 dataPoints: data_8.slicerDataPoints,
66395 slicerContainer: this.container,
66396 itemsContainer: itemsContainer,
66397 itemLabels: itemLabels,
66398 clear: clear,
66399 interactivityService: this.interactivityService,
66400 settings: data_8.slicerSettings,
66401 };
66402 var orientationBehaviorOptions = {
66403 behaviorOptions: behaviorOptions,
66404 orientation: 1 /* Horizontal */,
66405 };
66406 this.interactivityService.bind(data_8.slicerDataPoints, this.behavior, orientationBehaviorOptions, { overrideSelectionFromData: true, hasSelectionOverride: data_8.hasSelectionOverride });
66407 visuals.SlicerWebBehavior.styleSlicerItems(this.itemsContainer.selectAll(visuals.SlicerUtil.Selectors.LabelText.selector), this.interactivityService.hasSelection(), this.interactivityService.isSelectionModeInverted());
66408 }
66409 else {
66410 visuals.SlicerWebBehavior.styleSlicerItems(this.itemsContainer.selectAll(visuals.SlicerUtil.Selectors.LabelText.selector), false, false);
66411 }
66412 };
66413 HorizontalSlicerRenderer.prototype.normalizePosition = function (points) {
66414 var dataStartIndex = this.dataStartIndex;
66415 // if dataStartIndex >= points.length
66416 dataStartIndex = Math.min(dataStartIndex, points.length - 1);
66417 // if dataStartIndex < 0
66418 this.dataStartIndex = Math.max(dataStartIndex, 0);
66419 };
66420 HorizontalSlicerRenderer.prototype.bindNavigationEvents = function () {
66421 this.registerMouseWheelScrollEvents();
66422 this.registerMouseClickEvents();
66423 };
66424 HorizontalSlicerRenderer.prototype.registerMouseClickEvents = function () {
66425 var _this = this;
66426 var rightNavigationArrow = this.container.selectAll(Selectors.RightNavigationArrow.selector);
66427 var leftNavigationArrow = this.container.selectAll(Selectors.LeftNavigationArrow.selector);
66428 rightNavigationArrow
66429 .on("click", function () {
66430 _this.scrollRight();
66431 });
66432 leftNavigationArrow
66433 .on("click", function () {
66434 _this.scrollLeft();
66435 });
66436 };
66437 // Register for mouse wheel scroll events
66438 HorizontalSlicerRenderer.prototype.registerMouseWheelScrollEvents = function () {
66439 var _this = this;
66440 var scrollableElement = this.body.node();
66441 scrollableElement.addEventListener("mousewheel", function (e) {
66442 _this.onMouseWheel(e.wheelDelta);
66443 });
66444 scrollableElement.addEventListener("DOMMouseScroll", function (e) {
66445 _this.onMouseWheel(e.detail);
66446 });
66447 };
66448 HorizontalSlicerRenderer.prototype.onMouseWheel = function (wheelDelta) {
66449 if (wheelDelta < 0) {
66450 this.scrollRight();
66451 }
66452 else if (wheelDelta > 0) {
66453 this.scrollLeft();
66454 }
66455 };
66456 /* If there is only one item being displayed, we show the next item when navigation arrows are clicked
66457 * But when there are more than 1 item, n-1 items are shown say we have 10 items in total , in initial page if we show 1 to 5 items when right button is clicked we will show items from 5 to 10
66458 */
66459 HorizontalSlicerRenderer.prototype.scrollRight = function () {
66460 var itemsToDisplay = this.itemsToDisplay;
66461 var startIndex = this.dataStartIndex;
66462 var dataPointsLength = this.data.slicerDataPoints.length;
66463 var lastItemIndex = dataPointsLength - 1;
66464 // If it is the last page stay on the same page and don't navigate
66465 if (itemsToDisplay + startIndex > lastItemIndex) {
66466 return;
66467 }
66468 if (itemsToDisplay === 1) {
66469 startIndex += itemsToDisplay;
66470 }
66471 else {
66472 startIndex += itemsToDisplay - 1;
66473 }
66474 // Adjust the startIndex to show last n items if startIndex + itemsToDisplay is greater than total datapoints
66475 if (itemsToDisplay + startIndex > lastItemIndex) {
66476 startIndex = lastItemIndex - itemsToDisplay + 1;
66477 }
66478 this.dataStartIndex = startIndex;
66479 this.renderCore();
66480 };
66481 /* If there is only one item being displayed, we show the next item when navigation arrows are clicked
66482 * But when there are more than 1 item, n-1 items are shown
66483 */
66484 HorizontalSlicerRenderer.prototype.scrollLeft = function () {
66485 var itemsToDisplay = this.itemsToDisplay;
66486 var startIndex = this.dataStartIndex;
66487 var firstItemIndex = 0;
66488 // If it is the first page stay on the same page and don't navigate
66489 if (startIndex === 0) {
66490 return;
66491 }
66492 // If there is only item shown when left navigation button is clicked we want to navigate back to show previous item
66493 if (itemsToDisplay === 1) {
66494 startIndex -= itemsToDisplay;
66495 }
66496 if (startIndex - itemsToDisplay < firstItemIndex) {
66497 startIndex = firstItemIndex;
66498 }
66499 else {
66500 startIndex = startIndex - itemsToDisplay + 1;
66501 }
66502 this.dataStartIndex = startIndex;
66503 this.renderCore();
66504 };
66505 HorizontalSlicerRenderer.prototype.isLastRowItem = function (fieldIndex, columnsToDisplay) {
66506 return fieldIndex === columnsToDisplay - 1;
66507 };
66508 HorizontalSlicerRenderer.prototype.getScaledTextWidth = function (textSize) {
66509 return (textSize / jsCommon.TextSizeDefaults.TextSizeMin) * MinTextWidth;
66510 };
66511 HorizontalSlicerRenderer.prototype.isMaxWidthCalculated = function () {
66512 return this.maxItemWidth !== undefined;
66513 };
66514 // Sampling a subset of total datapoints to calculate max item width
66515 HorizontalSlicerRenderer.prototype.calculateAndSetMaxItemWidth = function () {
66516 var dataPointsLength = this.getDataPointsCount();
66517 var maxItemWidth = 0;
66518 if (dataPointsLength === 0) {
66519 this.maxItemWidth = maxItemWidth;
66520 return;
66521 }
66522 var data = this.data;
66523 var dataPoints = data.slicerDataPoints;
66524 var sampleSize = Math.min(dataPointsLength, ItemWidthSampleSize);
66525 var properties = jQuery.extend(true, {}, this.textProperties);
66526 var textSize = data.slicerSettings.slicerText.textSize;
66527 // Update text properties from formatting pane values
66528 properties.fontSize = PixelConverter.fromPoint(textSize);
66529 var getMaxWordWidth = jsCommon.WordBreaker.getMaxWordWidth;
66530 for (var i = 0; i < sampleSize; i++) {
66531 var itemText = dataPoints[i].value;
66532 properties.text = itemText;
66533 maxItemWidth = Math.max(maxItemWidth, getMaxWordWidth(itemText, powerbi.TextMeasurementService.measureSvgTextWidth, properties));
66534 }
66535 this.maxItemWidth = Math.min(maxItemWidth, this.getScaledTextWidth(textSize));
66536 };
66537 HorizontalSlicerRenderer.prototype.calculateAndSetTotalItemWidth = function () {
66538 var data = this.data;
66539 var itemPadding = DefaultStyleProperties.labelText.paddingLeft + DefaultStyleProperties.labelText.paddingRight + DefaultStyleProperties.labelText.marginRight;
66540 var borderWidth = this.domHelper.getRowsOutlineWidth(data.slicerSettings.slicerText.outline, data.slicerSettings.general.outlineWeight);
66541 this.totalItemWidth = this.maxItemWidth + itemPadding + borderWidth;
66542 };
66543 HorizontalSlicerRenderer.prototype.getNumberOfItemsToDisplay = function (widthAvailable) {
66544 var totalItemWidth = this.totalItemWidth;
66545 if (totalItemWidth === 0)
66546 return 0;
66547 var dataPointsLength = this.getDataPointsCount();
66548 var numberOfItems = Math.min(dataPointsLength, Math.round(widthAvailable / totalItemWidth));
66549 // Show atleast 1 item by default
66550 return Math.max(numberOfItems, 1);
66551 };
66552 HorizontalSlicerRenderer.prototype.getDataPointsCount = function () {
66553 return _.size(this.data.slicerDataPoints);
66554 };
66555 return HorizontalSlicerRenderer;
66556 }());
66557 visuals.HorizontalSlicerRenderer = HorizontalSlicerRenderer;
66558 var Selectors;
66559 (function (Selectors) {
66560 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
66561 Selectors.container = createClassAndSelector('horizontalSlicerContainer');
66562 Selectors.ItemsContainer = createClassAndSelector('slicerItemsContainer');
66563 Selectors.NavigationArrow = createClassAndSelector('navigationArrow');
66564 Selectors.LeftNavigationArrow = createClassAndSelector('left');
66565 Selectors.RightNavigationArrow = createClassAndSelector('right');
66566 Selectors.MultiSelectEnabled = createClassAndSelector('isMultiSelectEnabled');
66567 Selectors.FlexDisplay = createClassAndSelector('flexDisplay');
66568 Selectors.CanScrollRight = createClassAndSelector('canScrollRight');
66569 Selectors.CanScrollLeft = createClassAndSelector('canScrollLeft');
66570 })(Selectors || (Selectors = {}));
66571 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
66572})(powerbi || (powerbi = {}));
66573/*
66574 * Power BI Visualizations
66575 *
66576 * Copyright (c) Microsoft Corporation
66577 * All rights reserved.
66578 * MIT License
66579 *
66580 * Permission is hereby granted, free of charge, to any person obtaining a copy
66581 * of this software and associated documentation files (the ""Software""), to deal
66582 * in the Software without restriction, including without limitation the rights
66583 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66584 * copies of the Software, and to permit persons to whom the Software is
66585 * furnished to do so, subject to the following conditions:
66586 *
66587 * The above copyright notice and this permission notice shall be included in
66588 * all copies or substantial portions of the Software.
66589 *
66590 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66591 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66592 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
66593 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66594 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66595 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
66596 * THE SOFTWARE.
66597 */
66598var powerbi;
66599(function (powerbi) {
66600 var visuals;
66601 (function (visuals) {
66602 var DisplayNameKeys = visuals.SlicerUtil.DisplayNameKeys;
66603 var DOMHelper = visuals.SlicerUtil.DOMHelper;
66604 var SettingsHelper = visuals.SlicerUtil.SettingsHelper;
66605 var Slicer = (function () {
66606 function Slicer(options) {
66607 if (options) {
66608 this.behavior = options.behavior;
66609 }
66610 this.domHelper = new DOMHelper();
66611 }
66612 Slicer.DefaultStyleProperties = function () {
66613 return {
66614 general: {
66615 outlineColor: '#808080',
66616 outlineWeight: 1,
66617 orientation: 0 /* Vertical */,
66618 },
66619 header: {
66620 borderBottomWidth: 1,
66621 show: true,
66622 outline: visuals.outline.bottomOnly,
66623 fontColor: '#000000',
66624 textSize: 10,
66625 },
66626 slicerText: {
66627 color: '#666666',
66628 outline: visuals.outline.none,
66629 textSize: 10,
66630 },
66631 selection: {
66632 selectAllCheckboxEnabled: false,
66633 singleSelect: true,
66634 },
66635 };
66636 };
66637 Slicer.prototype.init = function (options) {
66638 this.initOptions = options;
66639 this.element = options.element;
66640 this.currentViewport = options.viewport;
66641 this.hostServices = options.host;
66642 var settings = this.settings = Slicer.DefaultStyleProperties();
66643 this.slicerOrientation = settings.general.orientation;
66644 this.waitingForData = false;
66645 this.initializeSlicerRenderer(this.slicerOrientation);
66646 };
66647 Slicer.prototype.onDataChanged = function (options) {
66648 debug.assertValue(options, 'options');
66649 var dataViews = options.dataViews;
66650 debug.assertValue(dataViews, 'dataViews');
66651 if (_.isEmpty(dataViews)) {
66652 return;
66653 }
66654 var existingDataView = this.dataView;
66655 this.dataView = dataViews[0];
66656 // Reset scrollbar by default, unless it's an Append operation or Selecting an item
66657 var resetScrollbarPosition = options.operationKind !== powerbi.VisualDataChangeOperationKind.Append
66658 && !powerbi.DataViewAnalysis.hasSameCategoryIdentity(existingDataView, this.dataView);
66659 this.render(resetScrollbarPosition, true);
66660 };
66661 Slicer.prototype.onResizing = function (finalViewport) {
66662 this.currentViewport = finalViewport;
66663 this.render(false /* resetScrollbarPosition */);
66664 };
66665 Slicer.prototype.enumerateObjectInstances = function (options) {
66666 return ObjectEnumerator.enumerateObjectInstances(options, this.slicerData, this.settings, this.dataView);
66667 };
66668 // public for testability
66669 Slicer.prototype.loadMoreData = function () {
66670 var dataView = this.dataView;
66671 if (!dataView)
66672 return;
66673 var dataViewMetadata = dataView.metadata;
66674 // Making sure that hostservices.loadMoreData is not invoked when waiting for server to load the next segment of data
66675 if (!this.waitingForData && dataViewMetadata && dataViewMetadata.segment) {
66676 this.hostServices.loadMoreData();
66677 this.waitingForData = true;
66678 }
66679 };
66680 Slicer.prototype.onClearSelection = function () {
66681 if (this.interactivityService) {
66682 this.interactivityService.clearSelection();
66683 // calls render so that default behavior can be applied after clear selection.
66684 this.render(false /* resetScrollbarPosition */);
66685 }
66686 };
66687 Slicer.prototype.render = function (resetScrollbarPosition, stopWaitingForData) {
66688 var localizedSelectAllText = this.hostServices.getLocalizedString(DisplayNameKeys.SelectAll);
66689 this.slicerData = visuals.DataConversion.convert(this.dataView, localizedSelectAllText, this.interactivityService, this.hostServices);
66690 if (this.slicerData) {
66691 this.slicerData.slicerSettings.general.outlineWeight = Math.max(this.slicerData.slicerSettings.general.outlineWeight, 0);
66692 this.settings = this.slicerData.slicerSettings;
66693 // TODO: Do we need to check SettingsHelper.areSettingsDefined(), etc. here? Can we just do value validation and coercion in the same place that we create the slicerSettings?
66694 var slicerOrientation_1 = SettingsHelper.areSettingsDefined(this.slicerData) && this.slicerData.slicerSettings.general && this.slicerData.slicerSettings.general.orientation ?
66695 this.slicerData.slicerSettings.general.orientation : Slicer.DefaultStyleProperties().general.orientation;
66696 var orientationHasChanged = this.orientationHasChanged(slicerOrientation_1);
66697 if (orientationHasChanged) {
66698 this.slicerOrientation = slicerOrientation_1;
66699 // Clear the previous slicer type when rendering the new slicer type
66700 this.element.empty();
66701 this.initializeSlicerRenderer(slicerOrientation_1);
66702 }
66703 }
66704 this.slicerRenderer.render({ dataView: this.dataView, data: this.slicerData, viewport: this.currentViewport, resetScrollbarPosition: resetScrollbarPosition });
66705 if (stopWaitingForData)
66706 this.waitingForData = false;
66707 };
66708 Slicer.prototype.orientationHasChanged = function (slicerOrientation) {
66709 return this.slicerOrientation !== slicerOrientation;
66710 };
66711 Slicer.prototype.initializeSlicerRenderer = function (slicerOrientation) {
66712 switch (slicerOrientation) {
66713 case 1 /* Horizontal */:
66714 this.initializeHorizontalSlicer();
66715 break;
66716 case 0 /* Vertical */:
66717 this.initializeVerticalSlicer();
66718 break;
66719 }
66720 };
66721 Slicer.prototype.initializeVerticalSlicer = function () {
66722 var verticalSlicerRenderer = this.slicerRenderer = new visuals.VerticalSlicerRenderer({ domHelper: this.domHelper, behavior: this.behavior });
66723 var options = this.createInitOptions();
66724 this.interactivityService = verticalSlicerRenderer.init(options);
66725 };
66726 Slicer.prototype.initializeHorizontalSlicer = function () {
66727 var horizontalSlicerRenderer = this.slicerRenderer = new visuals.HorizontalSlicerRenderer({ domHelper: this.domHelper, behavior: this.behavior });
66728 var options = this.createInitOptions();
66729 this.interactivityService = horizontalSlicerRenderer.init(options);
66730 };
66731 Slicer.prototype.createInitOptions = function () {
66732 var _this = this;
66733 return {
66734 visualInitOptions: this.initOptions,
66735 loadMoreData: function () { return _this.loadMoreData(); }
66736 };
66737 };
66738 return Slicer;
66739 }());
66740 visuals.Slicer = Slicer;
66741 /** Helper class for calculating the current slicer settings. */
66742 var ObjectEnumerator;
66743 (function (ObjectEnumerator) {
66744 function enumerateObjectInstances(options, data, settings, dataView) {
66745 if (!data)
66746 return;
66747 switch (options.objectName) {
66748 case 'items':
66749 return enumerateItems(data, settings);
66750 case 'header':
66751 return enumerateHeader(data, settings);
66752 case 'general':
66753 return enumerateGeneral(data, settings);
66754 case 'selection':
66755 if (shouldShowSelectionOption(dataView))
66756 return enumerateSelection(data, settings);
66757 }
66758 }
66759 ObjectEnumerator.enumerateObjectInstances = enumerateObjectInstances;
66760 function shouldShowSelectionOption(dataView) {
66761 return !(dataView &&
66762 dataView.metadata &&
66763 dataView.metadata.columns &&
66764 _.some(dataView.metadata.columns, function (column) { return column.discourageAggregationAcrossGroups; }));
66765 }
66766 function enumerateSelection(data, settings) {
66767 var slicerSettings = settings;
66768 var areSelectionSettingsDefined = SettingsHelper.areSettingsDefined(data) && data.slicerSettings.selection;
66769 var selectAllCheckboxEnabled = areSelectionSettingsDefined && data.slicerSettings.selection.selectAllCheckboxEnabled ?
66770 data.slicerSettings.selection.selectAllCheckboxEnabled : slicerSettings.selection.selectAllCheckboxEnabled;
66771 var singleSelect = data && data.slicerSettings && data.slicerSettings.selection && data.slicerSettings.selection.singleSelect !== undefined ?
66772 data.slicerSettings.selection.singleSelect : slicerSettings.selection.singleSelect;
66773 return [{
66774 selector: null,
66775 objectName: 'selection',
66776 properties: {
66777 selectAllCheckboxEnabled: selectAllCheckboxEnabled,
66778 singleSelect: singleSelect,
66779 }
66780 }];
66781 }
66782 function enumerateHeader(data, settings) {
66783 var slicerSettings = settings;
66784 var areHeaderSettingsDefined = SettingsHelper.areSettingsDefined(data) && data.slicerSettings.header;
66785 var fontColor = areHeaderSettingsDefined && data.slicerSettings.header.fontColor ?
66786 data.slicerSettings.header.fontColor : slicerSettings.header.fontColor;
66787 var background = areHeaderSettingsDefined && data.slicerSettings.header.background ?
66788 data.slicerSettings.header.background : slicerSettings.header.background;
66789 return [{
66790 selector: null,
66791 objectName: 'header',
66792 properties: {
66793 show: slicerSettings.header.show,
66794 fontColor: fontColor,
66795 background: background,
66796 outline: slicerSettings.header.outline,
66797 textSize: slicerSettings.header.textSize,
66798 }
66799 }];
66800 }
66801 function enumerateItems(data, settings) {
66802 var slicerSettings = settings;
66803 var areTextSettingsDefined = SettingsHelper.areSettingsDefined(data) && data.slicerSettings.slicerText;
66804 var fontColor = areTextSettingsDefined && data.slicerSettings.slicerText.color ?
66805 data.slicerSettings.slicerText.color : slicerSettings.slicerText.color;
66806 var background = areTextSettingsDefined && data.slicerSettings.slicerText.background ?
66807 data.slicerSettings.slicerText.background : slicerSettings.slicerText.background;
66808 return [{
66809 selector: null,
66810 objectName: 'items',
66811 properties: {
66812 fontColor: fontColor,
66813 background: background,
66814 outline: slicerSettings.slicerText.outline,
66815 textSize: slicerSettings.slicerText.textSize,
66816 }
66817 }];
66818 }
66819 function enumerateGeneral(data, settings) {
66820 var slicerSettings = settings;
66821 var areGeneralSettingsDefined = SettingsHelper.areSettingsDefined(data) && data.slicerSettings.general != null;
66822 var outlineColor = areGeneralSettingsDefined && data.slicerSettings.general.outlineColor ?
66823 data.slicerSettings.general.outlineColor : slicerSettings.general.outlineColor;
66824 var outlineWeight = areGeneralSettingsDefined && data.slicerSettings.general.outlineWeight ?
66825 data.slicerSettings.general.outlineWeight : slicerSettings.general.outlineWeight;
66826 var orientation = areGeneralSettingsDefined && data.slicerSettings.general.orientation != null ?
66827 data.slicerSettings.general.orientation : slicerSettings.general.orientation;
66828 return [{
66829 selector: null,
66830 objectName: 'general',
66831 properties: {
66832 outlineColor: outlineColor,
66833 outlineWeight: outlineWeight,
66834 orientation: orientation,
66835 }
66836 }];
66837 }
66838 })(ObjectEnumerator || (ObjectEnumerator = {}));
66839 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
66840})(powerbi || (powerbi = {}));
66841/*
66842 * Power BI Visualizations
66843 *
66844 * Copyright (c) Microsoft Corporation
66845 * All rights reserved.
66846 * MIT License
66847 *
66848 * Permission is hereby granted, free of charge, to any person obtaining a copy
66849 * of this software and associated documentation files (the ""Software""), to deal
66850 * in the Software without restriction, including without limitation the rights
66851 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66852 * copies of the Software, and to permit persons to whom the Software is
66853 * furnished to do so, subject to the following conditions:
66854 *
66855 * The above copyright notice and this permission notice shall be included in
66856 * all copies or substantial portions of the Software.
66857 *
66858 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66859 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66860 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
66861 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66862 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66863 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
66864 * THE SOFTWARE.
66865 */
66866var powerbi;
66867(function (powerbi) {
66868 var visuals;
66869 (function (visuals) {
66870 var TablixUtils = visuals.controls.internal.TablixUtils;
66871 var TablixObjects = visuals.controls.internal.TablixObjects;
66872 var TableHierarchyNavigator = (function () {
66873 function TableHierarchyNavigator(tableDataView, formatter) {
66874 debug.assertValue(tableDataView, 'tableDataView');
66875 debug.assertValue(formatter, 'formatter');
66876 this.tableDataView = tableDataView;
66877 this.formatter = formatter;
66878 }
66879 /**
66880 * Returns the depth of the Columnm hierarchy.
66881 */
66882 TableHierarchyNavigator.prototype.getColumnHierarchyDepth = function () {
66883 return 1;
66884 };
66885 /**
66886 * Returns the depth of the Row hierarchy.
66887 */
66888 TableHierarchyNavigator.prototype.getRowHierarchyDepth = function () {
66889 return 1;
66890 };
66891 /**
66892 * Returns the leaf count of a hierarchy.
66893 */
66894 TableHierarchyNavigator.prototype.getLeafCount = function (hierarchy) {
66895 return hierarchy.length;
66896 };
66897 /**
66898 * Returns the leaf member of a hierarchy at a specified index.
66899 */
66900 TableHierarchyNavigator.prototype.getLeafAt = function (hierarchy, index) {
66901 return hierarchy[index];
66902 };
66903 /**
66904 * Returns the specified hierarchy member parent.
66905 */
66906 TableHierarchyNavigator.prototype.getParent = function (item) {
66907 return null;
66908 };
66909 /**
66910 * Returns the index of the hierarchy member relative to its parent.
66911 */
66912 TableHierarchyNavigator.prototype.getIndex = function (item) {
66913 if (!item)
66914 return -1;
66915 if (this.isRow(item))
66916 return item.index;
66917 return this.getColumnIndex(item);
66918 };
66919 TableHierarchyNavigator.prototype.isRow = function (item) {
66920 if (!item)
66921 return false;
66922 var row = item;
66923 return row.index !== undefined && row.values !== undefined;
66924 };
66925 TableHierarchyNavigator.prototype.getColumnIndex = function (item) {
66926 return TableHierarchyNavigator.getIndex(this.tableDataView.columns, item);
66927 };
66928 /**
66929 * Checks whether a hierarchy member is a leaf.
66930 */
66931 TableHierarchyNavigator.prototype.isLeaf = function (item) {
66932 return true;
66933 };
66934 TableHierarchyNavigator.prototype.isRowHierarchyLeaf = function (cornerItem) {
66935 return false;
66936 };
66937 TableHierarchyNavigator.prototype.isColumnHierarchyLeaf = function (cornerItem) {
66938 return true;
66939 };
66940 TableHierarchyNavigator.prototype.isFirstItem = function (item, items) {
66941 // checking for item.index is unreliable because reordering the columns would cause a mismatch between index and items order
66942 return item === items[0];
66943 };
66944 TableHierarchyNavigator.prototype.areAllParentsFirst = function (item, items) {
66945 return this.isFirstItem(item, items);
66946 };
66947 /**
66948 * Checks whether a hierarchy member is the last item within its parent.
66949 */
66950 TableHierarchyNavigator.prototype.isLastItem = function (item, items) {
66951 debug.assertValue(item, 'item');
66952 return items[items.length - 1] === item;
66953 };
66954 TableHierarchyNavigator.prototype.areAllParentsLast = function (item, items) {
66955 return this.isLastItem(item, items);
66956 };
66957 /**
66958 * Gets the children members of a hierarchy member.
66959 */
66960 TableHierarchyNavigator.prototype.getChildren = function (item) {
66961 return null;
66962 };
66963 TableHierarchyNavigator.prototype.getChildrenLevelDifference = function (item) {
66964 return Infinity;
66965 };
66966 /**
66967 * Gets the members count in a specified collection.
66968 */
66969 TableHierarchyNavigator.prototype.getCount = function (items) {
66970 return items.length;
66971 };
66972 /**
66973 * Gets the member at the specified index.
66974 */
66975 TableHierarchyNavigator.prototype.getAt = function (items, index) {
66976 return items[index];
66977 };
66978 /**
66979 * Gets the hierarchy member level.
66980 */
66981 TableHierarchyNavigator.prototype.getLevel = function (item) {
66982 return 0;
66983 };
66984 /**
66985 * Returns the intersection between a row and a column item.
66986 */
66987 TableHierarchyNavigator.prototype.getIntersection = function (rowItem, columnItem) {
66988 var value;
66989 var isTotal = false;
66990 var position = new TablixUtils.CellPosition();
66991 var columnIndex = TableHierarchyNavigator.getIndex(this.tableDataView.columns, columnItem);
66992 ;
66993 position.column.index = columnIndex;
66994 position.column.isFirst = columnIndex === 0 ? true : false;
66995 position.column.isLast = columnIndex === this.tableDataView.columns.length - 1;
66996 var totalRow = rowItem;
66997 if (totalRow.totalCells != null) {
66998 isTotal = true;
66999 value = totalRow.totalCells[columnIndex];
67000 }
67001 else {
67002 var row = rowItem;
67003 var rowIndex = row.index;
67004 position.row.index = rowIndex;
67005 position.row.isFirst = rowIndex === 0;
67006 position.row.isLast = rowIndex === this.tableDataView.rows.length - 1;
67007 value = row.values[columnIndex];
67008 }
67009 var cellItem = new TablixUtils.TablixVisualCell(value, isTotal, columnItem, this.formatter);
67010 cellItem.position = position;
67011 var tableRow = rowItem;
67012 if (tableRow && tableRow.values) {
67013 var rowObjects = tableRow.values.objects;
67014 if (rowObjects) {
67015 var cellObject = rowObjects[columnIndex];
67016 if (cellObject) {
67017 cellItem.backColor = TablixObjects.PropValuesBackColor.getValue(cellObject);
67018 }
67019 }
67020 }
67021 return cellItem;
67022 };
67023 /**
67024 * Returns the corner cell between a row and a column level.
67025 */
67026 TableHierarchyNavigator.prototype.getCorner = function (rowLevel, columnLevel) {
67027 return null;
67028 };
67029 TableHierarchyNavigator.prototype.headerItemEquals = function (item1, item2) {
67030 if (item1 === item2)
67031 return true;
67032 // Typechecking does not work with interfaces nor at runtime. We need to explicitly check for
67033 // properties of DataViewMetadataColumn to determine if we can use the column equivalency check.
67034 // We expect this method to handle either VisualTableRows or DataViewMetadataColumns so checking
67035 // for displayName should be sufficient.
67036 if (item1.displayName && item2.displayName) {
67037 var column1 = item1;
67038 var column2 = item2;
67039 return powerbi.DataViewAnalysis.areMetadataColumnsEquivalent(column1, column2);
67040 }
67041 if (this.isRow(item1) && this.isRow(item2))
67042 return item1.index === item2.index;
67043 return false;
67044 };
67045 TableHierarchyNavigator.prototype.bodyCellItemEquals = function (item1, item2) {
67046 //return (item1.dataPoint === item2.dataPoint);
67047 return (item1.isMatch(item2));
67048 };
67049 TableHierarchyNavigator.prototype.cornerCellItemEquals = function (item1, item2) {
67050 // Should not be called as we don't return any corner items for table
67051 return true;
67052 };
67053 TableHierarchyNavigator.prototype.update = function (table) {
67054 this.tableDataView = table;
67055 };
67056 TableHierarchyNavigator.getIndex = function (items, item) {
67057 for (var index = 0, len = items.length; index < len; index++) {
67058 // For cases when the item was re-created during the DataTransformation phase,
67059 // we check for the item's index to verify equality.
67060 var arrayItem = items[index];
67061 if (arrayItem.index != null && item.index != null && arrayItem.index === item.index) {
67062 return index;
67063 }
67064 else {
67065 if (item === items[index])
67066 return index;
67067 }
67068 }
67069 return -1;
67070 };
67071 return TableHierarchyNavigator;
67072 }());
67073 visuals.TableHierarchyNavigator = TableHierarchyNavigator;
67074 /**
67075 * Note: Public for testability.
67076 */
67077 var TableBinder = (function () {
67078 function TableBinder(options) {
67079 this.options = options;
67080 }
67081 TableBinder.prototype.onDataViewChanged = function (dataView) {
67082 this.tableDataView = dataView;
67083 this.formattingProperties = dataView.formattingProperties;
67084 this.updateTextHeights();
67085 };
67086 TableBinder.prototype.updateTextHeights = function () {
67087 var textProps = {
67088 fontFamily: '',
67089 fontSize: TablixObjects.getTextSizeInPx(this.formattingProperties.general.textSize),
67090 text: 'a',
67091 };
67092 textProps.fontFamily = TablixUtils.FontFamilyHeader;
67093 this.textHeightHeader = Math.ceil(powerbi.TextMeasurementService.measureSvgTextHeight(textProps));
67094 textProps.fontFamily = TablixUtils.FontFamilyCell;
67095 this.textHeightValue = Math.ceil(powerbi.TextMeasurementService.measureSvgTextHeight(textProps));
67096 textProps.fontFamily = TablixUtils.FontFamilyTotal;
67097 this.textHeightTotal = Math.ceil(powerbi.TextMeasurementService.measureSvgTextHeight(textProps));
67098 };
67099 TableBinder.prototype.onStartRenderingSession = function () {
67100 };
67101 TableBinder.prototype.onEndRenderingSession = function () {
67102 };
67103 /**
67104 * Row Header.
67105 */
67106 TableBinder.prototype.bindRowHeader = function (item, cell) {
67107 cell.contentHeight = this.textHeightValue;
67108 // To clear the CSS classes that adds paddings
67109 TablixUtils.clearCellStyle(cell);
67110 if (this.options.onBindRowHeader)
67111 this.options.onBindRowHeader(item);
67112 };
67113 TableBinder.prototype.unbindRowHeader = function (item, cell) {
67114 };
67115 /**
67116 * Column Header.
67117 */
67118 TableBinder.prototype.bindColumnHeader = function (item, cell) {
67119 var _this = this;
67120 cell.extension.disableDragResize();
67121 TablixUtils.resetCellCssClass(cell);
67122 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixHeader);
67123 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixColumnHeaderLeaf);
67124 var cellStyle = new TablixUtils.CellStyle();
67125 // Set default style
67126 cellStyle.fontFamily = TablixUtils.FontFamilyHeader;
67127 cellStyle.fontColor = TablixUtils.FontColorHeaders;
67128 cellStyle.borders.bottom = new TablixUtils.EdgeSettings(TablixObjects.PropGridOutlineWeight.defaultValue, TablixObjects.PropGridOutlineColor.defaultValue);
67129 cell.contentHeight = this.textHeightHeader;
67130 if (this.sortIconsEnabled())
67131 TablixUtils.createColumnHeaderWithSortIcon(item, cell);
67132 else
67133 TablixUtils.setCellTextAndTooltip(cell, item.displayName);
67134 if (this.options.onColumnHeaderClick) {
67135 var handler = function (e) {
67136 if (TablixUtils.isValidSortClick(e)) {
67137 var sortDirection = TablixUtils.reverseSort(item.sort);
67138 _this.options.onColumnHeaderClick(item.queryName ? item.queryName : item.displayName, sortDirection);
67139 }
67140 };
67141 cell.extension.registerClickHandler(handler);
67142 }
67143 this.setColumnHeaderStyle(cell, cellStyle);
67144 cell.applyStyle(cellStyle);
67145 };
67146 TableBinder.prototype.setColumnHeaderStyle = function (cell, style) {
67147 var propsGrid = this.formattingProperties.grid;
67148 var props = this.formattingProperties.columnHeaders;
67149 var propsTotal = this.formattingProperties.total;
67150 var propsValues = this.formattingProperties.values;
67151 style.borders.top = new TablixUtils.EdgeSettings();
67152 style.borders.top.applyParams(visuals.outline.showTop(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67153 style.borders.bottom = new TablixUtils.EdgeSettings();
67154 style.borders.bottom.applyParams(visuals.outline.showBottom(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67155 style.borders.left = new TablixUtils.EdgeSettings();
67156 if (cell.position.column.isFirst) {
67157 style.borders.left.applyParams(visuals.outline.showLeft(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67158 // If we dont have left border, but Footer or Body has, we need to apply extra padding
67159 if (!visuals.outline.showLeft(props.outline) && (visuals.outline.showLeft(propsTotal.outline) || visuals.outline.showLeft(propsValues.outline)))
67160 style.paddings.left += propsGrid.outlineWeight;
67161 } // else: do nothing
67162 style.borders.right = new TablixUtils.EdgeSettings();
67163 if (cell.position.column.isLast) {
67164 style.borders.right.applyParams(visuals.outline.showRight(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67165 // If we dont have right border, but Footer or Body has, we need to apply extra padding
67166 if (!visuals.outline.showRight(props.outline) && (visuals.outline.showRight(propsTotal.outline) || visuals.outline.showRight(propsValues.outline)))
67167 style.paddings.right += propsGrid.outlineWeight;
67168 }
67169 else {
67170 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
67171 }
67172 style.fontColor = props.fontColor;
67173 style.backColor = props.backColor;
67174 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
67175 };
67176 TableBinder.prototype.unbindColumnHeader = function (item, cell) {
67177 TablixUtils.clearCellStyle(cell);
67178 TablixUtils.clearCellTextAndTooltip(cell);
67179 if (this.sortIconsEnabled())
67180 TablixUtils.removeSortIcons(cell);
67181 if (this.options.onColumnHeaderClick) {
67182 cell.extension.unregisterClickHandler();
67183 }
67184 };
67185 /**
67186 * Body Cell.
67187 */
67188 TableBinder.prototype.bindBodyCell = function (item, cell) {
67189 TablixUtils.resetCellCssClass(cell);
67190 var imgHeight;
67191 imgHeight = this.formattingProperties.grid.imageHeight;
67192 var cellStyle = new TablixUtils.CellStyle();
67193 if (item.isImage) {
67194 cell.contentHeight = imgHeight;
67195 }
67196 else {
67197 cell.contentHeight = this.textHeightValue;
67198 }
67199 if (item.isUrl && item.isValidUrl) {
67200 TablixUtils.appendATagToBodyCell(item.textContent, cell, this.formattingProperties.values.urlIcon);
67201 }
67202 else if (item.isImage && item.isValidUrl) {
67203 TablixUtils.appendImgTagToBodyCell(item.textContent, cell, imgHeight);
67204 cellStyle.hasImage = true;
67205 }
67206 else if (item.domContent) {
67207 $(cell.extension.contentHost).append(item.domContent);
67208 }
67209 else if (item.textContent) {
67210 TablixUtils.setCellTextAndTooltip(cell, item.textContent);
67211 }
67212 else {
67213 TablixUtils.setCellTextAndTooltip(cell, " ");
67214 }
67215 if (item.isTotal) {
67216 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixValueTotal);
67217 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTableFooter);
67218 cellStyle.fontFamily = TablixUtils.FontFamilyTotal;
67219 cellStyle.borders.top = new TablixUtils.EdgeSettings(TablixObjects.PropGridOutlineWeight.defaultValue, TablixObjects.PropGridOutlineColor.defaultValue);
67220 cell.contentHeight = this.textHeightTotal;
67221 }
67222 else if (item.position.row.isLast) {
67223 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTableBodyCellBottom);
67224 }
67225 else {
67226 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTableBodyCell);
67227 cellStyle.borders.bottom = new TablixUtils.EdgeSettings(TablixObjects.PropGridHorizontalWeight.defaultValue, TablixObjects.PropGridHorizontalColor.defaultValue);
67228 }
67229 if (item.isNumeric)
67230 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixValueNumeric);
67231 if (item.isTotal)
67232 this.setFooterStyle(cell, cellStyle);
67233 else
67234 this.setBodyStyle(item, cell, cellStyle);
67235 cell.applyStyle(cellStyle);
67236 };
67237 TableBinder.prototype.setBodyStyle = function (item, cell, style) {
67238 var propsGrid = this.formattingProperties.grid;
67239 var props = this.formattingProperties.values;
67240 var propsTotal = this.formattingProperties.total;
67241 var propsColumns = this.formattingProperties.columnHeaders;
67242 style.borders.top = new TablixUtils.EdgeSettings();
67243 if (cell.position.row.isFirst) {
67244 style.borders.top.applyParams(visuals.outline.showTop(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67245 } // else: do nothing
67246 style.borders.bottom = new TablixUtils.EdgeSettings();
67247 if (cell.position.row.isLast) {
67248 style.borders.bottom.applyParams(visuals.outline.showBottom(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67249 }
67250 else {
67251 style.borders.bottom.applyParams(propsGrid.gridHorizontal, propsGrid.gridHorizontalWeight, propsGrid.gridHorizontalColor);
67252 }
67253 style.borders.left = new TablixUtils.EdgeSettings();
67254 if (cell.position.column.isFirst) {
67255 style.borders.left.applyParams(visuals.outline.showLeft(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67256 // If we dont have left border, but Footer or Header has, we need to apply extra padding
67257 if (!visuals.outline.showLeft(props.outline) && (visuals.outline.showLeft(propsTotal.outline) || visuals.outline.showLeft(propsColumns.outline)))
67258 style.paddings.left += propsGrid.outlineWeight;
67259 } // else: do nothing
67260 style.borders.right = new TablixUtils.EdgeSettings();
67261 if (cell.position.column.isLast) {
67262 style.borders.right.applyParams(visuals.outline.showRight(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67263 // If we dont have right border, but Footer has, we need to apply extra padding
67264 if (!visuals.outline.showRight(props.outline) && (visuals.outline.showRight(propsTotal.outline) || visuals.outline.showRight(propsColumns.outline)))
67265 style.paddings.right += propsGrid.outlineWeight;
67266 }
67267 else {
67268 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
67269 }
67270 style.fontColor = cell.position.row.index % 2 === 0 ? props.fontColorPrimary : props.fontColorSecondary;
67271 // Conditional formatting on the cell overrides primary/secondary background colors.
67272 if (item.backColor)
67273 style.backColor = item.backColor;
67274 else
67275 style.backColor = cell.position.row.index % 2 === 0 ? props.backColorPrimary : props.backColorSecondary;
67276 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
67277 };
67278 TableBinder.prototype.setFooterStyle = function (cell, style) {
67279 var props = this.formattingProperties.total;
67280 var propsGrid = this.formattingProperties.grid;
67281 var propsValues = this.formattingProperties.values;
67282 var propsColumns = this.formattingProperties.columnHeaders;
67283 style.borders.top = new TablixUtils.EdgeSettings();
67284 style.borders.top.applyParams(visuals.outline.showTop(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67285 style.borders.bottom = new TablixUtils.EdgeSettings();
67286 style.borders.bottom.applyParams(visuals.outline.showBottom(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67287 style.borders.left = new TablixUtils.EdgeSettings();
67288 if (cell.position.column.isFirst) {
67289 style.borders.left.applyParams(visuals.outline.showLeft(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67290 // If we dont have left border, but values or column headers have, we need to apply padding
67291 if (!visuals.outline.showLeft(props.outline) && (visuals.outline.showLeft(propsValues.outline) || visuals.outline.showLeft(propsColumns.outline)))
67292 style.paddings.left += propsGrid.outlineWeight;
67293 } // else: do nothing
67294 style.borders.right = new TablixUtils.EdgeSettings();
67295 if (cell.position.column.isLast) {
67296 style.borders.right.applyParams(visuals.outline.showRight(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
67297 // If we dont have left border, but values or column headers have, we need to apply padding
67298 if (!visuals.outline.showRight(props.outline) && (visuals.outline.showRight(propsValues.outline) || visuals.outline.showRight(propsColumns.outline)))
67299 style.paddings.right += propsGrid.outlineWeight;
67300 }
67301 else {
67302 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
67303 }
67304 style.fontColor = props.fontColor;
67305 style.backColor = props.backColor;
67306 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
67307 };
67308 TableBinder.prototype.unbindBodyCell = function (item, cell) {
67309 TablixUtils.clearCellStyle(cell);
67310 TablixUtils.clearCellTextAndTooltip(cell);
67311 };
67312 /**
67313 * Corner Cell.
67314 */
67315 TableBinder.prototype.bindCornerCell = function (item, cell) {
67316 };
67317 TableBinder.prototype.unbindCornerCell = function (item, cell) {
67318 };
67319 TableBinder.prototype.bindEmptySpaceHeaderCell = function (cell) {
67320 // Not needed for Table
67321 };
67322 TableBinder.prototype.unbindEmptySpaceHeaderCell = function (cell) {
67323 // Not needed for Table
67324 };
67325 TableBinder.prototype.bindEmptySpaceFooterCell = function (cell) {
67326 // Not needed for Table
67327 };
67328 TableBinder.prototype.unbindEmptySpaceFooterCell = function (cell) {
67329 // Not needed for Table
67330 };
67331 /**
67332 * Measurement Helper.
67333 */
67334 TableBinder.prototype.getHeaderLabel = function (item) {
67335 return item.displayName;
67336 };
67337 TableBinder.prototype.getCellContent = function (item) {
67338 return item;
67339 };
67340 TableBinder.prototype.hasRowGroups = function () {
67341 return false;
67342 };
67343 TableBinder.prototype.sortIconsEnabled = function () {
67344 return this.options.layoutKind === 0 /* Canvas */;
67345 };
67346 return TableBinder;
67347 }());
67348 visuals.TableBinder = TableBinder;
67349 var Table = (function () {
67350 function Table(options) {
67351 if (options) {
67352 this.isConditionalFormattingEnabled = options.isConditionalFormattingEnabled;
67353 this.isTouchEnabled = options.isTouchEnabled;
67354 }
67355 }
67356 Table.customizeQuery = function (options) {
67357 var dataViewMapping = options.dataViewMappings[0];
67358 if (!dataViewMapping || !dataViewMapping.table || !dataViewMapping.metadata)
67359 return;
67360 var dataViewTableRows = dataViewMapping.table.rows;
67361 var objects = dataViewMapping.metadata.objects;
67362 dataViewTableRows.for.in.subtotalType = TablixObjects.shouldShowTableTotals(objects) ? 1 /* Before */ : 0 /* None */;
67363 };
67364 Table.getSortableRoles = function () {
67365 return ['Values'];
67366 };
67367 Table.prototype.init = function (options) {
67368 this.element = options.element;
67369 this.style = options.style;
67370 this.updateViewport(options.viewport);
67371 this.formatter = visuals.valueFormatter.formatValueColumn;
67372 this.isInteractive = options.interactivity && options.interactivity.selection != null;
67373 this.getLocalizedString = options.host.getLocalizedString;
67374 this.hostServices = options.host;
67375 this.persistingObjects = false;
67376 this.waitingForData = false;
67377 this.lastAllowHeaderResize = true;
67378 this.waitingForSort = false;
67379 };
67380 /**
67381 * Note: Public for testability.
67382 */
67383 Table.converter = function (dataView) {
67384 var table = dataView.table;
67385 debug.assertValue(table, 'table');
67386 debug.assertValue(table.rows, 'table.rows');
67387 var visualTable = powerbi.Prototype.inherit(table);
67388 visualTable.visualRows = [];
67389 for (var i = 0; i < table.rows.length; i++) {
67390 var visualRow = {
67391 index: i,
67392 values: table.rows[i]
67393 };
67394 visualTable.visualRows.push(visualRow);
67395 }
67396 visualTable.formattingProperties = TablixObjects.getTableObjects(dataView);
67397 return visualTable;
67398 };
67399 Table.prototype.onResizing = function (finalViewport) {
67400 this.updateViewport(finalViewport);
67401 };
67402 // Public for testability
67403 Table.prototype.getColumnWidthManager = function () {
67404 return this.columnWidthManager;
67405 };
67406 Table.prototype.onDataChanged = function (options) {
67407 debug.assertValue(options, 'options');
67408 var dataViews = options.dataViews;
67409 if (dataViews && dataViews.length > 0) {
67410 var previousDataView = this.dataView;
67411 this.dataView = dataViews[0];
67412 /* To avoid OnDataChanged being called every time we persist Objects. If:
67413 * AutoSizeColumns options was flipped
67414 * A Column was resized manually
67415 * A Column was auto-sized
67416 */
67417 if (this.persistingObjects) {
67418 this.persistingObjects = false;
67419 return;
67420 }
67421 var visualTable = Table.converter(this.dataView);
67422 var textSize = visualTable.formattingProperties.general.textSize;
67423 if (options.operationKind === powerbi.VisualDataChangeOperationKind.Append) {
67424 this.hierarchyNavigator.update(visualTable);
67425 this.tablixControl.updateModels(/*resetScrollOffsets*/ false, visualTable.visualRows, visualTable.columns);
67426 this.refreshControl(/*clear*/ false);
67427 }
67428 else {
67429 this.createOrUpdateHierarchyNavigator(visualTable);
67430 this.createColumnWidthManager();
67431 this.createTablixControl(textSize);
67432 var binder = this.tablixControl.getBinder();
67433 binder.onDataViewChanged(visualTable);
67434 this.updateInternal(textSize, previousDataView, visualTable);
67435 }
67436 }
67437 this.waitingForData = false;
67438 this.waitingForSort = false;
67439 };
67440 Table.prototype.createColumnWidthManager = function () {
67441 var _this = this;
67442 if (!this.columnWidthManager) {
67443 this.columnWidthManager = new visuals.controls.TablixColumnWidthManager(this.dataView, false /* isMatrix */, function (objectInstances) { return _this.persistColumnWidths(objectInstances); });
67444 }
67445 else {
67446 this.columnWidthManager.updateDataView(this.dataView);
67447 }
67448 };
67449 Table.prototype.persistColumnWidths = function (objectInstances) {
67450 this.persistingObjects = true;
67451 this.hostServices.persistProperties(objectInstances);
67452 };
67453 Table.prototype.updateViewport = function (newViewport) {
67454 this.currentViewport = newViewport;
67455 if (this.tablixControl) {
67456 this.tablixControl.viewport = this.currentViewport;
67457 this.verifyHeaderResize();
67458 this.refreshControl(false);
67459 }
67460 };
67461 Table.prototype.refreshControl = function (clear) {
67462 if (visuals.visibilityHelper.partiallyVisible(this.element) || this.getLayoutKind() === 1 /* DashboardTile */) {
67463 this.tablixControl.refresh(clear);
67464 }
67465 };
67466 Table.prototype.getLayoutKind = function () {
67467 return this.isInteractive ? 0 /* Canvas */ : 1 /* DashboardTile */;
67468 };
67469 Table.prototype.createOrUpdateHierarchyNavigator = function (visualTable) {
67470 if (!this.tablixControl) {
67471 var dataNavigator = new TableHierarchyNavigator(visualTable, this.formatter);
67472 this.hierarchyNavigator = dataNavigator;
67473 }
67474 else {
67475 this.hierarchyNavigator.update(visualTable);
67476 }
67477 };
67478 Table.prototype.createTablixControl = function (textSize) {
67479 if (!this.tablixControl) {
67480 // Create the control
67481 this.tablixControl = this.createControl(this.hierarchyNavigator, textSize);
67482 }
67483 };
67484 Table.prototype.createControl = function (dataNavigator, textSize) {
67485 var _this = this;
67486 var layoutKind = this.getLayoutKind();
67487 var tableBinderOptions = {
67488 onBindRowHeader: function (item) { return _this.onBindRowHeader(item); },
67489 onColumnHeaderClick: function (queryName, sortDirection) { return _this.onColumnHeaderClick(queryName, sortDirection); },
67490 layoutKind: layoutKind
67491 };
67492 var tableBinder = new TableBinder(tableBinderOptions);
67493 var layoutManager = layoutKind === 1 /* DashboardTile */
67494 ? visuals.controls.internal.DashboardTablixLayoutManager.createLayoutManager(tableBinder)
67495 : visuals.controls.internal.CanvasTablixLayoutManager.createLayoutManager(tableBinder, this.columnWidthManager);
67496 // Create Host element
67497 var tablixContainer = document.createElement('div');
67498 this.element.append(tablixContainer);
67499 var tablixOptions = {
67500 interactive: this.isInteractive,
67501 enableTouchSupport: this.isTouchEnabled,
67502 layoutKind: layoutKind,
67503 fontSize: TablixObjects.getTextSizeInPx(textSize),
67504 };
67505 return new visuals.controls.TablixControl(dataNavigator, layoutManager, tableBinder, tablixContainer, tablixOptions);
67506 };
67507 Table.prototype.updateInternal = function (textSize, previousDataView, visualTable) {
67508 var _this = this;
67509 if (this.getLayoutKind() === 1 /* DashboardTile */) {
67510 this.tablixControl.layoutManager.adjustContentSize(visuals.converterHelper.hasImageUrlColumn(this.dataView));
67511 }
67512 this.tablixControl.fontSize = TablixObjects.getTextSizeInPx(textSize);
67513 this.verifyHeaderResize();
67514 // Update models before the viewport to make sure column widths are computed correctly
67515 this.tablixControl.updateModels(/*resetScrollOffsets*/ true, visualTable.visualRows, visualTable.columns);
67516 var totals = this.createTotalsRow(this.dataView);
67517 this.tablixControl.rowDimension.setFooter(totals);
67518 this.tablixControl.viewport = this.currentViewport;
67519 var shouldClearControl = this.shouldClearControl(previousDataView, this.dataView);
67520 // Render
67521 // We need the layout for the DIV to be done so that the control can measure items correctly.
67522 setTimeout(function () {
67523 // Render
67524 _this.refreshControl(shouldClearControl);
67525 //Persist actual widths if autoSize flipped to true
67526 if (_this.columnWidthManager.shouldPersistAllColumnWidths()) {
67527 _this.columnWidthManager.persistAllColumnWidths(_this.tablixControl.layoutManager.columnWidthsToPersist);
67528 }
67529 }, 0);
67530 };
67531 Table.prototype.shouldClearControl = function (previousDataView, newDataView) {
67532 if (!this.waitingForSort || !previousDataView || !newDataView)
67533 return true;
67534 return !powerbi.DataViewAnalysis.isMetadataEquivalent(previousDataView.metadata, newDataView.metadata);
67535 };
67536 Table.prototype.createTotalsRow = function (dataView) {
67537 if (!TablixObjects.shouldShowTableTotals(dataView.metadata.objects))
67538 return null;
67539 var totals = dataView.table.totals;
67540 if (!totals || totals.length === 0)
67541 return null;
67542 var totalRow = [];
67543 var columns = dataView.table.columns;
67544 // Add totals for measure columns, blank for non-measure columns unless it's the first column
67545 for (var i = 0, len = columns.length; i < len; ++i) {
67546 var column = columns[i];
67547 var totalValue = totals[column.index];
67548 if (totalValue != null) {
67549 totalRow.push(totalValue);
67550 }
67551 else {
67552 // If the first column is a non-measure column, we put 'Total' as the text similar to PV.
67553 // Note that if the first column is a measure column we don't render any Total text at
67554 // all, once again similar to PV.
67555 totalRow.push((i === 0) ? this.getLocalizedString('TableTotalLabel') : '');
67556 }
67557 }
67558 return { totalCells: totalRow };
67559 };
67560 Table.prototype.onBindRowHeader = function (item) {
67561 if (this.needsMoreData(item)) {
67562 this.hostServices.loadMoreData();
67563 this.waitingForData = true;
67564 }
67565 };
67566 Table.prototype.onColumnHeaderClick = function (queryName, sortDirection) {
67567 this.waitingForSort = true;
67568 this.hostServices.onCustomSort(TablixUtils.getCustomSortEventArgs(queryName, sortDirection));
67569 };
67570 /**
67571 * Note: Public for testability.
67572 */
67573 Table.prototype.needsMoreData = function (item) {
67574 if (this.waitingForData || !this.dataView.metadata || !this.dataView.metadata.segment)
67575 return false;
67576 var leafCount = this.tablixControl.rowDimension.getItemsCount();
67577 var loadMoreThreshold = leafCount * Table.preferredLoadMoreThreshold;
67578 return this.hierarchyNavigator.getIndex(item) >= loadMoreThreshold;
67579 };
67580 Table.prototype.enumerateObjectInstances = function (options) {
67581 var enumeration = new visuals.ObjectEnumerationBuilder();
67582 // Visuals are initialized with an empty data view before queries are run, therefore we need to make sure that
67583 // we are resilient here when we do not have data view.
67584 if (this.dataView) {
67585 TablixObjects.enumerateObjectInstances(options, enumeration, this.dataView, visuals.controls.TablixType.Table);
67586 }
67587 return enumeration.complete();
67588 };
67589 Table.prototype.enumerateObjectRepetition = function () {
67590 var enumeration = [];
67591 // Visuals are initialized with an empty data view before queries are run, therefore we need to make sure that
67592 // we are resilient here when we do not have data view.
67593 if (this.isConditionalFormattingEnabled && this.dataView) {
67594 TablixObjects.enumerateObjectRepetition(enumeration, this.dataView, visuals.controls.TablixType.Table);
67595 }
67596 return enumeration;
67597 };
67598 Table.prototype.shouldAllowHeaderResize = function () {
67599 return this.hostServices.getViewMode() === 1 /* Edit */;
67600 };
67601 Table.prototype.onViewModeChanged = function (viewMode) {
67602 /* Refreshes the column headers to enable/disable Column resizing */
67603 this.updateViewport(this.currentViewport);
67604 };
67605 Table.prototype.verifyHeaderResize = function () {
67606 var currentAllowHeaderResize = this.shouldAllowHeaderResize();
67607 if (currentAllowHeaderResize !== this.lastAllowHeaderResize) {
67608 this.lastAllowHeaderResize = currentAllowHeaderResize;
67609 this.tablixControl.layoutManager.setAllowHeaderResize(currentAllowHeaderResize);
67610 }
67611 };
67612 Table.preferredLoadMoreThreshold = 0.8;
67613 return Table;
67614 }());
67615 visuals.Table = Table;
67616 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
67617})(powerbi || (powerbi = {}));
67618/*
67619 * Power BI Visualizations
67620 *
67621 * Copyright (c) Microsoft Corporation
67622 * All rights reserved.
67623 * MIT License
67624 *
67625 * Permission is hereby granted, free of charge, to any person obtaining a copy
67626 * of this software and associated documentation files (the ""Software""), to deal
67627 * in the Software without restriction, including without limitation the rights
67628 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
67629 * copies of the Software, and to permit persons to whom the Software is
67630 * furnished to do so, subject to the following conditions:
67631 *
67632 * The above copyright notice and this permission notice shall be included in
67633 * all copies or substantial portions of the Software.
67634 *
67635 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67636 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
67637 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67638 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
67639 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
67640 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
67641 * THE SOFTWARE.
67642 */
67643var powerbi;
67644(function (powerbi) {
67645 var visuals;
67646 (function (visuals) {
67647 var TablixUtils = visuals.controls.internal.TablixUtils;
67648 var TablixObjects = visuals.controls.internal.TablixObjects;
67649 var UrlUtils = jsCommon.UrlUtils;
67650 var MatrixVisualBodyItem = (function (_super) {
67651 __extends(MatrixVisualBodyItem, _super);
67652 function MatrixVisualBodyItem() {
67653 _super.apply(this, arguments);
67654 }
67655 Object.defineProperty(MatrixVisualBodyItem.prototype, "isMeasure", {
67656 get: function () {
67657 return true;
67658 },
67659 enumerable: true,
67660 configurable: true
67661 });
67662 ;
67663 Object.defineProperty(MatrixVisualBodyItem.prototype, "isValidUrl", {
67664 get: function () {
67665 return false;
67666 },
67667 enumerable: true,
67668 configurable: true
67669 });
67670 ;
67671 Object.defineProperty(MatrixVisualBodyItem.prototype, "isValidImage", {
67672 get: function () {
67673 return false;
67674 },
67675 enumerable: true,
67676 configurable: true
67677 });
67678 ;
67679 return MatrixVisualBodyItem;
67680 }(TablixUtils.TablixVisualCell));
67681 visuals.MatrixVisualBodyItem = MatrixVisualBodyItem;
67682 /**
67683 * Factory method used by unit tests.
67684 */
67685 function createMatrixHierarchyNavigator(matrix, formatter) {
67686 return new MatrixHierarchyNavigator(matrix, formatter);
67687 }
67688 visuals.createMatrixHierarchyNavigator = createMatrixHierarchyNavigator;
67689 var MatrixHierarchyNavigator = (function () {
67690 function MatrixHierarchyNavigator(matrix, formatter) {
67691 this.matrix = matrix;
67692 this.rowHierarchy = MatrixHierarchyNavigator.wrapMatrixHierarchy(matrix.rows);
67693 this.columnHierarchy = MatrixHierarchyNavigator.wrapMatrixHierarchy(matrix.columns);
67694 this.formatter = formatter;
67695 this.update();
67696 }
67697 /**
67698 * Returns the data view matrix.
67699 */
67700 MatrixHierarchyNavigator.prototype.getDataViewMatrix = function () {
67701 return this.matrix;
67702 };
67703 /**
67704 * Returns the depth of the column hierarchy.
67705 */
67706 MatrixHierarchyNavigator.prototype.getColumnHierarchyDepth = function () {
67707 return Math.max(this.columnHierarchy.levels.length, 1);
67708 };
67709 /**
67710 * Returns the depth of the Row hierarchy.
67711 */
67712 MatrixHierarchyNavigator.prototype.getRowHierarchyDepth = function () {
67713 return Math.max(this.rowHierarchy.levels.length, 1);
67714 };
67715 /**
67716 * Returns the leaf count of a hierarchy.
67717 */
67718 MatrixHierarchyNavigator.prototype.getLeafCount = function (hierarchy) {
67719 var matrixHierarchy = this.getMatrixHierarchy(hierarchy);
67720 if (matrixHierarchy)
67721 return matrixHierarchy.leafNodes.length;
67722 return 0;
67723 };
67724 /**
67725 * Returns the leaf member of a hierarchy at a specified index.
67726 */
67727 MatrixHierarchyNavigator.prototype.getLeafAt = function (hierarchy, index) {
67728 var matrixHierarchy = this.getMatrixHierarchy(hierarchy);
67729 if (matrixHierarchy)
67730 return matrixHierarchy.leafNodes[index];
67731 return null;
67732 };
67733 /**
67734 * Returns the leaf index of the visual node.
67735 */
67736 MatrixHierarchyNavigator.prototype.getLeafIndex = function (item) {
67737 debug.assertValue(item, 'item');
67738 return item.leafIndex;
67739 };
67740 /**
67741 * Returns the specified hierarchy member parent.
67742 */
67743 MatrixHierarchyNavigator.prototype.getParent = function (item) {
67744 debug.assertValue(item, 'item');
67745 // Return null for outermost nodes
67746 if (item.level === 0)
67747 return null;
67748 return item.parent;
67749 };
67750 /**
67751 * Returns the index of the hierarchy member relative to its parent.
67752 */
67753 MatrixHierarchyNavigator.prototype.getIndex = function (item) {
67754 debug.assertValue(item, 'item');
67755 return item.index;
67756 };
67757 /**
67758 * Checks whether a hierarchy member is a leaf.
67759 */
67760 MatrixHierarchyNavigator.prototype.isLeaf = function (item) {
67761 debug.assertValue(item, 'item');
67762 return !item.children || item.children.length === 0;
67763 };
67764 MatrixHierarchyNavigator.prototype.isRowHierarchyLeaf = function (item) {
67765 return true;
67766 };
67767 MatrixHierarchyNavigator.prototype.isColumnHierarchyLeaf = function (item) {
67768 return false;
67769 };
67770 MatrixHierarchyNavigator.prototype.isFirstItem = function (item, items) {
67771 return item === _.first(items);
67772 };
67773 MatrixHierarchyNavigator.prototype.areAllParentsFirst = function (item, items) {
67774 if (!item)
67775 return false;
67776 var parent = this.getParent(item);
67777 if (!parent) {
67778 return this.isFirstItem(item, item.siblings);
67779 }
67780 else {
67781 return this.isFirstItem(item, item.siblings) && this.areAllParentsFirst(parent, parent.siblings);
67782 }
67783 };
67784 /**
67785 * Checks whether a hierarchy member is the last item within its parent.
67786 */
67787 MatrixHierarchyNavigator.prototype.isLastItem = function (item, items) {
67788 debug.assertValue(item, 'item');
67789 return item === _.last(items);
67790 };
67791 MatrixHierarchyNavigator.prototype.areAllParentsLast = function (item, items) {
67792 if (!item)
67793 return false;
67794 var parent = this.getParent(item);
67795 if (!parent) {
67796 return this.isLastItem(item, item.siblings);
67797 }
67798 else {
67799 return this.isLastItem(item, item.siblings) && this.areAllParentsLast(parent, parent.siblings);
67800 }
67801 };
67802 /**
67803 * Gets the children members of a hierarchy member.
67804 */
67805 MatrixHierarchyNavigator.prototype.getChildren = function (item) {
67806 debug.assertValue(item, 'item');
67807 return item.children;
67808 };
67809 /**
67810 * Gets the difference between current level and highest child's level. Can be > 1 if there are multiple values
67811 * @param {MatrixVisualNode} item
67812 * @returns
67813 */
67814 MatrixHierarchyNavigator.prototype.getChildrenLevelDifference = function (item) {
67815 var diff = Infinity;
67816 var children = this.getChildren(item);
67817 for (var i = 0, ilen = children.length; i < ilen; i++) {
67818 diff = Math.min(diff, children[i].level - item.level);
67819 }
67820 return diff;
67821 };
67822 /**
67823 * Gets the members count in a specified collection.
67824 */
67825 MatrixHierarchyNavigator.prototype.getCount = function (items) {
67826 debug.assertValue(items, 'items');
67827 return items.length;
67828 };
67829 /**
67830 * Gets the member at the specified index.
67831 */
67832 MatrixHierarchyNavigator.prototype.getAt = function (items, index) {
67833 debug.assertValue(items, 'items');
67834 return items[index];
67835 };
67836 /**
67837 * Gets the hierarchy member level.
67838 */
67839 MatrixHierarchyNavigator.prototype.getLevel = function (item) {
67840 debug.assertValue(item, 'item');
67841 return item.level;
67842 };
67843 /**
67844 * Returns the intersection between a row and a column item.
67845 */
67846 MatrixHierarchyNavigator.prototype.getIntersection = function (rowItem, columnItem) {
67847 debug.assertValue(rowItem, 'rowItem');
67848 debug.assertValue(columnItem, 'columnItem');
67849 var isSubtotalItem = rowItem.isSubtotal === true || columnItem.isSubtotal === true;
67850 var node;
67851 var valueSource;
67852 var rowIndex = rowItem.leafIndex;
67853 var colIndex = columnItem.leafIndex;
67854 var bodyCell;
67855 if (!rowItem.values) {
67856 node = undefined;
67857 }
67858 else {
67859 node = (rowItem.values[columnItem.leafIndex]);
67860 }
67861 if (node) {
67862 valueSource = this.matrix.valueSources[node.valueSourceIndex || 0];
67863 bodyCell = new MatrixVisualBodyItem(node.value, isSubtotalItem, valueSource, this.formatter);
67864 }
67865 else {
67866 bodyCell = new MatrixVisualBodyItem(undefined, isSubtotalItem, undefined, this.formatter);
67867 }
67868 bodyCell.position.row.index = rowIndex;
67869 bodyCell.position.row.indexInSiblings = rowItem.siblings.indexOf(rowItem);
67870 bodyCell.position.row.isFirst = rowIndex === 0;
67871 bodyCell.position.row.isLast = rowIndex === this.rowHierarchy.leafNodes.length - 1;
67872 bodyCell.position.column.index = colIndex;
67873 bodyCell.position.column.indexInSiblings = columnItem.siblings.indexOf(columnItem);
67874 bodyCell.position.column.isFirst = colIndex === 0;
67875 bodyCell.position.column.isLast = colIndex === this.columnHierarchy.leafNodes.length - 1;
67876 return bodyCell;
67877 };
67878 /**
67879 * Returns the corner cell between a row and a column level.
67880 */
67881 MatrixHierarchyNavigator.prototype.getCorner = function (rowLevel, columnLevel) {
67882 debug.assert(rowLevel >= 0, 'rowLevel');
67883 debug.assert(columnLevel >= 0, 'columnLevel');
67884 var columnLevels = this.columnHierarchy.levels;
67885 var rowLevels = this.rowHierarchy.levels;
67886 if (columnLevel === columnLevels.length - 1 || columnLevels.length === 0) {
67887 var levelSource = rowLevels[rowLevel];
67888 if (levelSource)
67889 return {
67890 metadata: levelSource.sources[0],
67891 isColumnHeaderLeaf: true,
67892 isRowHeaderLeaf: rowLevel === rowLevels.length - 1,
67893 };
67894 }
67895 if (rowLevel === rowLevels.length - 1) {
67896 var levelSource = columnLevels[columnLevel];
67897 if (levelSource)
67898 return {
67899 metadata: levelSource.sources[0],
67900 isColumnHeaderLeaf: false,
67901 isRowHeaderLeaf: true,
67902 };
67903 }
67904 return {
67905 metadata: null,
67906 isColumnHeaderLeaf: false,
67907 isRowHeaderLeaf: false,
67908 };
67909 };
67910 MatrixHierarchyNavigator.prototype.headerItemEquals = function (item1, item2) {
67911 if (item1 && item2)
67912 return (item1 === item2);
67913 else
67914 return false;
67915 };
67916 MatrixHierarchyNavigator.prototype.bodyCellItemEquals = function (item1, item2) {
67917 return (item1.position.isMatch(item2.position));
67918 };
67919 MatrixHierarchyNavigator.prototype.cornerCellItemEquals = function (item1, item2) {
67920 return item1 === item2;
67921 };
67922 MatrixHierarchyNavigator.prototype.getMatrixColumnHierarchy = function () {
67923 return this.columnHierarchy;
67924 };
67925 MatrixHierarchyNavigator.prototype.getMatrixRowHierarchy = function () {
67926 return this.rowHierarchy;
67927 };
67928 /**
67929 * Implementation for MatrixDataAdapter interface.
67930 */
67931 MatrixHierarchyNavigator.prototype.update = function (dataViewMatrix, updateColumns) {
67932 if (updateColumns === void 0) { updateColumns = true; }
67933 if (dataViewMatrix) {
67934 this.matrix = dataViewMatrix;
67935 this.rowHierarchy = MatrixHierarchyNavigator.wrapMatrixHierarchy(dataViewMatrix.rows);
67936 if (updateColumns)
67937 this.columnHierarchy = MatrixHierarchyNavigator.wrapMatrixHierarchy(dataViewMatrix.columns);
67938 }
67939 this.updateHierarchy(this.rowHierarchy);
67940 if (updateColumns) {
67941 this.updateHierarchy(this.columnHierarchy);
67942 MatrixHierarchyNavigator.updateStaticColumnHeaders(this.columnHierarchy);
67943 }
67944 };
67945 MatrixHierarchyNavigator.wrapMatrixHierarchy = function (hierarchy) {
67946 var matrixHierarchy = powerbi.Prototype.inherit(hierarchy);
67947 matrixHierarchy.leafNodes = [];
67948 return matrixHierarchy;
67949 };
67950 MatrixHierarchyNavigator.prototype.updateHierarchy = function (hierarchy) {
67951 if (hierarchy.leafNodes.length > 0)
67952 hierarchy.leafNodes.length = 0;
67953 if (hierarchy.root.children)
67954 this.updateRecursive(hierarchy, hierarchy.root.children, null, hierarchy.leafNodes);
67955 };
67956 MatrixHierarchyNavigator.prototype.updateRecursive = function (hierarchy, nodes, parent, cache) {
67957 var level;
67958 for (var i = 0, ilen = nodes.length; i < ilen; i++) {
67959 var node = nodes[i];
67960 node.siblings = nodes;
67961 if (parent)
67962 node.parent = parent;
67963 if (!level)
67964 level = hierarchy.levels[node.level];
67965 if (level) {
67966 var source = level.sources[node.levelSourceIndex ? node.levelSourceIndex : 0];
67967 var formatString = visuals.valueFormatter.getFormatString(source, TablixObjects.PropColumnFormatString.getPropertyID());
67968 if (formatString)
67969 node.name = this.formatter(node.value, source, TablixObjects.PropColumnFormatString.getPropertyID());
67970 node.queryName = source.queryName;
67971 }
67972 node.index = i;
67973 if (node.children && node.children.length > 0) {
67974 this.updateRecursive(hierarchy, node.children, node, cache);
67975 }
67976 else {
67977 node.leafIndex = cache.length;
67978 cache.push(node);
67979 }
67980 }
67981 };
67982 MatrixHierarchyNavigator.updateStaticColumnHeaders = function (columnHierarchy) {
67983 var columnLeafNodes = columnHierarchy.leafNodes;
67984 if (columnLeafNodes && columnLeafNodes.length > 0) {
67985 var columnLeafSources = columnHierarchy.levels[columnLeafNodes[0].level].sources;
67986 for (var i = 0, ilen = columnLeafNodes.length; i < ilen; i++) {
67987 var columnLeafNode = columnLeafNodes[i];
67988 // Static leaf may need to get label from it's definition
67989 if (!columnLeafNode.identity && columnLeafNode.value === undefined) {
67990 // We make distincion between null and undefined. Null can be considered as legit value, undefined means we need to fall back to metadata
67991 var source = columnLeafSources[columnLeafNode.levelSourceIndex ? columnLeafNode.levelSourceIndex : 0];
67992 if (source)
67993 columnLeafNode.name = source.displayName;
67994 }
67995 }
67996 }
67997 };
67998 MatrixHierarchyNavigator.prototype.getMatrixHierarchy = function (rootNodes) {
67999 var rowHierarchyRootNodes = this.rowHierarchy.root.children;
68000 if (rowHierarchyRootNodes && rootNodes === rowHierarchyRootNodes)
68001 return this.rowHierarchy;
68002 var columnHierarchyRootNodes = this.columnHierarchy.root.children;
68003 if (columnHierarchyRootNodes && rootNodes === columnHierarchyRootNodes)
68004 return this.columnHierarchy;
68005 return null;
68006 };
68007 return MatrixHierarchyNavigator;
68008 }());
68009 var MatrixBinder = (function () {
68010 function MatrixBinder(hierarchyNavigator, options) {
68011 // We pass the hierarchy navigator in here because it is the object that will
68012 // survive data changes and gets updated with the latest data view.
68013 this.hierarchyNavigator = hierarchyNavigator;
68014 this.options = options;
68015 }
68016 MatrixBinder.prototype.onDataViewChanged = function (formattingProperties) {
68017 this.formattingProperties = formattingProperties;
68018 this.updateTextHeights();
68019 };
68020 MatrixBinder.prototype.updateTextHeights = function () {
68021 var textProps = {
68022 fontFamily: '',
68023 fontSize: TablixObjects.getTextSizeInPx(this.formattingProperties.general.textSize),
68024 text: 'a',
68025 };
68026 textProps.fontFamily = TablixUtils.FontFamilyHeader;
68027 this.textHeightHeader = Math.ceil(powerbi.TextMeasurementService.measureSvgTextHeight(textProps));
68028 textProps.fontFamily = TablixUtils.FontFamilyCell;
68029 this.textHeightValue = Math.ceil(powerbi.TextMeasurementService.measureSvgTextHeight(textProps));
68030 textProps.fontFamily = TablixUtils.FontFamilyTotal;
68031 this.textHeightTotal = Math.ceil(powerbi.TextMeasurementService.measureSvgTextHeight(textProps));
68032 };
68033 MatrixBinder.prototype.onStartRenderingSession = function () {
68034 };
68035 MatrixBinder.prototype.onEndRenderingSession = function () {
68036 };
68037 /**
68038 * Row Header.
68039 */
68040 MatrixBinder.prototype.bindRowHeader = function (item, cell) {
68041 TablixUtils.resetCellCssClass(cell);
68042 var cellStyle = new TablixUtils.CellStyle();
68043 var isLeaf = this.hierarchyNavigator && this.hierarchyNavigator.isLeaf(item);
68044 if (isLeaf) {
68045 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassMatrixRowHeaderLeaf);
68046 cellStyle.borders.right = new TablixUtils.EdgeSettings(TablixObjects.PropGridOutlineWeight.defaultValue, TablixObjects.PropGridOutlineColor.defaultValue);
68047 }
68048 if (item.isSubtotal) {
68049 cellStyle.paddings.left = TablixUtils.CellPaddingLeftMatrixTotal;
68050 }
68051 this.bindHeader(item, cell, this.getRowHeaderMetadata(item), cellStyle);
68052 if (this.options.onBindRowHeader)
68053 this.options.onBindRowHeader(item);
68054 this.setRowHeaderStyle(cell, cellStyle);
68055 cell.applyStyle(cellStyle);
68056 };
68057 MatrixBinder.prototype.setRowHeaderStyle = function (cell, style) {
68058 var propsGrid = this.formattingProperties.grid;
68059 var props = this.formattingProperties.rowHeaders;
68060 var propsValues = this.formattingProperties.values;
68061 var propsCols = this.formattingProperties.columnHeaders;
68062 style.borders.top = new TablixUtils.EdgeSettings();
68063 if (cell.position.row.isFirst) {
68064 style.borders.top.applyParams(visuals.outline.showTop(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68065 // If we dont have top border, but Values have, we need to apply extra padding
68066 if (!visuals.outline.showTop(props.outline) && visuals.outline.showTop(propsValues.outline))
68067 style.paddings.top += propsGrid.outlineWeight;
68068 } // else: do nothing
68069 style.borders.bottom = new TablixUtils.EdgeSettings();
68070 if (cell.position.row.isLast) {
68071 style.borders.bottom.applyParams(visuals.outline.showBottom(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68072 // If we dont have bottom border, but Values have, we need to apply extra padding
68073 if (!visuals.outline.showBottom(props.outline) && visuals.outline.showBottom(propsValues.outline))
68074 style.paddings.bottom += propsGrid.outlineWeight;
68075 }
68076 else {
68077 style.borders.bottom.applyParams(propsGrid.gridHorizontal, propsGrid.gridHorizontalWeight, propsGrid.gridHorizontalColor);
68078 }
68079 style.borders.left = new TablixUtils.EdgeSettings();
68080 if (cell.position.column.isFirst) {
68081 style.borders.left.applyParams(visuals.outline.showLeft(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68082 // If we dont have left border, but Column Headers have, we need to apply extra padding
68083 if (!visuals.outline.showLeft(props.outline) && visuals.outline.showLeft(propsCols.outline))
68084 style.paddings.left += propsGrid.outlineWeight;
68085 } // else: do nothing
68086 style.borders.right = new TablixUtils.EdgeSettings();
68087 if (cell.position.column.isLast) {
68088 style.borders.right.applyParams(visuals.outline.showRight(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68089 }
68090 else {
68091 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
68092 }
68093 style.fontColor = props.fontColor;
68094 style.backColor = props.backColor;
68095 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
68096 };
68097 MatrixBinder.prototype.unbindRowHeader = function (item, cell) {
68098 TablixUtils.clearCellStyle(cell);
68099 TablixUtils.clearCellTextAndTooltip(cell);
68100 };
68101 /**
68102 * Column Header.
68103 */
68104 MatrixBinder.prototype.bindColumnHeader = function (item, cell) {
68105 TablixUtils.resetCellCssClass(cell);
68106 // Set default style
68107 var cellStyle = new TablixUtils.CellStyle();
68108 var overwriteTotalLabel = false;
68109 var isLeaf = this.hierarchyNavigator && this.hierarchyNavigator.isLeaf(item);
68110 if (isLeaf) {
68111 cellStyle.borders.bottom = new TablixUtils.EdgeSettings(TablixObjects.PropGridOutlineWeight.defaultValue, TablixObjects.PropGridOutlineColor.defaultValue);
68112 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixColumnHeaderLeaf);
68113 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixValueNumeric);
68114 var sortableHeaderColumnMetadata = this.getSortableHeaderColumnMetadata(item);
68115 if (sortableHeaderColumnMetadata && this.options.showSortIcons) {
68116 this.registerColumnHeaderClickHandler(sortableHeaderColumnMetadata, cell);
68117 TablixUtils.createColumnHeaderWithSortIcon(sortableHeaderColumnMetadata, cell);
68118 }
68119 // Overwrite only if the there are subtotal siblings (like in the multimeasure case), which means ALL siblings are subtotals.
68120 if (item.isSubtotal && item.parent && item.parent.children.length > 1 && item.parent.children[0].isSubtotal)
68121 overwriteTotalLabel = true;
68122 }
68123 cell.extension.disableDragResize();
68124 this.bindHeader(item, cell, this.getColumnHeaderMetadata(item), cellStyle, overwriteTotalLabel);
68125 this.setColumnHeaderStyle(cell, cellStyle);
68126 cell.applyStyle(cellStyle);
68127 };
68128 MatrixBinder.prototype.setColumnHeaderStyle = function (cell, style) {
68129 var propsGrid = this.formattingProperties.grid;
68130 var props = this.formattingProperties.columnHeaders;
68131 var propsValues = this.formattingProperties.values;
68132 style.fontColor = props.fontColor;
68133 style.backColor = props.backColor;
68134 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
68135 style.borders.top = new TablixUtils.EdgeSettings();
68136 if (cell.position.row.isFirst) {
68137 style.borders.top.applyParams(visuals.outline.showTop(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68138 } // else: do nothing
68139 style.borders.bottom = new TablixUtils.EdgeSettings();
68140 if (cell.position.row.isLast) {
68141 style.borders.bottom.applyParams(visuals.outline.showBottom(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68142 }
68143 else {
68144 style.borders.bottom.applyParams(propsGrid.gridHorizontal, propsGrid.gridHorizontalWeight, propsGrid.gridHorizontalColor);
68145 }
68146 style.borders.left = new TablixUtils.EdgeSettings();
68147 if (cell.position.column.isFirst) {
68148 // If we dont have left border, but Values have, we need to apply extra padding
68149 if (!visuals.outline.showLeft(props.outline) && visuals.outline.showLeft(propsValues.outline))
68150 style.paddings.left += propsGrid.outlineWeight;
68151 }
68152 style.borders.right = new TablixUtils.EdgeSettings();
68153 if (cell.position.column.isLast) {
68154 style.borders.right.applyParams(visuals.outline.showRight(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68155 // If we dont have right border, but Values have, we need to apply extra padding
68156 if (!visuals.outline.showRight(props.outline) && visuals.outline.showRight(propsValues.outline))
68157 style.paddings.right += propsGrid.outlineWeight;
68158 }
68159 else {
68160 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
68161 }
68162 };
68163 MatrixBinder.prototype.unbindColumnHeader = function (item, cell) {
68164 TablixUtils.clearCellStyle(cell);
68165 TablixUtils.clearCellTextAndTooltip(cell);
68166 var sortableHeaderColumnMetadata = this.getSortableHeaderColumnMetadata(item);
68167 if (sortableHeaderColumnMetadata) {
68168 this.unregisterColumnHeaderClickHandler(cell);
68169 }
68170 if (this.options.showSortIcons)
68171 TablixUtils.removeSortIcons(cell);
68172 };
68173 MatrixBinder.prototype.bindHeader = function (item, cell, metadata, style, overwriteSubtotalLabel) {
68174 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixHeader);
68175 style.fontFamily = TablixUtils.FontFamilyHeader;
68176 style.fontColor = TablixUtils.FontColorHeaders;
68177 var imgHeight = this.formattingProperties.grid.imageHeight;
68178 if (visuals.converterHelper.isImageUrlColumn(metadata))
68179 cell.contentHeight = imgHeight;
68180 else if (item.isSubtotal)
68181 cell.contentHeight = this.textHeightTotal;
68182 else
68183 cell.contentHeight = this.textHeightValue;
68184 if (item.isSubtotal) {
68185 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixValueTotal);
68186 style.fontFamily = TablixUtils.FontFamilyTotal;
68187 if (!overwriteSubtotalLabel) {
68188 TablixUtils.setCellTextAndTooltip(cell, this.options.totalLabel);
68189 return;
68190 }
68191 }
68192 var value = MatrixBinder.getNodeLabel(item);
68193 if (!value) {
68194 // just to maintain the height of the row in case all realized cells are nulls
68195 cell.extension.contentHost.innerHTML = TablixUtils.StringNonBreakingSpace;
68196 }
68197 else if (visuals.converterHelper.isWebUrlColumn(metadata) && UrlUtils.isValidUrl(value)) {
68198 TablixUtils.appendATagToBodyCell(item.value, cell);
68199 }
68200 else if (visuals.converterHelper.isImageUrlColumn(metadata)) {
68201 style.hasImage = true;
68202 if (UrlUtils.isValidImageUrl(value)) {
68203 TablixUtils.appendImgTagToBodyCell(item.value, cell, imgHeight);
68204 }
68205 else {
68206 TablixUtils.setCellTextAndTooltip(cell, value);
68207 }
68208 }
68209 else {
68210 TablixUtils.setCellTextAndTooltip(cell, value);
68211 }
68212 };
68213 MatrixBinder.prototype.registerColumnHeaderClickHandler = function (columnMetadata, cell) {
68214 var _this = this;
68215 if (this.options.onColumnHeaderClick) {
68216 var handler = function (e) {
68217 if (TablixUtils.isValidSortClick(e)) {
68218 var sortDirection = TablixUtils.reverseSort(columnMetadata.sort);
68219 _this.options.onColumnHeaderClick(columnMetadata.queryName ? columnMetadata.queryName : columnMetadata.displayName, sortDirection);
68220 }
68221 };
68222 cell.extension.registerClickHandler(handler);
68223 }
68224 };
68225 MatrixBinder.prototype.unregisterColumnHeaderClickHandler = function (cell) {
68226 if (this.options.onColumnHeaderClick) {
68227 cell.extension.unregisterClickHandler();
68228 }
68229 };
68230 /**
68231 * Body Cell.
68232 */
68233 MatrixBinder.prototype.bindBodyCell = function (item, cell) {
68234 TablixUtils.resetCellCssClass(cell);
68235 var cellStyle = new TablixUtils.CellStyle();
68236 cell.contentHeight = this.textHeightValue;
68237 if (item.domContent) {
68238 $(cell.extension.contentHost).append(item.domContent);
68239 }
68240 else {
68241 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixValueNumeric);
68242 if (item.isTotal) {
68243 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixValueTotal);
68244 cellStyle.fontFamily = TablixUtils.FontFamilyTotal;
68245 cell.contentHeight = this.textHeightTotal;
68246 }
68247 if (item.textContent) {
68248 TablixUtils.setCellTextAndTooltip(cell, item.textContent);
68249 }
68250 }
68251 this.setBodyCellStyle(cell, item, cellStyle);
68252 cell.applyStyle(cellStyle);
68253 };
68254 MatrixBinder.prototype.setBodyCellStyle = function (cell, item, style) {
68255 var propsGrid = this.formattingProperties.grid;
68256 var props = this.formattingProperties.values;
68257 var propsTotal = this.formattingProperties.subtotals;
68258 var propsRows = this.formattingProperties.rowHeaders;
68259 var propsColumns = this.formattingProperties.columnHeaders;
68260 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
68261 style.borders.top = new TablixUtils.EdgeSettings();
68262 if (cell.position.row.isFirst) {
68263 style.borders.top.applyParams(visuals.outline.showTop(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68264 // If we dont have top border, but Row Headers have, we need to apply extra padding
68265 if (!visuals.outline.showTop(props.outline) && visuals.outline.showTop(propsRows.outline))
68266 style.paddings.top += propsGrid.outlineWeight;
68267 } // else: do nothing
68268 style.borders.bottom = new TablixUtils.EdgeSettings();
68269 if (cell.position.row.isLast) {
68270 style.borders.bottom.applyParams(visuals.outline.showBottom(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68271 // If we dont have bottom border, but Row Headers have, we need to apply extra padding
68272 if (!visuals.outline.showBottom(props.outline) && visuals.outline.showBottom(propsRows.outline))
68273 style.paddings.bottom += propsGrid.outlineWeight;
68274 }
68275 else {
68276 style.borders.bottom.applyParams(propsGrid.gridHorizontal, propsGrid.gridHorizontalWeight, propsGrid.gridHorizontalColor);
68277 }
68278 style.borders.left = new TablixUtils.EdgeSettings();
68279 if (cell.position.column.isFirst) {
68280 style.borders.left.applyParams(visuals.outline.showLeft(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68281 } // else: do nothing
68282 style.borders.right = new TablixUtils.EdgeSettings();
68283 if (cell.position.column.isLast) {
68284 style.borders.right.applyParams(visuals.outline.showRight(props.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68285 // If we dont have right border, but Column Headers have, we need to apply extra padding
68286 if (!visuals.outline.showRight(props.outline) && visuals.outline.showRight(propsColumns.outline))
68287 style.paddings.right += propsGrid.outlineWeight;
68288 }
68289 else {
68290 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
68291 }
68292 var rowBandingIndex;
68293 if (this.formattingProperties.general.rowSubtotals && propsTotal.backColor)
68294 rowBandingIndex = item.position.row.indexInSiblings;
68295 else
68296 rowBandingIndex = item.position.row.index;
68297 if (item.isTotal && propsTotal.fontColor) {
68298 style.fontColor = propsTotal.fontColor;
68299 }
68300 else {
68301 style.fontColor = rowBandingIndex % 2 === 0 ? props.fontColorPrimary : props.fontColorSecondary;
68302 }
68303 if (item.isTotal && propsTotal.backColor) {
68304 style.backColor = propsTotal.backColor;
68305 }
68306 else {
68307 style.backColor = rowBandingIndex % 2 === 0 ? props.backColorPrimary : props.backColorSecondary;
68308 }
68309 };
68310 MatrixBinder.prototype.unbindBodyCell = function (item, cell) {
68311 TablixUtils.clearCellStyle(cell);
68312 TablixUtils.clearCellTextAndTooltip(cell);
68313 };
68314 /**
68315 * Corner Cell.
68316 */
68317 MatrixBinder.prototype.bindCornerCell = function (item, cell) {
68318 TablixUtils.resetCellCssClass(cell);
68319 var cellStyle = new TablixUtils.CellStyle();
68320 cellStyle.fontFamily = TablixUtils.FontFamilyHeader;
68321 cellStyle.fontColor = TablixUtils.FontColorHeaders;
68322 cell.contentHeight = this.textHeightHeader;
68323 if (item.isColumnHeaderLeaf) {
68324 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixColumnHeaderLeaf);
68325 cellStyle.borders.bottom = new TablixUtils.EdgeSettings(TablixObjects.PropGridOutlineWeight.defaultValue, TablixObjects.PropGridOutlineColor.defaultValue);
68326 var cornerHeaderMetadata = this.getSortableCornerColumnMetadata(item);
68327 if (cornerHeaderMetadata)
68328 this.registerColumnHeaderClickHandler(cornerHeaderMetadata, cell);
68329 if (this.options.showSortIcons)
68330 TablixUtils.createColumnHeaderWithSortIcon(cornerHeaderMetadata, cell);
68331 else
68332 TablixUtils.setCellTextAndTooltip(cell, cornerHeaderMetadata.displayName);
68333 }
68334 else {
68335 var itemText = item.metadata ? item.metadata.displayName : '';
68336 TablixUtils.setCellTextAndTooltip(cell, itemText);
68337 }
68338 if (item.isRowHeaderLeaf) {
68339 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassMatrixRowHeaderLeaf);
68340 }
68341 TablixUtils.addCellCssClass(cell, TablixUtils.CssClassTablixHeader);
68342 this.setCornerCellsStyle(cell, cellStyle);
68343 cell.applyStyle(cellStyle);
68344 cell.extension.disableDragResize();
68345 };
68346 MatrixBinder.prototype.setCornerCellsStyle = function (cell, style) {
68347 var propsGrid = this.formattingProperties.grid;
68348 var propsCol = this.formattingProperties.columnHeaders;
68349 var propsRow = this.formattingProperties.rowHeaders;
68350 style.fontColor = propsCol.fontColor || propsRow.fontColor;
68351 style.backColor = propsCol.backColor || propsRow.backColor;
68352 style.paddings.top = style.paddings.bottom = propsGrid.rowPadding;
68353 style.borders.top = new TablixUtils.EdgeSettings();
68354 if (cell.position.row.isFirst) {
68355 style.borders.top.applyParams(visuals.outline.showTop(propsCol.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68356 } // else: do nothing
68357 style.borders.bottom = new TablixUtils.EdgeSettings();
68358 if (cell.position.row.isLast) {
68359 style.borders.bottom.applyParams(visuals.outline.showBottom(propsCol.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68360 }
68361 else {
68362 style.borders.bottom.applyParams(propsGrid.gridHorizontal, propsGrid.gridHorizontalWeight, propsGrid.gridHorizontalColor);
68363 }
68364 style.borders.left = new TablixUtils.EdgeSettings();
68365 if (cell.position.column.isFirst) {
68366 style.borders.left.applyParams(visuals.outline.showLeft(propsCol.outline), propsGrid.outlineWeight, propsGrid.outlineColor);
68367 // If we dont have left border, but Row Headers have, we need to apply extra padding
68368 if (!visuals.outline.showLeft(propsCol.outline) && visuals.outline.showLeft(propsRow.outline))
68369 style.paddings.left += propsGrid.outlineWeight;
68370 } // else: do nothing
68371 style.borders.right = new TablixUtils.EdgeSettings();
68372 style.borders.right.applyParams(propsGrid.gridVertical, propsGrid.gridVerticalWeight, propsGrid.gridVerticalColor);
68373 };
68374 MatrixBinder.prototype.unbindCornerCell = function (item, cell) {
68375 TablixUtils.clearCellStyle(cell);
68376 TablixUtils.clearCellTextAndTooltip(cell);
68377 if (this.options.showSortIcons)
68378 TablixUtils.removeSortIcons(cell);
68379 if (item.isColumnHeaderLeaf) {
68380 this.unregisterColumnHeaderClickHandler(cell);
68381 }
68382 };
68383 MatrixBinder.prototype.bindEmptySpaceHeaderCell = function (cell) {
68384 };
68385 MatrixBinder.prototype.unbindEmptySpaceHeaderCell = function (cell) {
68386 };
68387 MatrixBinder.prototype.bindEmptySpaceFooterCell = function (cell) {
68388 };
68389 MatrixBinder.prototype.unbindEmptySpaceFooterCell = function (cell) {
68390 };
68391 /**
68392 * Measurement Helper.
68393 */
68394 MatrixBinder.prototype.getHeaderLabel = function (item) {
68395 return MatrixBinder.getNodeLabel(item);
68396 };
68397 MatrixBinder.prototype.getCellContent = function (item) {
68398 return item.textContent || '';
68399 };
68400 MatrixBinder.prototype.hasRowGroups = function () {
68401 // Figure out whether we have a static row header, i.e., not row groups
68402 var dataView = this.hierarchyNavigator.getDataViewMatrix();
68403 if (!dataView || !dataView.rows || !dataView.rows.levels || dataView.rows.levels.length === 0)
68404 return false;
68405 return true;
68406 };
68407 MatrixBinder.getNodeLabel = function (node) {
68408 // Return formatted value
68409 if (node.name)
68410 return node.name;
68411 // Return unformatted value (fallback case)
68412 if (node.value != null)
68413 return node.value.toString();
68414 return '';
68415 };
68416 /**
68417 * Returns the column metadata of the column that needs to be sorted for the specified matrix corner node.
68418 *
68419 * @return Column metadata or null if the specified corner node does not represent a sortable header.
68420 */
68421 MatrixBinder.prototype.getSortableCornerColumnMetadata = function (item) {
68422 if (item.isColumnHeaderLeaf)
68423 return item.metadata;
68424 };
68425 MatrixBinder.prototype.getRowHeaderMetadata = function (item) {
68426 if (!this.hierarchyNavigator || !item)
68427 return;
68428 var dataView = this.hierarchyNavigator.getDataViewMatrix();
68429 if (!dataView || !dataView.rows)
68430 return;
68431 return this.getHierarchyMetadata(dataView.rows, item.level);
68432 };
68433 MatrixBinder.prototype.getColumnHeaderMetadata = function (item) {
68434 if (!this.hierarchyNavigator || !item)
68435 return;
68436 var dataView = this.hierarchyNavigator.getDataViewMatrix();
68437 if (!dataView || !dataView.columns)
68438 return;
68439 return this.getHierarchyMetadata(dataView.columns, item.level);
68440 };
68441 MatrixBinder.prototype.getHierarchyMetadata = function (hierarchy, level) {
68442 if (!hierarchy || !hierarchy.levels || hierarchy.levels.length < level)
68443 return;
68444 var levelInfo = hierarchy.levels[level];
68445 if (!levelInfo || !levelInfo.sources || levelInfo.sources.length === 0)
68446 return;
68447 // This assumes the source will always be the first item in the array of sources.
68448 return levelInfo.sources[0];
68449 };
68450 /**
68451 * Returns the column metadata of the column that needs to be sorted for the specified header node.
68452 *
68453 * @return Column metadata or null if the specified header node does not represent a sortable header.
68454 */
68455 MatrixBinder.prototype.getSortableHeaderColumnMetadata = function (item) {
68456 var dataView = this.hierarchyNavigator.getDataViewMatrix();
68457 // If there are no row groups, sorting is not supported (as it does not make sense).
68458 if (!dataView.rows || !dataView.rows.levels || dataView.rows.levels.length === 0)
68459 return null;
68460 var isMultiMeasure = dataView.valueSources && dataView.valueSources.length > 1;
68461 var columnGroupCount = dataView.columns ? dataView.columns.levels.length : 0;
68462 // If we have multiple values, they establish an extra level, so need to subtract 1
68463 if (isMultiMeasure) {
68464 columnGroupCount--;
68465 }
68466 else if (columnGroupCount === 1 &&
68467 dataView.columns.levels[0] &&
68468 dataView.columns.levels[0].sources && dataView.columns.levels[0].sources[0] &&
68469 dataView.columns.levels[0].sources[0].roles && dataView.columns.levels[0].sources[0].roles["Values"]) {
68470 columnGroupCount = 0;
68471 }
68472 var valueIndex = -1;
68473 if (columnGroupCount === 0) {
68474 // Matrices without column groups, support sorting on all columns (which are then measure columns).
68475 valueIndex = item.levelSourceIndex;
68476 }
68477 else if (item.isSubtotal) {
68478 // Matrices with column groups support sorting only on the column grand total.
68479 if (isMultiMeasure) {
68480 // In the multi-measure case we need to check if the parent's level is 0 in order
68481 // to determine whether this is the column grand total. The cells are layed out such
68482 // that the clickable cells are at the innermost level, but the parent for the column
68483 // grand total will have level 0.
68484 if (item.parent && item.parent.level === 0)
68485 valueIndex = item.levelSourceIndex;
68486 }
68487 else {
68488 // In the single-measure case we can directly check the level of the subtotal to
68489 // detect the column grand total (at level 0).
68490 if (item.level === 0)
68491 valueIndex = item.levelSourceIndex;
68492 }
68493 }
68494 if (valueIndex !== -1) {
68495 // NOTE: if the valueIndex is undefined it implicitly means that it is 0 based on the
68496 // visual node contract
68497 valueIndex = valueIndex ? valueIndex : 0;
68498 return dataView.valueSources[valueIndex];
68499 }
68500 return null;
68501 };
68502 return MatrixBinder;
68503 }());
68504 visuals.MatrixBinder = MatrixBinder;
68505 var Matrix = (function () {
68506 function Matrix(options) {
68507 if (options) {
68508 this.isTouchEnabled = options.isTouchEnabled;
68509 }
68510 }
68511 Matrix.customizeQuery = function (options) {
68512 var dataViewMapping = options.dataViewMappings[0];
68513 if (!dataViewMapping || !dataViewMapping.matrix || !dataViewMapping.metadata)
68514 return;
68515 var dataViewMatrix = dataViewMapping.matrix;
68516 // If Columns Hierarchy is not empty, set Window DataReduction Count to 100
68517 if (!_.isEmpty(dataViewMatrix.columns.for.in.items)) {
68518 dataViewMatrix.rows.dataReductionAlgorithm.window.count = 100;
68519 }
68520 var objects = dataViewMapping.metadata.objects;
68521 dataViewMatrix.rows.for.in.subtotalType = TablixObjects.shouldShowRowSubtotals(objects) ? 2 /* After */ : 0 /* None */;
68522 dataViewMatrix.columns.for.in.subtotalType = TablixObjects.shouldShowColumnSubtotals(objects) ? 2 /* After */ : 0 /* None */;
68523 };
68524 Matrix.getSortableRoles = function () {
68525 return ['Rows', 'Values'];
68526 };
68527 Matrix.prototype.init = function (options) {
68528 this.element = options.element;
68529 this.style = options.style;
68530 this.updateViewport(options.viewport);
68531 this.formatter = visuals.valueFormatter.formatValueColumn;
68532 this.isInteractive = options.interactivity && options.interactivity.selection != null;
68533 this.hostServices = options.host;
68534 this.persistingObjects = false;
68535 this.waitingForData = false;
68536 this.lastAllowHeaderResize = true;
68537 this.waitingForSort = false;
68538 };
68539 Matrix.converter = function (dataView) {
68540 debug.assertValue(dataView, 'dataView');
68541 return TablixObjects.getMatrixObjects(dataView);
68542 };
68543 Matrix.prototype.onResizing = function (finalViewport) {
68544 this.updateViewport(finalViewport);
68545 };
68546 /*
68547 Public for testing
68548 */
68549 Matrix.prototype.getColumnWidthManager = function () {
68550 return this.columnWidthManager;
68551 };
68552 Matrix.prototype.onDataChanged = function (options) {
68553 debug.assertValue(options, 'options');
68554 var dataViews = options.dataViews;
68555 if (dataViews && dataViews.length > 0) {
68556 var previousDataView = this.dataView;
68557 this.dataView = dataViews[0];
68558 // We don't check for persisting flag
68559 // Any change to the Column Widths need to go through to update all column group instances
68560 // ToDo: Consider not resetting scrollbar everytime
68561 var formattingProperties = Matrix.converter(this.dataView);
68562 var textSize = formattingProperties.general.textSize;
68563 if (options.operationKind === powerbi.VisualDataChangeOperationKind.Append) {
68564 var rootChanged = previousDataView.matrix.rows.root !== this.dataView.matrix.rows.root;
68565 this.hierarchyNavigator.update(this.dataView.matrix, rootChanged);
68566 // If Root for Rows or Columns has changed by the DataViewTransform (e.g. when having reorders in values)
68567 if (rootChanged)
68568 this.tablixControl.updateModels(/*resetScrollOffsets*/ false, this.dataView.matrix.rows.root.children, this.dataView.matrix.columns.root.children);
68569 this.refreshControl(/*clear*/ false);
68570 }
68571 else {
68572 this.createOrUpdateHierarchyNavigator();
68573 this.createColumnWidthManager();
68574 this.createTablixControl(textSize);
68575 var binder = this.tablixControl.getBinder();
68576 binder.onDataViewChanged(formattingProperties);
68577 this.updateInternal(textSize, previousDataView);
68578 }
68579 }
68580 this.waitingForData = false;
68581 this.waitingForSort = false;
68582 };
68583 Matrix.prototype.createColumnWidthManager = function () {
68584 var _this = this;
68585 var columnHierarchy = this.hierarchyNavigator.getMatrixColumnHierarchy();
68586 if (!this.columnWidthManager) {
68587 this.columnWidthManager = new visuals.controls.TablixColumnWidthManager(this.dataView, true /* isMatrix */, function (objectInstances) { return _this.persistColumnWidths(objectInstances); }, columnHierarchy.leafNodes);
68588 }
68589 else if (!this.persistingObjects) {
68590 this.columnWidthManager.updateDataView(this.dataView, columnHierarchy.leafNodes);
68591 }
68592 };
68593 Matrix.prototype.persistColumnWidths = function (objectInstances) {
68594 this.persistingObjects = true;
68595 this.hostServices.persistProperties(objectInstances);
68596 };
68597 Matrix.prototype.updateViewport = function (newViewport) {
68598 this.currentViewport = newViewport;
68599 if (this.tablixControl) {
68600 this.tablixControl.viewport = this.currentViewport;
68601 this.verifyHeaderResize();
68602 this.refreshControl(/*clear*/ false);
68603 }
68604 };
68605 Matrix.prototype.refreshControl = function (clear) {
68606 if (visuals.visibilityHelper.partiallyVisible(this.element) || this.getLayoutKind() === 1 /* DashboardTile */) {
68607 this.tablixControl.refresh(clear);
68608 }
68609 };
68610 Matrix.prototype.getLayoutKind = function () {
68611 return this.isInteractive ? 0 /* Canvas */ : 1 /* DashboardTile */;
68612 };
68613 Matrix.prototype.createOrUpdateHierarchyNavigator = function () {
68614 if (!this.tablixControl) {
68615 var matrixNavigator = createMatrixHierarchyNavigator(this.dataView.matrix, this.formatter);
68616 this.hierarchyNavigator = matrixNavigator;
68617 }
68618 else {
68619 this.hierarchyNavigator.update(this.dataView.matrix);
68620 }
68621 };
68622 Matrix.prototype.createTablixControl = function (textSize) {
68623 if (!this.tablixControl) {
68624 // Create the control
68625 this.tablixControl = this.createControl(this.hierarchyNavigator, textSize);
68626 }
68627 };
68628 Matrix.prototype.createControl = function (matrixNavigator, textSize) {
68629 var _this = this;
68630 var layoutKind = this.getLayoutKind();
68631 var matrixBinderOptions = {
68632 onBindRowHeader: function (item) { _this.onBindRowHeader(item); },
68633 totalLabel: this.hostServices.getLocalizedString(Matrix.TotalLabel),
68634 onColumnHeaderClick: function (queryName, sortDirection) { return _this.onColumnHeaderClick(queryName, sortDirection); },
68635 showSortIcons: layoutKind === 0 /* Canvas */,
68636 };
68637 var matrixBinder = new MatrixBinder(this.hierarchyNavigator, matrixBinderOptions);
68638 var layoutManager = layoutKind === 1 /* DashboardTile */
68639 ? visuals.controls.internal.DashboardTablixLayoutManager.createLayoutManager(matrixBinder)
68640 : visuals.controls.internal.CanvasTablixLayoutManager.createLayoutManager(matrixBinder, this.columnWidthManager);
68641 var tablixContainer = document.createElement('div');
68642 this.element.append(tablixContainer);
68643 var tablixOptions = {
68644 interactive: this.isInteractive,
68645 enableTouchSupport: this.isTouchEnabled,
68646 layoutKind: layoutKind,
68647 fontSize: TablixObjects.getTextSizeInPx(textSize),
68648 };
68649 return new visuals.controls.TablixControl(matrixNavigator, layoutManager, matrixBinder, tablixContainer, tablixOptions);
68650 };
68651 Matrix.prototype.updateInternal = function (textSize, previousDataView) {
68652 var _this = this;
68653 if (this.getLayoutKind() === 1 /* DashboardTile */) {
68654 this.tablixControl.layoutManager.adjustContentSize(visuals.converterHelper.hasImageUrlColumn(this.dataView));
68655 }
68656 this.tablixControl.fontSize = TablixObjects.getTextSizeInPx(textSize);
68657 this.verifyHeaderResize();
68658 /* To avoid resetting scrollbar every time we persist Objects. If:
68659 * AutoSizeColumns options was flipped
68660 * A Column was resized manually
68661 * A Column was auto-sized
68662 */
68663 // Update models before the viewport to make sure column widths are computed correctly
68664 // if a persisting operation is going, don't reset the scrollbar (column resize)
68665 this.tablixControl.updateModels(/*resetScrollOffsets*/ !this.persistingObjects, this.dataView.matrix.rows.root.children, this.dataView.matrix.columns.root.children);
68666 this.tablixControl.viewport = this.currentViewport;
68667 var shouldClearControl = this.shouldClearControl(previousDataView, this.dataView);
68668 // We need the layout for the DIV to be done so that the control can measure items correctly.
68669 setTimeout(function () {
68670 // Render
68671 _this.refreshControl(shouldClearControl);
68672 // At this point, all columns are rendered with proper width, reset the flag if it was raised
68673 if (_this.persistingObjects) {
68674 _this.persistingObjects = false;
68675 return;
68676 }
68677 // if AutoSize option was set to OFF, persist all columns width
68678 if (_this.columnWidthManager.shouldPersistAllColumnWidths()) {
68679 _this.columnWidthManager.persistAllColumnWidths(_this.tablixControl.layoutManager.columnWidthsToPersist);
68680 }
68681 }, 0);
68682 };
68683 Matrix.prototype.shouldClearControl = function (previousDataView, newDataView) {
68684 if (!this.waitingForSort || !previousDataView || !newDataView)
68685 return true;
68686 // ToDo: Get better criteria
68687 return !powerbi.DataViewAnalysis.isMetadataEquivalent(previousDataView.metadata, newDataView.metadata);
68688 };
68689 Matrix.prototype.onBindRowHeader = function (item) {
68690 if (this.needsMoreData(item)) {
68691 this.hostServices.loadMoreData();
68692 this.waitingForData = true;
68693 }
68694 };
68695 Matrix.prototype.onColumnHeaderClick = function (queryName, sortDirection) {
68696 this.waitingForSort = true;
68697 this.hostServices.onCustomSort(TablixUtils.getCustomSortEventArgs(queryName, sortDirection));
68698 };
68699 /**
68700 * Note: Public for testability.
68701 */
68702 Matrix.prototype.needsMoreData = function (item) {
68703 if (this.waitingForData || !this.hierarchyNavigator.isLeaf(item) || !this.dataView.metadata || !this.dataView.metadata.segment)
68704 return false;
68705 var leafCount = this.tablixControl.rowDimension.getItemsCount();
68706 var loadMoreThreshold = leafCount * Matrix.preferredLoadMoreThreshold;
68707 return this.hierarchyNavigator.getLeafIndex(item) >= loadMoreThreshold;
68708 };
68709 Matrix.prototype.enumerateObjectInstances = function (options) {
68710 var enumeration = new visuals.ObjectEnumerationBuilder();
68711 // Visuals are initialized with an empty data view before queries are run, therefore we need to make sure that
68712 // we are resilient here when we do not have data view.
68713 if (this.dataView) {
68714 TablixObjects.enumerateObjectInstances(options, enumeration, this.dataView, visuals.controls.TablixType.Matrix);
68715 }
68716 return enumeration.complete();
68717 };
68718 Matrix.prototype.shouldAllowHeaderResize = function () {
68719 return this.hostServices.getViewMode() === 1 /* Edit */;
68720 };
68721 Matrix.prototype.onViewModeChanged = function (viewMode) {
68722 /* Refreshes the column headers to enable/disable Column resizing */
68723 this.updateViewport(this.currentViewport);
68724 };
68725 Matrix.prototype.verifyHeaderResize = function () {
68726 var currentAllowHeaderResize = this.shouldAllowHeaderResize();
68727 if (currentAllowHeaderResize !== this.lastAllowHeaderResize) {
68728 this.lastAllowHeaderResize = currentAllowHeaderResize;
68729 this.tablixControl.layoutManager.setAllowHeaderResize(currentAllowHeaderResize);
68730 }
68731 };
68732 Matrix.preferredLoadMoreThreshold = 0.8;
68733 /**
68734 * Note: Public only for testing.
68735 */
68736 Matrix.TotalLabel = 'TableTotalLabel';
68737 return Matrix;
68738 }());
68739 visuals.Matrix = Matrix;
68740 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
68741})(powerbi || (powerbi = {}));
68742/*
68743 * Power BI Visualizations
68744 *
68745 * Copyright (c) Microsoft Corporation
68746 * All rights reserved.
68747 * MIT License
68748 *
68749 * Permission is hereby granted, free of charge, to any person obtaining a copy
68750 * of this software and associated documentation files (the ""Software""), to deal
68751 * in the Software without restriction, including without limitation the rights
68752 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
68753 * copies of the Software, and to permit persons to whom the Software is
68754 * furnished to do so, subject to the following conditions:
68755 *
68756 * The above copyright notice and this permission notice shall be included in
68757 * all copies or substantial portions of the Software.
68758 *
68759 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68760 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68761 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68762 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68763 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
68764 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
68765 * THE SOFTWARE.
68766 */
68767var powerbi;
68768(function (powerbi) {
68769 var visuals;
68770 (function (visuals) {
68771 var CssConstants = jsCommon.CssConstants;
68772 /**
68773 * Renders an interactive treemap visual from categorical data.
68774 */
68775 var Treemap = (function () {
68776 function Treemap(options) {
68777 this.tooltipsEnabled = options && options.tooltipsEnabled;
68778 if (options && options.animator) {
68779 this.animator = options.animator;
68780 this.isScrollable = options.isScrollable ? options.isScrollable : false;
68781 this.behavior = options.behavior;
68782 }
68783 }
68784 Treemap.getLayout = function (labelsSettings, alternativeScale) {
68785 var formattersCache = visuals.dataLabelUtils.createColumnFormatterCacheManager();
68786 var majorLabelsEnabled = labelsSettings.showCategory;
68787 var minorLabelsEnabled = labelsSettings.show || labelsSettings.showCategory;
68788 return {
68789 shapeClass: function (d) { return Treemap.getNodeClass(d, false); },
68790 shapeLayout: Treemap.createTreemapShapeLayout(false),
68791 highlightShapeClass: function (d) { return Treemap.getNodeClass(d, true); },
68792 highlightShapeLayout: Treemap.createTreemapShapeLayout(true),
68793 zeroShapeLayout: Treemap.createTreemapZeroShapeLayout(),
68794 majorLabelClass: function (d) { return Treemap.MajorLabelClassName; },
68795 majorLabelLayout: {
68796 x: function (d) { return d.x + Treemap.TextMargin; },
68797 y: function (d) { return d.y + Treemap.TextMargin + Treemap.MajorLabelTextSize; },
68798 },
68799 majorLabelText: function (d) { return Treemap.createMajorLabelText(d, labelsSettings, alternativeScale, formattersCache); },
68800 minorLabelClass: function (d) { return Treemap.MinorLabelClassName; },
68801 minorLabelLayout: {
68802 x: function (d) { return d.x + Treemap.TextMargin; },
68803 y: function (d) { return d.y + d.dy - Treemap.TextMargin; },
68804 },
68805 minorLabelText: function (d) { return Treemap.createMinorLabelText(d, labelsSettings, alternativeScale, formattersCache); },
68806 areMajorLabelsEnabled: function () { return majorLabelsEnabled; },
68807 areMinorLabelsEnabled: function () { return minorLabelsEnabled; },
68808 };
68809 };
68810 Treemap.prototype.init = function (options) {
68811 this.options = options;
68812 var element = options.element;
68813 // Ensure viewport is empty on init
68814 element.empty();
68815 this.svg = d3.select(element.get(0))
68816 .append('svg')
68817 .style('position', 'absolute')
68818 .classed(Treemap.ClassName, true);
68819 this.shapeGraphicsContext = this.svg
68820 .append('g')
68821 .classed(Treemap.ShapesClassName, true);
68822 this.labelGraphicsContext = this.svg
68823 .append('g')
68824 .classed(Treemap.LabelsGroupClassName, true);
68825 this.element = element;
68826 // avoid deep copy
68827 this.currentViewport = {
68828 height: options.viewport.height,
68829 width: options.viewport.width,
68830 };
68831 this.style = options.style;
68832 this.treemap = d3.layout.treemap()
68833 .sticky(false)
68834 .sort(function (a, b) { return a.size - b.size; })
68835 .value(function (d) { return d.size; })
68836 .round(false);
68837 if (this.behavior) {
68838 this.interactivityService = visuals.createInteractivityService(options.host);
68839 }
68840 this.legend = visuals.createLegend(element, options.interactivity && options.interactivity.isInteractiveLegend, this.interactivityService, this.isScrollable);
68841 this.colors = this.style.colorPalette.dataColors;
68842 this.hostService = options.host;
68843 };
68844 /**
68845 * Note: Public for testing purposes.
68846 */
68847 Treemap.converter = function (dataView, colors, labelSettings, interactivityService, viewport, legendObjectProperties, tooltipsEnabled) {
68848 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
68849 var reader = powerbi.data.createIDataViewCategoricalReader(dataView);
68850 var rootNode = {
68851 key: "root",
68852 name: "root",
68853 children: [],
68854 selected: false,
68855 highlightMultiplier: 0,
68856 identity: visuals.SelectionId.createNull(),
68857 color: undefined,
68858 };
68859 var allNodes = [];
68860 var hasHighlights;
68861 var legendDataPoints = [];
68862 var legendTitle = "";
68863 var colorHelper = new visuals.ColorHelper(colors, visuals.treemapProps.dataPoint.fill);
68864 var dataWasCulled = undefined;
68865 if (dataView && dataView.metadata && dataView.metadata.objects) {
68866 var objects = dataView.metadata.objects;
68867 labelSettings.show = powerbi.DataViewObjects.getValue(objects, visuals.treemapProps.labels.show, labelSettings.show);
68868 labelSettings.labelColor = powerbi.DataViewObjects.getFillColor(objects, visuals.treemapProps.labels.color, labelSettings.labelColor);
68869 labelSettings.displayUnits = powerbi.DataViewObjects.getValue(objects, visuals.treemapProps.labels.labelDisplayUnits, labelSettings.displayUnits);
68870 labelSettings.precision = powerbi.DataViewObjects.getValue(objects, visuals.treemapProps.labels.labelPrecision, labelSettings.precision);
68871 labelSettings.showCategory = powerbi.DataViewObjects.getValue(objects, visuals.treemapProps.categoryLabels.show, labelSettings.showCategory);
68872 }
68873 if (dataView && dataView.categorical && dataView.categorical.values) {
68874 var categorical = dataView.categorical;
68875 var valueColumns = categorical.values;
68876 hasHighlights = !!(valueColumns.length > 0 && valueColumns[0].highlights);
68877 var formatStringProp = visuals.treemapProps.general.formatString;
68878 var result = Treemap.getValuesFromCategoricalDataView(categorical, hasHighlights);
68879 var values = result.values;
68880 var highlights = result.highlights;
68881 var totalValue = result.totalValue;
68882 if (result.highlightsOverflow) {
68883 hasHighlights = false;
68884 values = highlights;
68885 }
68886 var cullableValue = Treemap.getCullableValue(totalValue, viewport);
68887 var grouped = valueColumns.grouped();
68888 var isMultiSeries = grouped && grouped.length > 0 && grouped[0].values && grouped[0].values.length > 1;
68889 var hasDynamicSeries = !!valueColumns.source;
68890 dataWasCulled = false;
68891 var shouldCullValue = undefined;
68892 var gradientValueColumn = visuals.GradientUtils.getGradientValueColumn(categorical);
68893 if ((categorical.categories == null) && !_.isEmpty(values)) {
68894 // No categories, sliced by series and measures
68895 for (var i = 0, ilen = values[0].length; i < ilen; i++) {
68896 var valueColumn = valueColumns[i];
68897 if (!powerbi.data.DataRoleHelper.hasRoleInValueColumn(valueColumn, Treemap.ValuesRoleName)) {
68898 continue;
68899 }
68900 var value = values[0][i];
68901 if (!Treemap.checkValueForShape(value)) {
68902 continue;
68903 }
68904 if (value < cullableValue) {
68905 dataWasCulled = dataWasCulled || shouldCullValue;
68906 continue;
68907 }
68908 var nodeName = hasDynamicSeries ? reader.getSeriesValueColumnGroup(i).name : visuals.converterHelper.formatFromMetadataColumn(reader.getValueDisplayName("Values", i), valueColumn.source, formatStringProp);
68909 var identity = new visuals.SelectionIdBuilder()
68910 .withSeries(valueColumns, hasDynamicSeries ? valueColumns[i] : undefined)
68911 .withMeasure(valueColumns[i].source.queryName)
68912 .createSelectionId();
68913 var key = identity.getKey();
68914 var color = hasDynamicSeries
68915 ? colorHelper.getColorForSeriesValue(grouped[i] && grouped[i].objects, categorical.values.identityFields, visuals.converterHelper.getSeriesName(valueColumn.source))
68916 : colorHelper.getColorForMeasure(valueColumn.source.objects, valueColumn.source.queryName);
68917 var highlightedValue = hasHighlights ? highlights[0][i] : undefined;
68918 var tooltipInfo = void 0;
68919 if (tooltipsEnabled) {
68920 tooltipInfo = [];
68921 if (hasDynamicSeries) {
68922 var seriesMetadataColumn = reader.getSeriesMetadataColumn();
68923 var seriesValue = reader.getSeriesValueColumnGroup(i).name;
68924 tooltipInfo.push({
68925 displayName: seriesMetadataColumn.displayName,
68926 value: visuals.converterHelper.formatFromMetadataColumn(seriesValue, seriesMetadataColumn, formatStringProp),
68927 });
68928 }
68929 if (value != null) {
68930 tooltipInfo.push({
68931 displayName: valueColumn.source.displayName,
68932 value: visuals.converterHelper.formatFromMetadataColumn(value, valueColumn.source, formatStringProp),
68933 });
68934 }
68935 if (highlightedValue != null) {
68936 tooltipInfo.push({
68937 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
68938 value: visuals.converterHelper.formatFromMetadataColumn(highlightedValue, valueColumn.source, formatStringProp),
68939 });
68940 }
68941 }
68942 var node = {
68943 key: key,
68944 name: nodeName,
68945 size: value,
68946 color: color,
68947 selected: false,
68948 identity: identity,
68949 tooltipInfo: tooltipInfo,
68950 highlightedTooltipInfo: tooltipInfo,
68951 labelFormatString: visuals.valueFormatter.getFormatString(valueColumn.source, formatStringProp),
68952 };
68953 if (hasHighlights && highlights) {
68954 node.highlightMultiplier = value !== 0 ? highlights[0][i] / value : 0;
68955 node.highlightValue = highlights[0][i];
68956 }
68957 rootNode.children.push(node);
68958 allNodes.push(node);
68959 legendDataPoints.push({
68960 label: nodeName,
68961 color: color,
68962 icon: visuals.LegendIcon.Box,
68963 identity: identity,
68964 selected: false
68965 });
68966 }
68967 }
68968 else if (categorical.categories && categorical.categories.length > 0) {
68969 // Count the columns that have the value roles
68970 var valueColumnCount = _.filter(valueColumns, function (x) { return x.source && x.source.roles && x.source.roles[Treemap.ValuesRoleName] === true; }).length;
68971 // Do not add second level if it's one and only one data point per shape and it's not a group value
68972 // e.g. Category/Series group plus only one Value field (excluding the gradient)
68973 var omitSecondLevel = valueColumnCount === 1 && (valueColumns[0].source.groupName == null);
68974 // Create the first level from categories
68975 var categoryColumn = categorical.categories[0];
68976 legendTitle = categoryColumn.source.displayName;
68977 var categoryFormat = visuals.valueFormatter.getFormatString(categoryColumn.source, formatStringProp);
68978 for (var categoryIndex = 0, categoryLen = values.length; categoryIndex < categoryLen; categoryIndex++) {
68979 var objects = categoryColumn.objects && categoryColumn.objects[categoryIndex];
68980 var color = colorHelper.getColorForSeriesValue(objects, categoryColumn.identityFields, categoryColumn.values[categoryIndex]);
68981 var categoryValue = visuals.valueFormatter.format(categoryColumn.values[categoryIndex], categoryFormat);
68982 var currentValues = values[categoryIndex];
68983 // This section area builds the tooltip for the parent node. It's only displayed if the node doesn't have any children (essentially if omitSecondLevel is true).
68984 // seriesIndex is the index of the 1st series with the role Values.
68985 var seriesIndex = powerbi.data.DataRoleHelper.getMeasureIndexOfRole(grouped, Treemap.ValuesRoleName);
68986 var value = currentValues[seriesIndex];
68987 var highlightValue = hasHighlights && highlights ? highlights[categoryIndex][seriesIndex] : undefined;
68988 var tooltipInfo = void 0;
68989 var categoryTooltipItem = void 0;
68990 if (tooltipsEnabled) {
68991 tooltipInfo = [];
68992 categoryTooltipItem = {
68993 displayName: categoryColumn.source.displayName,
68994 value: categoryValue,
68995 };
68996 tooltipInfo.push(categoryTooltipItem);
68997 var valueColumnMetadata = void 0;
68998 if (value != null) {
68999 valueColumnMetadata = valueColumns[seriesIndex].source;
69000 tooltipInfo.push({
69001 displayName: valueColumnMetadata.displayName,
69002 value: visuals.converterHelper.formatFromMetadataColumn(value, valueColumnMetadata, formatStringProp),
69003 });
69004 }
69005 if (highlightValue != null) {
69006 tooltipInfo.push({
69007 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
69008 value: visuals.converterHelper.formatFromMetadataColumn(highlightValue, valueColumnMetadata, formatStringProp),
69009 });
69010 }
69011 var gradientValueColumnMetadata = gradientValueColumn ? gradientValueColumn.source : undefined;
69012 if (omitSecondLevel && gradientValueColumnMetadata && gradientValueColumnMetadata !== valueColumnMetadata && gradientValueColumn.values[categoryIndex] != null) {
69013 tooltipInfo.push({
69014 displayName: gradientValueColumnMetadata.displayName,
69015 value: visuals.converterHelper.formatFromMetadataColumn(gradientValueColumn.values[categoryIndex], gradientValueColumnMetadata, formatStringProp),
69016 });
69017 }
69018 }
69019 var identity = visuals.SelectionIdBuilder.builder()
69020 .withCategory(categoryColumn, categoryIndex)
69021 .withMeasure(omitSecondLevel ? valueColumns[seriesIndex].source.queryName : undefined)
69022 .createSelectionId();
69023 var key = JSON.stringify({ nodeKey: identity.getKey(), depth: 1 });
69024 var node = {
69025 key: key,
69026 name: categoryValue,
69027 color: color,
69028 selected: false,
69029 identity: identity,
69030 tooltipInfo: tooltipInfo,
69031 highlightedTooltipInfo: tooltipInfo,
69032 labelFormatString: valueColumnCount === 1 ? visuals.valueFormatter.getFormatString(valueColumns[seriesIndex].source, formatStringProp) : categoryFormat,
69033 };
69034 if (hasHighlights) {
69035 node.highlightMultiplier = value !== 0 ? highlightValue / value : 0;
69036 node.highlightValue = highlightValue;
69037 }
69038 legendDataPoints.push({
69039 label: categoryValue,
69040 color: color,
69041 icon: visuals.LegendIcon.Box,
69042 identity: identity,
69043 selected: false
69044 });
69045 var total = 0;
69046 var highlightTotal = 0; // Used if omitting second level
69047 for (var j = 0, jlen = currentValues.length; j < jlen; j++) {
69048 var valueColumn = valueColumns[j];
69049 if (!powerbi.data.DataRoleHelper.hasRoleInValueColumn(valueColumn, Treemap.ValuesRoleName)) {
69050 continue;
69051 }
69052 var value_1 = currentValues[j];
69053 var highlight = void 0;
69054 shouldCullValue = value_1 < cullableValue;
69055 if (!Treemap.checkValueForShape(value_1) || shouldCullValue) {
69056 dataWasCulled = dataWasCulled || shouldCullValue;
69057 continue;
69058 }
69059 total += value_1;
69060 if (hasHighlights) {
69061 highlight = highlights[categoryIndex][j];
69062 highlightTotal += highlight;
69063 }
69064 if (!omitSecondLevel) {
69065 var childName = null;
69066 if (isMultiSeries) {
69067 // Measure: use name and index
69068 childName = valueColumn.source.displayName;
69069 }
69070 else {
69071 // Series group instance
69072 childName = valueColumn.source.groupName;
69073 }
69074 var categoricalValues = categorical ? categorical.values : null;
69075 var measureId = valueColumn.source.queryName;
69076 var childIdentity = visuals.SelectionIdBuilder.builder()
69077 .withCategory(categoryColumn, categoryIndex)
69078 .withSeries(categoricalValues, valueColumn)
69079 .withMeasure(measureId)
69080 .createSelectionId();
69081 var childKey = JSON.stringify({ nodeKey: childIdentity.getKey(), depth: 2 });
69082 var highlightedValue = hasHighlights && highlight !== 0 ? highlight : undefined;
69083 var tooltipInfo_1 = void 0;
69084 if (tooltipsEnabled) {
69085 tooltipInfo_1 = [];
69086 tooltipInfo_1.push(categoryTooltipItem);
69087 if (hasDynamicSeries) {
69088 if (!categoryColumn || categoryColumn.source !== categoricalValues.source) {
69089 // Category/series on the same column -- don't repeat its value in the tooltip.
69090 tooltipInfo_1.push({
69091 displayName: categoricalValues.source.displayName,
69092 value: visuals.converterHelper.formatFromMetadataColumn(grouped[j].name, categoricalValues.source, formatStringProp),
69093 });
69094 }
69095 }
69096 if (value_1 != null) {
69097 tooltipInfo_1.push({
69098 displayName: valueColumn.source.displayName,
69099 value: visuals.converterHelper.formatFromMetadataColumn(value_1, valueColumn.source, formatStringProp),
69100 });
69101 }
69102 if (highlightValue != null) {
69103 tooltipInfo_1.push({
69104 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
69105 value: visuals.converterHelper.formatFromMetadataColumn(highlightedValue, valueColumn.source, formatStringProp),
69106 });
69107 }
69108 }
69109 var childNode = {
69110 key: childKey,
69111 name: childName,
69112 size: value_1,
69113 color: color,
69114 selected: false,
69115 identity: childIdentity,
69116 tooltipInfo: tooltipInfo_1,
69117 highlightedTooltipInfo: tooltipInfo_1,
69118 labelFormatString: visuals.valueFormatter.getFormatString(valueColumn.source, formatStringProp),
69119 };
69120 if (hasHighlights) {
69121 childNode.highlightMultiplier = value_1 !== 0 ? highlight / value_1 : 0;
69122 childNode.highlightValue = highlight;
69123 }
69124 if (node.children == null)
69125 node.children = [];
69126 node.children.push(childNode);
69127 allNodes.push(childNode);
69128 }
69129 }
69130 if (Treemap.checkValueForShape(total)) {
69131 node.size = total;
69132 rootNode.children.push(node);
69133 allNodes.push(node);
69134 }
69135 if (hasHighlights)
69136 node.highlightMultiplier = total ? highlightTotal / total : 0;
69137 }
69138 }
69139 }
69140 if (interactivityService) {
69141 interactivityService.applySelectionStateToData(allNodes);
69142 interactivityService.applySelectionStateToData(legendDataPoints);
69143 }
69144 return {
69145 root: rootNode,
69146 hasHighlights: hasHighlights,
69147 legendData: { title: legendTitle, dataPoints: legendDataPoints, fontSize: visuals.SVGLegend.DefaultFontSizeInPt },
69148 dataLabelsSettings: labelSettings,
69149 legendObjectProperties: legendObjectProperties,
69150 dataWasCulled: dataWasCulled,
69151 };
69152 };
69153 Treemap.getValuesFromCategoricalDataView = function (data, hasHighlights) {
69154 var valueColumns = data.values;
69155 var categoryValueCount;
69156 if (valueColumns && (data.categories == null)) {
69157 categoryValueCount = 1; // We only get the first value out of each valueColumn since we don't have a category
69158 }
69159 else if (valueColumns && data.categories && data.categories.length > 0) {
69160 categoryValueCount = data.categories[0].values.length;
69161 }
69162 var values = [];
69163 var highlights = [];
69164 var totalValue = 0;
69165 for (var i = 0; i < categoryValueCount; i++) {
69166 values.push([]);
69167 if (hasHighlights)
69168 highlights.push([]);
69169 }
69170 var highlightsOverflow;
69171 for (var j = 0; j < valueColumns.length; j++) {
69172 var valueColumn = valueColumns[j];
69173 for (var i = 0; i < categoryValueCount; i++) {
69174 var value = valueColumn.values[i];
69175 values[i].push(value);
69176 totalValue += isNaN(value) ? 0 : value;
69177 if (hasHighlights) {
69178 var highlight = valueColumn.highlights[i];
69179 if (!highlight)
69180 highlight = 0;
69181 highlights[i].push(highlight);
69182 if (highlight > value)
69183 highlightsOverflow = true;
69184 }
69185 }
69186 }
69187 return {
69188 values: values,
69189 highlights: hasHighlights ? highlights : undefined,
69190 highlightsOverflow: hasHighlights ? highlightsOverflow : undefined,
69191 totalValue: totalValue,
69192 };
69193 };
69194 Treemap.getCullableValue = function (totalValue, viewport) {
69195 var totalArea = viewport.width * viewport.height;
69196 var culledPercent = Treemap.CullableArea / totalArea;
69197 return culledPercent * totalValue;
69198 };
69199 Treemap.prototype.update = function (options) {
69200 debug.assertValue(options, 'options');
69201 var dataViews = this.dataViews = options.dataViews;
69202 this.currentViewport = options.viewport;
69203 var dataViewCategorical = dataViews && dataViews.length > 0 && dataViews[0].categorical ? dataViews[0].categorical : undefined;
69204 var labelSettings = visuals.dataLabelUtils.getDefaultTreemapLabelSettings();
69205 var legendObjectProperties = null;
69206 if (dataViewCategorical) {
69207 var dataView = dataViews[0];
69208 var dataViewMetadata = dataView.metadata;
69209 var objects = void 0;
69210 if (dataViewMetadata)
69211 objects = dataViewMetadata.objects;
69212 if (objects) {
69213 legendObjectProperties = objects['legend'];
69214 }
69215 this.data = Treemap.converter(dataView, this.colors, labelSettings, this.interactivityService, this.currentViewport, legendObjectProperties, this.tooltipsEnabled);
69216 }
69217 else {
69218 var rootNode = {
69219 key: "root",
69220 name: "root",
69221 children: [],
69222 selected: false,
69223 highlightMultiplier: 0,
69224 identity: visuals.SelectionId.createNull(),
69225 color: undefined,
69226 };
69227 var legendData = { title: "", dataPoints: [] };
69228 var treeMapData = {
69229 root: rootNode,
69230 hasHighlights: false,
69231 legendData: legendData,
69232 dataLabelsSettings: labelSettings,
69233 dataWasCulled: false,
69234 };
69235 this.data = treeMapData;
69236 }
69237 this.updateInternal(options.suppressAnimations);
69238 if (dataViews) {
69239 var warnings = visuals.getInvalidValueWarnings(dataViews, false /*supportsNaN*/, false /*supportsNegativeInfinity*/, false /*supportsPositiveInfinity*/);
69240 this.hostService.setWarnings(warnings);
69241 }
69242 };
69243 // TODO: Remove this once all visuals have implemented update.
69244 Treemap.prototype.onDataChanged = function (options) {
69245 this.update({
69246 suppressAnimations: options.suppressAnimations,
69247 dataViews: options.dataViews,
69248 viewport: this.currentViewport
69249 });
69250 };
69251 // TODO: Remove this once all visuals have implemented update.
69252 Treemap.prototype.onResizing = function (viewport) {
69253 this.update({
69254 suppressAnimations: true,
69255 dataViews: this.dataViews,
69256 viewport: viewport
69257 });
69258 };
69259 Treemap.prototype.onClearSelection = function () {
69260 if (this.interactivityService)
69261 this.interactivityService.clearSelection();
69262 };
69263 Treemap.prototype.enumerateObjectInstances = function (options) {
69264 var data = this.data;
69265 if (!data)
69266 return;
69267 var objectName = options.objectName, enumeration = new visuals.ObjectEnumerationBuilder();
69268 var dataLabelsSettings = this.data.dataLabelsSettings
69269 ? this.data.dataLabelsSettings
69270 : visuals.dataLabelUtils.getDefaultTreemapLabelSettings();
69271 switch (objectName) {
69272 case 'dataPoint':
69273 var dataViewCat = this.dataViews && this.dataViews.length > 0 && this.dataViews[0] && this.dataViews[0].categorical;
69274 var hasGradientRole = visuals.GradientUtils.hasGradientRole(dataViewCat);
69275 if (!hasGradientRole)
69276 this.enumerateDataPoints(enumeration, data);
69277 break;
69278 case 'legend':
69279 return this.enumerateLegend(data);
69280 case 'labels':
69281 var labelSettingOptions = {
69282 enumeration: enumeration,
69283 dataLabelsSettings: dataLabelsSettings,
69284 show: true,
69285 displayUnits: true,
69286 precision: true,
69287 };
69288 visuals.dataLabelUtils.enumerateDataLabels(labelSettingOptions);
69289 break;
69290 case 'categoryLabels':
69291 visuals.dataLabelUtils.enumerateCategoryLabels(enumeration, dataLabelsSettings, false /* withFill */, true /* isShowCategory */);
69292 break;
69293 }
69294 return enumeration.complete();
69295 };
69296 Treemap.prototype.enumerateDataPoints = function (enumeration, data) {
69297 var rootChildren = data.root.children;
69298 if (_.isEmpty(rootChildren))
69299 return;
69300 for (var y = 0; y < rootChildren.length; y++) {
69301 var treemapNode = rootChildren[y];
69302 enumeration.pushInstance({
69303 displayName: treemapNode.name,
69304 selector: visuals.ColorHelper.normalizeSelector(treemapNode.identity.getSelector()),
69305 properties: {
69306 fill: { solid: { color: treemapNode.color } }
69307 },
69308 objectName: 'dataPoint'
69309 });
69310 }
69311 };
69312 Treemap.prototype.enumerateLegend = function (data) {
69313 var legendObjectProperties = { legend: data.legendObjectProperties };
69314 var show = powerbi.DataViewObjects.getValue(legendObjectProperties, visuals.treemapProps.legend.show, this.legend.isVisible());
69315 var showTitle = powerbi.DataViewObjects.getValue(legendObjectProperties, visuals.treemapProps.legend.showTitle, true);
69316 var titleText = powerbi.DataViewObjects.getValue(legendObjectProperties, visuals.treemapProps.legend.titleText, this.data.legendData.title);
69317 var labelColor = powerbi.DataViewObject.getValue(legendObjectProperties, visuals.legendProps.labelColor, this.data.legendData ? this.data.legendData.labelColor : visuals.LegendData.DefaultLegendLabelFillColor);
69318 var labelFontSize = powerbi.DataViewObject.getValue(legendObjectProperties, visuals.legendProps.fontSize, this.data.legendData && this.data.legendData.fontSize ? this.data.legendData.fontSize : visuals.SVGLegend.DefaultFontSizeInPt);
69319 return [{
69320 selector: null,
69321 objectName: 'legend',
69322 properties: {
69323 show: show,
69324 position: visuals.LegendPosition[this.legend.getOrientation()],
69325 showTitle: showTitle,
69326 titleText: titleText,
69327 labelColor: labelColor,
69328 fontSize: labelFontSize,
69329 }
69330 }];
69331 };
69332 Treemap.checkValueForShape = function (value) {
69333 if (!value)
69334 return false;
69335 return value > 0;
69336 };
69337 Treemap.prototype.calculateTreemapSize = function () {
69338 var legendMargins = this.legend.getMargins();
69339 return {
69340 height: this.currentViewport.height - legendMargins.height,
69341 width: this.currentViewport.width - legendMargins.width
69342 };
69343 };
69344 Treemap.prototype.initViewportDependantProperties = function (duration) {
69345 if (duration === void 0) { duration = 0; }
69346 var viewport = this.calculateTreemapSize();
69347 this.svg.attr({
69348 width: viewport.width,
69349 height: viewport.height
69350 });
69351 visuals.Legend.positionChartArea(this.svg, this.legend);
69352 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
69353 };
69354 Treemap.hasChildrenWithIdentity = function (node) {
69355 var children = node.children;
69356 if (!children)
69357 return false;
69358 var count = children.length;
69359 if (count === 0)
69360 return false;
69361 for (var i = count - 1; i >= 0; i--) {
69362 if (children[i].identity.hasIdentity())
69363 return true;
69364 }
69365 return false;
69366 };
69367 Treemap.canDisplayMajorLabel = function (node) {
69368 // Only display major labels for level 1
69369 if (node.depth !== 1)
69370 return false;
69371 if (_.isEmpty(node.name))
69372 return false;
69373 // Check if the room is enough for text with or without ellipse
69374 var availableWidth = node.dx - Treemap.TextMargin * 2;
69375 if (availableWidth < Treemap.MinTextWidthForMajorLabel)
69376 return false;
69377 // Check if the shape is high enough for label
69378 var textHeightWithMargin = Treemap.MajorLabelTextSize + Treemap.TextMargin * 2;
69379 if (node.dy < textHeightWithMargin)
69380 return false;
69381 return true;
69382 };
69383 Treemap.canDisplayMinorLabel = function (node, labelSettings) {
69384 // Only display minor labels for level 1 and 2
69385 if (node.depth < 1 || node.depth > 2)
69386 return false;
69387 // If a depth 1 node has children or is not showing data labels, do not show minor labels
69388 if (node.depth === 1 && (node.children || !labelSettings.show)) {
69389 return false;
69390 }
69391 if (_.isEmpty(node.name))
69392 return false;
69393 // Check if the room is enough for text with or without ellipse
69394 var availableWidth = node.dx - Treemap.TextMargin * 2;
69395 if (availableWidth < Treemap.MinTextWidthForMinorLabel)
69396 return false;
69397 // Check if the shape is high enough for label
69398 var textHeightWithMargin = Treemap.MinorLabelTextSize + Treemap.TextMargin * 2;
69399 if (node.dy < textHeightWithMargin)
69400 return false;
69401 if (node.depth === 1) {
69402 var roomTop = node.y + Treemap.MajorLabelTextSize + Treemap.TextMargin * 2;
69403 if (node.y + node.dy - roomTop < textHeightWithMargin)
69404 return false;
69405 }
69406 else if (node.depth === 2) {
69407 var parent_1 = node.parent;
69408 var roomTop = Math.max(parent_1.y + Treemap.MajorLabelTextSize + Treemap.TextMargin * 2, node.y);
69409 // Parent's label needs the room
69410 if (node.y + node.dy - roomTop < textHeightWithMargin)
69411 return false;
69412 }
69413 return true;
69414 };
69415 Treemap.createMajorLabelText = function (node, labelsSettings, alternativeScale, formattersCache) {
69416 var spaceAvaliableForLabels = node.dx - Treemap.TextMargin * 2;
69417 var baseTextProperties = Treemap.MajorLabelTextProperties;
69418 var textProperties = {
69419 text: node.name,
69420 fontFamily: baseTextProperties.fontFamily,
69421 fontSize: baseTextProperties.fontSize
69422 };
69423 return powerbi.TextMeasurementService.getTailoredTextOrDefault(textProperties, spaceAvaliableForLabels);
69424 };
69425 Treemap.createMinorLabelText = function (node, labelsSettings, alternativeScale, formattersCache) {
69426 var spaceAvaliableForLabels = node.dx - Treemap.TextMargin * 2;
69427 var label = node.name;
69428 if (labelsSettings.show) {
69429 var measureFormatter = formattersCache.getOrCreate(node.labelFormatString, labelsSettings, alternativeScale);
69430 // Create measure label
69431 label = visuals.dataLabelUtils.getLabelFormattedText({
69432 label: node.highlightValue != null ? node.highlightValue : node.value, maxWidth: spaceAvaliableForLabels, formatter: measureFormatter
69433 });
69434 // Add category if needed (we're showing category and the node depth is 2)
69435 if (labelsSettings.showCategory && node.depth === 2)
69436 label = visuals.dataLabelUtils.getLabelFormattedText({
69437 label: node.name,
69438 maxWidth: spaceAvaliableForLabels
69439 }) + " " + label;
69440 }
69441 return visuals.dataLabelUtils.getLabelFormattedText({
69442 label: label,
69443 maxWidth: spaceAvaliableForLabels,
69444 fontSize: labelsSettings.fontSize
69445 });
69446 };
69447 Treemap.getFill = function (d, isHighlightRect) {
69448 // NOTE: only painted shapes will catch click event. We either paint children or their parent but not both.
69449 // If it's a leaf with no category, parent will be painted instead (and support interactivity)
69450 if (d.depth > 1 && !d.identity.hasIdentity() && !isHighlightRect)
69451 return CssConstants.noneValue;
69452 // If it's not a leaf and it has children with a category, children will be painted
69453 if (Treemap.hasChildrenWithIdentity(d))
69454 return CssConstants.noneValue;
69455 return d.color;
69456 };
69457 Treemap.getFillOpacity = function (d, hasSelection, hasHighlights, isHighlightRect) {
69458 if (hasHighlights) {
69459 if (isHighlightRect)
69460 return null;
69461 return Treemap.DimmedShapeOpacity.toString();
69462 }
69463 if (!hasSelection || d.selected)
69464 return null;
69465 // Parent node is selected (as an optimization, we only check below level 1 because root node cannot be selected anyway)
69466 if (d.depth > 1 && d.parent.selected)
69467 return null;
69468 // It's a parent node with interactive children, fall back to default opacity
69469 if (Treemap.hasChildrenWithIdentity(d))
69470 return null;
69471 return Treemap.DimmedShapeOpacity.toString();
69472 };
69473 Treemap.prototype.updateInternal = function (suppressAnimations) {
69474 var data = this.data;
69475 var hasHighlights = data && data.hasHighlights;
69476 var labelSettings = data ? data.dataLabelsSettings : null;
69477 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
69478 if (!(this.options.interactivity && this.options.interactivity.isInteractiveLegend) && this.data) {
69479 this.renderLegend();
69480 }
69481 this.initViewportDependantProperties(duration);
69482 var viewport = this.calculateTreemapSize();
69483 this.treemap.size([viewport.width, viewport.height]);
69484 // Shapes are drawn for all nodes
69485 var nodes = (data && data.root) ? this.treemap.nodes(data.root) : [];
69486 // Highlight shapes are drawn only for nodes with non-null/undefed highlightMultipliers that have no children
69487 var highlightNodes = nodes.filter(function (value) { return value.highlightMultiplier != null && (!value.children || value.children.length === 0); });
69488 var majorLabeledNodes = [];
69489 var minorLabeledNodes = [];
69490 var alternativeScale = null;
69491 // Only populate major labels if category labels are turned on
69492 if (labelSettings.showCategory) {
69493 majorLabeledNodes = nodes.filter(function (d) { return Treemap.canDisplayMajorLabel(d); });
69494 }
69495 // Only populate minor labels if category or data labels are turned on
69496 if (labelSettings.show || labelSettings.showCategory) {
69497 minorLabeledNodes = nodes.filter(function (d) { return Treemap.canDisplayMinorLabel(d, labelSettings); });
69498 // If the display unit is 0 we calculate the format scale using the maximum value available
69499 if (labelSettings.displayUnits === 0)
69500 alternativeScale = d3.max(minorLabeledNodes, function (d) { return Math.abs(d.value); });
69501 }
69502 var treemapLayout = Treemap.getLayout(labelSettings, alternativeScale);
69503 var shapes;
69504 var highlightShapes;
69505 var majorLabels;
69506 var minorLabels;
69507 var result;
69508 if (this.animator && !suppressAnimations) {
69509 var options = {
69510 viewModel: data,
69511 nodes: nodes,
69512 highlightNodes: highlightNodes,
69513 majorLabeledNodes: majorLabeledNodes,
69514 minorLabeledNodes: minorLabeledNodes,
69515 shapeGraphicsContext: this.shapeGraphicsContext,
69516 labelGraphicsContext: this.labelGraphicsContext,
69517 interactivityService: this.interactivityService,
69518 layout: treemapLayout,
69519 labelSettings: labelSettings,
69520 };
69521 result = this.animator.animate(options);
69522 shapes = result.shapes;
69523 highlightShapes = result.highlightShapes;
69524 majorLabels = result.majorLabels;
69525 minorLabels = result.minorLabels;
69526 }
69527 if (!this.animator || suppressAnimations || result.failed) {
69528 var hasSelection = this.interactivityService && this.interactivityService.hasSelection();
69529 var shapeGraphicsContext = this.shapeGraphicsContext;
69530 shapes = Treemap.drawDefaultShapes(shapeGraphicsContext, nodes, hasSelection, hasHighlights, treemapLayout);
69531 highlightShapes = Treemap.drawDefaultHighlightShapes(shapeGraphicsContext, highlightNodes, hasSelection, hasHighlights, treemapLayout);
69532 var labelGraphicsContext = this.labelGraphicsContext;
69533 majorLabels = Treemap.drawDefaultMajorLabels(labelGraphicsContext, majorLabeledNodes, labelSettings, treemapLayout);
69534 minorLabels = Treemap.drawDefaultMinorLabels(labelGraphicsContext, minorLabeledNodes, labelSettings, treemapLayout);
69535 }
69536 if (this.interactivityService) {
69537 var behaviorOptions = {
69538 shapes: shapes,
69539 highlightShapes: highlightShapes,
69540 majorLabels: majorLabels,
69541 minorLabels: minorLabels,
69542 nodes: nodes,
69543 hasHighlights: data.hasHighlights,
69544 };
69545 this.interactivityService.bind(nodes, this.behavior, behaviorOptions);
69546 }
69547 if (this.tooltipsEnabled) {
69548 visuals.TooltipManager.addTooltip(shapes, function (tooltipEvent) { return tooltipEvent.data.highlightedTooltipInfo ? tooltipEvent.data.highlightedTooltipInfo : tooltipEvent.data.tooltipInfo; });
69549 visuals.TooltipManager.addTooltip(highlightShapes, function (tooltipEvent) { return tooltipEvent.data.highlightedTooltipInfo; });
69550 }
69551 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
69552 };
69553 Treemap.prototype.renderLegend = function () {
69554 var legendObjectProperties = this.data.legendObjectProperties;
69555 if (legendObjectProperties) {
69556 var legendData = this.data.legendData;
69557 visuals.LegendData.update(legendData, legendObjectProperties);
69558 var position = legendObjectProperties[visuals.legendProps.position];
69559 if (position)
69560 this.legend.changeOrientation(visuals.LegendPosition[position]);
69561 this.legend.drawLegend(legendData, this.currentViewport);
69562 }
69563 else {
69564 // TODO: Draw should be the only API. Visuals should only call that with orientation, props, etc
69565 // instead of managing state. Will follow up with another change.
69566 this.legend.changeOrientation(visuals.LegendPosition.Top);
69567 this.legend.drawLegend({ dataPoints: [] }, this.currentViewport);
69568 }
69569 };
69570 Treemap.getNodeClass = function (d, highlight) {
69571 var nodeClass;
69572 switch (d.depth) {
69573 case 1:
69574 nodeClass = Treemap.ParentGroupClassName;
69575 break;
69576 case 2:
69577 nodeClass = Treemap.NodeGroupClassName;
69578 break;
69579 case 0:
69580 nodeClass = Treemap.RootNodeClassName;
69581 break;
69582 default:
69583 debug.assertFail('Treemap only supports 2 levels maxiumum');
69584 }
69585 nodeClass += " " + (highlight ? Treemap.HighlightNodeClassName : Treemap.TreemapNodeClassName);
69586 return nodeClass;
69587 };
69588 Treemap.createTreemapShapeLayout = function (isHighlightRect) {
69589 if (isHighlightRect === void 0) { isHighlightRect = false; }
69590 return {
69591 x: function (d) { return d.x; },
69592 y: function (d) { return d.y + (isHighlightRect ? d.dy * (1 - d.highlightMultiplier) : 0); },
69593 width: function (d) { return Math.max(0, d.dx); },
69594 height: function (d) { return Math.max(0, d.dy * (isHighlightRect ? d.highlightMultiplier : 1)); },
69595 };
69596 };
69597 Treemap.createTreemapZeroShapeLayout = function () {
69598 return {
69599 x: function (d) { return d.x; },
69600 y: function (d) { return d.y + d.dy; },
69601 width: function (d) { return Math.max(0, d.dx); },
69602 height: function (d) { return 0; },
69603 };
69604 };
69605 Treemap.drawDefaultShapes = function (context, nodes, hasSelection, hasHighlights, layout) {
69606 var isHighlightShape = false;
69607 var shapes = context.selectAll('.' + Treemap.TreemapNodeClassName)
69608 .data(nodes, function (d) { return d.key; });
69609 shapes.enter().append('rect')
69610 .attr('class', layout.shapeClass);
69611 shapes
69612 .style("fill", function (d) { return Treemap.getFill(d, isHighlightShape); })
69613 .style("fill-opacity", function (d) { return Treemap.getFillOpacity(d, hasSelection, hasHighlights, isHighlightShape); })
69614 .attr(layout.shapeLayout);
69615 shapes.exit().remove();
69616 return shapes;
69617 };
69618 Treemap.drawDefaultHighlightShapes = function (context, nodes, hasSelection, hasHighlights, layout) {
69619 var isHighlightShape = true;
69620 var highlightShapes = context.selectAll('.' + Treemap.HighlightNodeClassName)
69621 .data(nodes, function (d) { return d.key + "highlight"; });
69622 highlightShapes.enter().append('rect')
69623 .attr('class', layout.highlightShapeClass);
69624 highlightShapes
69625 .style("fill", function (d) { return Treemap.getFill(d, isHighlightShape); })
69626 .style("fill-opacity", function (d) { return Treemap.getFillOpacity(d, hasSelection, hasHighlights, isHighlightShape); })
69627 .attr(layout.highlightShapeLayout);
69628 highlightShapes.exit().remove();
69629 return highlightShapes;
69630 };
69631 Treemap.drawDefaultMajorLabels = function (context, nodes, labelSettings, layout) {
69632 var labels = context
69633 .selectAll('.' + Treemap.MajorLabelClassName)
69634 .data(nodes, function (d) { return d.key; });
69635 labels.enter().append('text')
69636 .attr('class', layout.majorLabelClass);
69637 labels
69638 .attr(layout.majorLabelLayout)
69639 .text(layout.majorLabelText)
69640 .style('fill', function () { return labelSettings.labelColor; });
69641 labels.exit().remove();
69642 return labels;
69643 };
69644 Treemap.drawDefaultMinorLabels = function (context, nodes, labelSettings, layout) {
69645 var labels = context
69646 .selectAll('.' + Treemap.MinorLabelClassName)
69647 .data(nodes, function (d) { return d.key; });
69648 labels.enter().append('text')
69649 .attr('class', layout.minorLabelClass);
69650 labels
69651 .attr(layout.minorLabelLayout)
69652 .text(layout.minorLabelText)
69653 .style('fill', function () { return labelSettings.labelColor; });
69654 labels.exit().remove();
69655 return labels;
69656 };
69657 Treemap.cleanMinorLabels = function (context) {
69658 var empty = [];
69659 var labels = context
69660 .selectAll('.' + Treemap.LabelsGroupClassName)
69661 .selectAll('.' + Treemap.MinorLabelClassName)
69662 .data(empty);
69663 labels.exit().remove();
69664 };
69665 Treemap.DimmedShapeOpacity = 0.4;
69666 Treemap.ClassName = 'treemap';
69667 Treemap.LabelsGroupClassName = "labels";
69668 Treemap.MajorLabelClassName = 'majorLabel';
69669 Treemap.MinorLabelClassName = 'minorLabel';
69670 Treemap.ShapesClassName = "shapes";
69671 Treemap.TreemapNodeClassName = "treemapNode";
69672 Treemap.RootNodeClassName = 'rootNode';
69673 Treemap.ParentGroupClassName = 'parentGroup';
69674 Treemap.NodeGroupClassName = 'nodeGroup';
69675 Treemap.HighlightNodeClassName = 'treemapNodeHighlight';
69676 Treemap.TextMargin = 5;
69677 Treemap.MinorLabelTextSize = 10;
69678 Treemap.MinTextWidthForMinorLabel = 18;
69679 Treemap.MajorLabelTextSize = 12;
69680 Treemap.MinTextWidthForMajorLabel = 22;
69681 Treemap.MajorLabelTextProperties = {
69682 fontFamily: 'wf_segoe-ui_normal',
69683 fontSize: Treemap.MajorLabelTextSize + 'px'
69684 };
69685 Treemap.ValuesRoleName = 'Values';
69686 /**
69687 * A rect with an area of 9 is a treemap rectangle of only
69688 * a single pixel in the middle with a 1 pixel stroke on each edge.
69689 */
69690 Treemap.CullableArea = 9;
69691 return Treemap;
69692 }());
69693 visuals.Treemap = Treemap;
69694 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
69695})(powerbi || (powerbi = {}));
69696/*
69697 * Power BI Visualizations
69698 *
69699 * Copyright (c) Microsoft Corporation
69700 * All rights reserved.
69701 * MIT License
69702 *
69703 * Permission is hereby granted, free of charge, to any person obtaining a copy
69704 * of this software and associated documentation files (the ""Software""), to deal
69705 * in the Software without restriction, including without limitation the rights
69706 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
69707 * copies of the Software, and to permit persons to whom the Software is
69708 * furnished to do so, subject to the following conditions:
69709 *
69710 * The above copyright notice and this permission notice shall be included in
69711 * all copies or substantial portions of the Software.
69712 *
69713 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
69714 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69715 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69716 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69717 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69718 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
69719 * THE SOFTWARE.
69720 */
69721var powerbi;
69722(function (powerbi) {
69723 var visuals;
69724 (function (visuals) {
69725 var getKpiImageMetadata = powerbi.visuals.KpiUtil.getKpiImageMetadata;
69726 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
69727 var Card = (function (_super) {
69728 __extends(Card, _super);
69729 function Card(options) {
69730 _super.call(this, Card.cardClassName);
69731 this.isScrollable = false;
69732 this.displayUnitSystemType = powerbi.DisplayUnitSystemType.WholeUnits;
69733 if (options) {
69734 this.isScrollable = !!options.isScrollable;
69735 if (options.animator)
69736 this.animator = options.animator;
69737 if (options.displayUnitSystemType != null)
69738 this.displayUnitSystemType = options.displayUnitSystemType;
69739 }
69740 }
69741 Card.prototype.init = function (options) {
69742 debug.assertValue(options, 'options');
69743 this.animationOptions = options.animation;
69744 var element = options.element;
69745 this.kpiImage = d3.select(element.get(0)).append('div')
69746 .classed(Card.KPIImage.class, true);
69747 var svg = this.svg = d3.select(element.get(0)).append('svg');
69748 this.graphicsContext = svg.append('g');
69749 this.currentViewport = options.viewport;
69750 this.hostServices = options.host;
69751 this.style = options.style;
69752 this.updateViewportProperties();
69753 if (this.isScrollable) {
69754 svg.attr('class', Card.cardClassName);
69755 this.labelContext = svg.append('g');
69756 }
69757 };
69758 Card.prototype.onDataChanged = function (options) {
69759 debug.assertValue(options, 'options');
69760 var dataView = options.dataViews[0];
69761 var value;
69762 if (dataView) {
69763 this.getMetaDataColumn(dataView);
69764 if (dataView.single) {
69765 value = dataView.single.value;
69766 }
69767 // Update settings based on new metadata column
69768 this.cardFormatSetting = this.getDefaultFormatSettings();
69769 var dataViewMetadata = dataView.metadata;
69770 if (dataViewMetadata) {
69771 var objects = dataViewMetadata.objects;
69772 if (objects) {
69773 var labelSettings = this.cardFormatSetting.labelSettings;
69774 labelSettings.labelColor = powerbi.DataViewObjects.getFillColor(objects, visuals.cardProps.labels.color, labelSettings.labelColor);
69775 labelSettings.precision = powerbi.DataViewObjects.getValue(objects, visuals.cardProps.labels.labelPrecision, labelSettings.precision);
69776 labelSettings.fontSize = powerbi.DataViewObjects.getValue(objects, visuals.cardProps.labels.fontSize, labelSettings.fontSize);
69777 // The precision can't go below 0
69778 if (labelSettings.precision !== visuals.dataLabelUtils.defaultLabelPrecision && labelSettings.precision < 0) {
69779 labelSettings.precision = 0;
69780 }
69781 labelSettings.displayUnits = powerbi.DataViewObjects.getValue(objects, visuals.cardProps.labels.labelDisplayUnits, labelSettings.displayUnits);
69782 //category labels
69783 labelSettings.showCategory = powerbi.DataViewObjects.getValue(objects, visuals.cardProps.categoryLabels.show, labelSettings.showCategory);
69784 labelSettings.categoryLabelColor = powerbi.DataViewObjects.getFillColor(objects, visuals.cardProps.categoryLabels.color, labelSettings.categoryLabelColor);
69785 this.cardFormatSetting.wordWrap = powerbi.DataViewObjects.getValue(objects, visuals.cardProps.wordWrap.show, this.cardFormatSetting.wordWrap);
69786 this.cardFormatSetting.textSize = powerbi.DataViewObjects.getValue(objects, visuals.cardProps.categoryLabels.fontSize, this.cardFormatSetting.textSize);
69787 }
69788 }
69789 }
69790 this.updateInternal(value, true /* suppressAnimations */, true /* forceUpdate */);
69791 };
69792 Card.prototype.onResizing = function (viewport) {
69793 this.currentViewport = viewport;
69794 this.updateViewportProperties();
69795 this.updateInternal(this.value, true /* suppressAnimations */, true /* forceUpdate */);
69796 };
69797 Card.prototype.updateViewportProperties = function () {
69798 var viewport = this.currentViewport;
69799 this.svg.attr('width', viewport.width)
69800 .attr('height', viewport.height);
69801 };
69802 Card.prototype.setTextProperties = function (text, fontSize) {
69803 Card.cardTextProperties.fontSize = jsCommon.PixelConverter.fromPoint(fontSize);
69804 Card.cardTextProperties.text = text;
69805 };
69806 Card.prototype.getCardFormatTextSize = function () {
69807 return this.cardFormatSetting.textSize;
69808 };
69809 Card.prototype.getAdjustedFontHeight = function (availableWidth, textToMeasure, seedFontHeight) {
69810 var adjustedFontHeight = _super.prototype.getAdjustedFontHeight.call(this, availableWidth, textToMeasure, seedFontHeight);
69811 return Math.min(adjustedFontHeight, Card.DefaultStyle.card.maxFontSize);
69812 };
69813 Card.prototype.clear = function (valueOnly) {
69814 if (valueOnly === void 0) { valueOnly = false; }
69815 this.svg.select(Card.Value.selector).text('');
69816 if (!valueOnly)
69817 this.svg.select(Card.Label.selector).text('');
69818 _super.prototype.clear.call(this);
69819 };
69820 Card.prototype.updateInternal = function (target, suppressAnimations, forceUpdate) {
69821 if (forceUpdate === void 0) { forceUpdate = false; }
69822 var start = this.value;
69823 var duration = visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
69824 if (target === undefined) {
69825 if (start !== undefined)
69826 this.clear();
69827 return;
69828 }
69829 var metaDataColumn = this.metaDataColumn;
69830 var labelSettings = this.cardFormatSetting.labelSettings;
69831 var isDefaultDisplayUnit = labelSettings.displayUnits === 0;
69832 var format = this.getFormatString(metaDataColumn);
69833 var formatter = visuals.valueFormatter.create({
69834 format: format,
69835 value: isDefaultDisplayUnit ? target : labelSettings.displayUnits,
69836 precision: visuals.dataLabelUtils.getLabelPrecision(labelSettings.precision, format),
69837 displayUnitSystemType: isDefaultDisplayUnit && labelSettings.precision === visuals.dataLabelUtils.defaultLabelPrecision ? this.displayUnitSystemType : powerbi.DisplayUnitSystemType.WholeUnits,
69838 formatSingleValues: isDefaultDisplayUnit ? true : false,
69839 allowFormatBeautification: true,
69840 columnType: metaDataColumn ? metaDataColumn.type : undefined
69841 });
69842 var formatSettings = this.cardFormatSetting;
69843 var valueTextHeightInPx = jsCommon.PixelConverter.fromPointToPixel(labelSettings.fontSize);
69844 var valueStyles = Card.DefaultStyle.value;
69845 this.setTextProperties(target, this.getCardFormatTextSize());
69846 var labelTextHeightInPx = powerbi.TextMeasurementService.estimateSvgTextHeight(Card.cardTextProperties);
69847 var labelHeightWithPadding = labelTextHeightInPx + Card.DefaultStyle.label.paddingTop;
69848 var width = this.currentViewport.width;
69849 var height = this.currentViewport.height;
69850 var translateX = this.getTranslateX(width);
69851 var translateY = (height - labelHeightWithPadding - valueTextHeightInPx) / 2;
69852 var statusGraphicInfo = getKpiImageMetadata(metaDataColumn, target, 1 /* Big */);
69853 if (this.isScrollable) {
69854 if (!forceUpdate && start === target)
69855 return;
69856 // We want to format for null/blank/empty string and anything that is not a string
69857 if (start !== target && (_.isEmpty(target) || typeof (target) !== "string"))
69858 target = formatter.format(target);
69859 var label = metaDataColumn ? metaDataColumn.displayName : undefined;
69860 var labelData = labelSettings.showCategory
69861 ? [label]
69862 : [];
69863 var translatedLabelY = this.getTranslateY(valueTextHeightInPx + labelHeightWithPadding + translateY);
69864 var labelElement = this.labelContext
69865 .attr('transform', visuals.SVGUtil.translate(translateX, translatedLabelY))
69866 .selectAll('text')
69867 .data(labelData);
69868 labelElement
69869 .enter()
69870 .append('text')
69871 .attr('class', Card.Label.class);
69872 labelElement
69873 .text(function (d) { return d; })
69874 .style({
69875 'font-size': jsCommon.PixelConverter.fromPoint(this.getCardFormatTextSize()),
69876 'fill': labelSettings.categoryLabelColor,
69877 'text-anchor': this.getTextAnchor()
69878 });
69879 var labelElementNode = labelElement.node();
69880 if (labelElementNode) {
69881 if (formatSettings.wordWrap)
69882 powerbi.TextMeasurementService.wordBreak(labelElementNode, width / 2, height - translatedLabelY);
69883 else
69884 labelElement.call(visuals.AxisHelper.LabelLayoutStrategy.clip, width, powerbi.TextMeasurementService.svgEllipsis);
69885 }
69886 labelElement
69887 .append('title')
69888 .text(function (d) { return d; });
69889 labelElement.exit().remove();
69890 if (statusGraphicInfo) {
69891 // Display card KPI icon
69892 this.graphicsContext.selectAll('text').remove();
69893 this.displayStatusGraphic(statusGraphicInfo, translateX, translateY, valueTextHeightInPx);
69894 }
69895 else {
69896 // Display card text value
69897 this.kpiImage.selectAll('div').remove();
69898 var valueElement = this.graphicsContext
69899 .attr('transform', visuals.SVGUtil.translate(translateX, this.getTranslateY(valueTextHeightInPx + translateY)))
69900 .selectAll('text')
69901 .data([target]);
69902 valueElement
69903 .enter()
69904 .append('text')
69905 .attr('class', Card.Value.class);
69906 valueElement
69907 .text(function (d) { return d; })
69908 .style({
69909 'font-size': jsCommon.PixelConverter.fromPoint(labelSettings.fontSize),
69910 'fill': labelSettings.labelColor,
69911 'font-family': valueStyles.fontFamily,
69912 'text-anchor': this.getTextAnchor(),
69913 });
69914 valueElement.call(visuals.AxisHelper.LabelLayoutStrategy.clip, width, powerbi.TextMeasurementService.svgEllipsis);
69915 valueElement
69916 .append('title')
69917 .text(function (d) { return d; });
69918 valueElement.exit().remove();
69919 }
69920 }
69921 else {
69922 if (statusGraphicInfo) {
69923 // Display card KPI icon
69924 this.graphicsContext.selectAll('text').remove();
69925 this.displayStatusGraphic(statusGraphicInfo, translateX, translateY, valueTextHeightInPx);
69926 }
69927 else {
69928 this.kpiImage.selectAll('div').remove();
69929 this.doValueTransition(start, target, this.displayUnitSystemType, this.animationOptions, duration, forceUpdate, formatter);
69930 //in order to remove duplicated title values we first remove all and than add a new one
69931 this.graphicsContext.call(visuals.tooltipUtils.tooltipUpdate, [target]);
69932 }
69933 }
69934 this.value = target;
69935 };
69936 Card.prototype.displayStatusGraphic = function (statusGraphicInfo, translateX, translateY, labelTextSizeInPx) {
69937 // Remove existing text
69938 this.graphicsContext.selectAll('text').remove();
69939 // Create status graphic, if necessary
69940 var kpiImageDiv = this.kpiImage.select('div');
69941 if (!kpiImageDiv || kpiImageDiv.empty())
69942 kpiImageDiv = this.kpiImage.append('div');
69943 // Style status graphic
69944 kpiImageDiv
69945 .attr('class', statusGraphicInfo.class)
69946 .style('position', 'absolute')
69947 .style('font-size', labelTextSizeInPx + 'px');
69948 // Layout thrash to get image dimensions (could set as a const in future when icon font is fixed)
69949 var imageWidth = kpiImageDiv.node().offsetWidth;
69950 var imageHeight = kpiImageDiv.node().offsetHeight;
69951 // Position based on image height
69952 kpiImageDiv.style('transform', visuals.SVGUtil.translateWithPixels((translateX - (imageWidth / 2)), this.getTranslateY(labelTextSizeInPx + translateY) - imageHeight));
69953 };
69954 Card.prototype.getDefaultFormatSettings = function () {
69955 return {
69956 labelSettings: visuals.dataLabelUtils.getDefaultCardLabelSettings(Card.DefaultStyle.value.color, Card.DefaultStyle.label.color, Card.DefaultStyle.value.textSize),
69957 wordWrap: false,
69958 textSize: Card.DefaultStyle.label.textSize,
69959 };
69960 };
69961 Card.prototype.enumerateObjectInstances = function (options) {
69962 if (!this.cardFormatSetting)
69963 this.cardFormatSetting = this.getDefaultFormatSettings();
69964 var formatSettings = this.cardFormatSetting;
69965 var enumeration = new visuals.ObjectEnumerationBuilder();
69966 switch (options.objectName) {
69967 case 'categoryLabels':
69968 visuals.dataLabelUtils.enumerateCategoryLabels(enumeration, formatSettings.labelSettings, true /* withFill */, true /* isShowCategory */, formatSettings.textSize);
69969 break;
69970 case 'labels':
69971 var labelSettingOptions = {
69972 enumeration: enumeration,
69973 dataLabelsSettings: formatSettings.labelSettings,
69974 show: true,
69975 displayUnits: true,
69976 precision: true,
69977 fontSize: true,
69978 };
69979 visuals.dataLabelUtils.enumerateDataLabels(labelSettingOptions);
69980 break;
69981 case 'wordWrap':
69982 enumeration.pushInstance({
69983 objectName: 'wordWrap',
69984 selector: null,
69985 properties: {
69986 show: formatSettings.wordWrap,
69987 },
69988 });
69989 break;
69990 }
69991 return enumeration.complete();
69992 };
69993 Card.cardClassName = 'card';
69994 Card.Label = createClassAndSelector('label');
69995 Card.Value = createClassAndSelector('value');
69996 Card.KPIImage = createClassAndSelector('caption');
69997 Card.cardTextProperties = {
69998 fontSize: null,
69999 text: null,
70000 fontFamily: visuals.dataLabelUtils.LabelTextProperties.fontFamily,
70001 };
70002 Card.DefaultStyle = {
70003 card: {
70004 maxFontSize: 200
70005 },
70006 label: {
70007 textSize: 12,
70008 color: '#a6a6a6',
70009 paddingTop: 8
70010 },
70011 value: {
70012 textSize: 27,
70013 color: '#333333',
70014 fontFamily: 'wf_standard-font'
70015 }
70016 };
70017 return Card;
70018 }(visuals.AnimatedText));
70019 visuals.Card = Card;
70020 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
70021})(powerbi || (powerbi = {}));
70022/*
70023 * Power BI Visualizations
70024 *
70025 * Copyright (c) Microsoft Corporation
70026 * All rights reserved.
70027 * MIT License
70028 *
70029 * Permission is hereby granted, free of charge, to any person obtaining a copy
70030 * of this software and associated documentation files (the ""Software""), to deal
70031 * in the Software without restriction, including without limitation the rights
70032 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
70033 * copies of the Software, and to permit persons to whom the Software is
70034 * furnished to do so, subject to the following conditions:
70035 *
70036 * The above copyright notice and this permission notice shall be included in
70037 * all copies or substantial portions of the Software.
70038 *
70039 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70040 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
70041 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70042 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70043 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70044 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
70045 * THE SOFTWARE.
70046 */
70047var powerbi;
70048(function (powerbi) {
70049 var visuals;
70050 (function (visuals) {
70051 var OwlHappiness;
70052 (function (OwlHappiness) {
70053 OwlHappiness[OwlHappiness["Sad"] = 0] = "Sad";
70054 OwlHappiness[OwlHappiness["Meh"] = 1] = "Meh";
70055 OwlHappiness[OwlHappiness["Happy"] = 2] = "Happy";
70056 })(OwlHappiness || (OwlHappiness = {}));
70057 var OwlGauge = (function () {
70058 function OwlGauge() {
70059 }
70060 OwlGauge.converter = function (dataView) {
70061 return {};
70062 };
70063 OwlGauge.getGaugeData = function (dataView) {
70064 var settings = {
70065 max: 100,
70066 min: 0,
70067 target: undefined,
70068 total: 0,
70069 tooltipItems: []
70070 };
70071 if (dataView && dataView.categorical && dataView.categorical.values && dataView.metadata && dataView.metadata.columns) {
70072 var values = dataView.categorical.values;
70073 var metadataColumns = dataView.metadata.columns;
70074 debug.assert(metadataColumns.length >= values.length, 'length');
70075 for (var i = 0; i < values.length; i++) {
70076 var col = metadataColumns[i], value = values[i].values[0] || 0;
70077 if (col && col.roles) {
70078 if (col.roles[visuals.gaugeRoleNames.y]) {
70079 settings.total = value;
70080 if (value)
70081 settings.tooltipItems.push({ displayName: values[i].source.displayName, value: visuals.converterHelper.formatFromMetadataColumn(value, values[i].source, visuals.Gauge.formatStringProp) });
70082 }
70083 else if (col.roles[visuals.gaugeRoleNames.minValue]) {
70084 settings.min = value;
70085 }
70086 else if (col.roles[visuals.gaugeRoleNames.maxValue]) {
70087 settings.max = value;
70088 }
70089 else if (col.roles[visuals.gaugeRoleNames.targetValue]) {
70090 settings.target = value;
70091 if (value)
70092 settings.tooltipItems.push({ displayName: values[i].source.displayName, value: visuals.converterHelper.formatFromMetadataColumn(value, values[i].source, visuals.Gauge.formatStringProp) });
70093 }
70094 }
70095 }
70096 }
70097 return settings;
70098 };
70099 OwlGauge.prototype.init = function (options) {
70100 var _this = this;
70101 this.rootElem = options.element;
70102 this.rootElem.addClass('owlGaugeVisual');
70103 this.svgTailElem = $(OwlGauge.owlTailSvg);
70104 this.svgBgElem = $(OwlGauge.visualBgSvg);
70105 this.svgBodyElem = $(OwlGauge.owlBodySvg);
70106 this.rootElem.append(this.svgBgElem).append(this.svgTailElem).append(this.svgBodyElem);
70107 if (OwlGauge.OwlDemoMode) {
70108 window.setInterval(function () {
70109 var randomPercentage = Math.random() * 100 + 1;
70110 _this.updateGauge(randomPercentage);
70111 }, 2000);
70112 }
70113 this.updateViewportSize(options.viewport.width, options.viewport.height);
70114 };
70115 OwlGauge.prototype.update = function (options) {
70116 this.updateViewportSize(options.viewport.width, options.viewport.height);
70117 var dataView = options.dataViews.length > 0 ? options.dataViews[0] : null;
70118 if (dataView) {
70119 var gaugeData = OwlGauge.getGaugeData(options.dataViews[0]);
70120 var percentage = (gaugeData.total - gaugeData.min) / (gaugeData.max - gaugeData.min);
70121 this.updateGauge(percentage * 100 | 0);
70122 }
70123 else
70124 this.updateGauge(0);
70125 };
70126 OwlGauge.prototype.updateGauge = function (percentage) {
70127 if (percentage >= 0 && percentage <= 100) {
70128 var rotationDeg = -180 + (180 * percentage / 100);
70129 this.svgBgElem.css({ transform: 'rotate(' + rotationDeg + 'deg)' });
70130 if (percentage >= 66) {
70131 this.happinessLevel = OwlHappiness.Happy;
70132 }
70133 else if (percentage >= 33) {
70134 this.happinessLevel = OwlHappiness.Meh;
70135 }
70136 else {
70137 this.happinessLevel = OwlHappiness.Sad;
70138 }
70139 }
70140 };
70141 Object.defineProperty(OwlGauge.prototype, "happinessLevel", {
70142 set: function (level) {
70143 this.rootElem.removeClass('sad').removeClass('meh').removeClass('happy');
70144 switch (level) {
70145 case OwlHappiness.Sad:
70146 this.rootElem.addClass('sad');
70147 break;
70148 case OwlHappiness.Meh:
70149 this.rootElem.addClass('meh');
70150 break;
70151 case OwlHappiness.Happy:
70152 this.rootElem.addClass('happy');
70153 break;
70154 default:
70155 console.log('Well, this is interesting...');
70156 }
70157 },
70158 enumerable: true,
70159 configurable: true
70160 });
70161 OwlGauge.prototype.updateViewportSize = function (width, height) {
70162 var _this = this;
70163 var smoothingFn = window.setImmediate || window.requestAnimationFrame;
70164 smoothingFn(function () {
70165 _this.rootElem.css({
70166 height: height,
70167 width: width
70168 });
70169 _this.svgBodyElem.height(_this.svgBodyElem.width() * OwlGauge.owlBodyHeightMultiplier);
70170 _this.svgBgElem.height(_this.svgBgElem.width() * OwlGauge.visualBgHeightMultiplier);
70171 _this.svgTailElem.height(_this.svgTailElem.width() * OwlGauge.owlTailHeightMultiplier);
70172 });
70173 };
70174 OwlGauge.owlBodySvg = '<svg version="1.1" class="owlGaugeBody" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 267.7 291.2" style="enable-background:new 0 0 267.7 291.2;" xml:space="preserve"> <style type="text/css"> .owlGaugeBody .st0{fill:#A87D50;} .owlGaugeBody .st1{fill:#C2B59B;} .owlGaugeBody .st2{fill:#EB2227;} .owlGaugeBody .st3{fill:#FFFFFF;} .owlGaugeBody .st4{fill:#F9D018;} .owlGaugeBody .st5{fill:none;} .owlGaugeBody .st6{fill:#83381B;} .owlGaugeBody .st7{fill:#231F20;} </style> <g id="XMLID_31_"> <g id="XMLID_34_"> <ellipse id="XMLID_21_" transform="matrix(0.9998 1.947640e-02 -1.947640e-02 0.9998 2.8614 -2.5802)" class="st0" cx="133.9" cy="145.6" rx="133.9" ry="145.6"/> <polygon id="XMLID_20_" class="st0" points="199.2,32.8 184,11.3 209,9.7 "/> <polygon id="XMLID_19_" class="st0" points="73.9,31.2 62.1,7.7 87.1,9.8 "/> <circle id="XMLID_18_" class="st1" cx="134.8" cy="189.2" r="89.8"/> <path id="XMLID_17_" class="st2" d="M140.1,88c-2.7,3.8-7.9,4.7-11.7,2c-2.7-1.9-3.9-5.1-3.4-8.1c0,0,9.6-41.8,9.6-41.8l6.9,40.8 C142,83.2,141.6,85.8,140.1,88z"/> <path id="XMLID_16_" class="st3" d="M164.6,16.2c-14.2,0-26.3,9.2-30.6,21.9c-4.1-13.1-16.3-22.6-30.8-22.6 C85.4,15.6,71,30,71,47.8s14.4,32.3,32.3,32.3c14.2,0,26.3-9.2,30.6-21.9c4.1,13.1,16.3,22.6,30.8,22.6 c17.8,0,32.3-14.4,32.3-32.3S182.4,16.2,164.6,16.2z"/> <path id="XMLID_15_" class="st4" d="M122,58.7l23.3-0.1c0,0-9,14.8-10.2,16.6c-1.2,1.9-2.2,0.1-2.2,0.1L122,58.7z"/> <rect id="XMLID_14_" x="-11.4" y="-68.8" class="st5" width="288.3" height="259.7"/> <g id="XMLID_37_"> <path id="XMLID_13_" class="st6" d="M121.6,125.5c0,3.7-3.5,6.6-7.7,6.6c-4.2,0-7.7-3-7.7-6.6"/> <path id="XMLID_12_" class="st6" d="M160.1,126.5c0,3.7-3.5,6.6-7.7,6.6s-7.7-3-7.7-6.6"/> <path id="XMLID_11_" class="st6" d="M142.4,148.1c0,3.7-3.5,6.6-7.7,6.6c-4.2,0-7.7-3-7.7-6.6"/> <path id="XMLID_10_" class="st6" d="M183.1,148.8c0,3.7-3.5,6.6-7.7,6.6c-4.2,0-7.7-3-7.7-6.6"/> <path id="XMLID_9_" class="st6" d="M160.9,177.4c0,3.7-3.5,6.6-7.7,6.6s-7.7-3-7.7-6.6"/> <path id="XMLID_8_" class="st6" d="M201.6,178c0,3.7-3.5,6.6-7.7,6.6s-7.7-3-7.7-6.6"/> <path id="XMLID_7_" class="st6" d="M76.4,177.4c0,3.7-3.5,6.6-7.7,6.6c-4.2,0-7.7-3-7.7-6.6"/> <path id="XMLID_6_" class="st6" d="M117,178c0,3.7-3.5,6.6-7.7,6.6s-7.7-3-7.7-6.6"/> <path id="XMLID_5_" class="st6" d="M98.6,148.1c0,3.7-3.5,6.6-7.7,6.6c-4.2,0-7.7-3-7.7-6.6"/> </g> <circle id="XMLID_4_" class="st7" cx="164.1" cy="49" r="6.4"/> <circle id="XMLID_3_" class="st7" cx="102.7" cy="47.7" r="6.4"/> </g> <path id="XMLID_2_" class="st0" d="M160.1,140.9c11.1-8.4,55.6-36,55.6-36l4.7,0.8l10.2,38.8c0,0-3,3-9.2,3.1 c-5.1,0.1-45.9-2.6-60.2-3.5C158.1,143.9,157.7,142.7,160.1,140.9z"/> <path id="XMLID_1_" class="st0" d="M110.6,140.8c-11.1-8.4-55.6-36-55.6-36l-4.7,0.8L40,144.4c0,0,3,3,9.2,3.1 c5.1,0.1,45.9-2.6,60.2-3.5C112.5,143.8,113,142.6,110.6,140.8z"/> </g> </svg>';
70175 OwlGauge.owlTailSvg = '<svg version="1.1" class="owlGaugeTail" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 587.8 295.5" style="enable-background:new 0 0 587.8 295.5;" xml:space="preserve"> <style type="text/css"> .owlGaugeTail .st0{fill:#3B2416;} .owlGaugeTail .st1{fill:#5B4B43;} .owlGaugeTail .st2{fill:#603A17;} .owlGaugeTail .st3{fill:#726659;} </style> <g id="XMLID_55_"> <path id="XMLID_29_" class="st0" d="M85.2,106.2c-27.1,0-49.2,22-49.2,49.2c0,19.1,10.9,35.7,26.9,43.8c0,0,231.2,95.9,231.2,95.9 l-171-171C114.1,113.2,100.5,106.2,85.2,106.2z"/> <g id="XMLID_56_"> <path id="XMLID_28_" class="st1" d="M482.5,86.4c0-27.1-22-49.2-49.2-49.2c-19.1,0-35.7,10.9-43.8,26.9c0,0-95.9,231.2-95.9,231.2 l171-171C475.5,115.3,482.5,101.7,482.5,86.4z"/> <path id="XMLID_27_" class="st2" d="M573.5,281.3c19.2-19.2,19.2-50.3,0-69.5c-13.5-13.5-33-17.5-50-12c0,0-231.3,95.7-231.3,95.7 l241.8,0C548,296.9,562.6,292.1,573.5,281.3z"/> <path id="XMLID_26_" class="st3" d="M279.9,14.4c-19.2-19.2-50.3-19.2-69.5,0c-13.5,13.5-17.5,33-12,50c0,0,95.7,231.3,95.7,231.3 L294,54C295.4,39.8,290.7,25.2,279.9,14.4z"/> <path id="XMLID_25_" class="st2" d="M105.3,86.4c0-27.1,22-49.2,49.2-49.2c19.1,0,35.7,10.9,43.8,26.9c0,0,95.9,231.2,95.9,231.2 l-171-171C112.3,115.3,105.3,101.7,105.3,86.4z"/> <path id="XMLID_24_" class="st2" d="M14.4,281.4c-19.2-19.2-19.2-50.3,0-69.5c13.5-13.5,33-17.5,50-12c0,0,231.3,95.7,231.3,95.7 l-241.8,0C39.8,297,25.2,292.3,14.4,281.4z"/> <path id="XMLID_23_" class="st2" d="M308.2,14c19.2-19.2,50.3-19.2,69.5,0c13.5,13.5,17.5,33,12,50c0,0-95.7,231.3-95.7,231.3 l0-241.8C292.6,39.4,297.4,24.8,308.2,14z"/> <path id="XMLID_22_" class="st0" d="M503.2,106c27.1,0,49.2,22,49.2,49.2c0,19.1-10.9,35.7-26.9,43.8c0,0-231.2,95.9-231.2,95.9 l171-171C474.2,113,487.8,106,503.2,106z"/> </g> </g> </svg>';
70176 OwlGauge.visualBgSvg = '<svg version="1.1" class="owlGaugeBg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="123.8 94.9 349.1 175.3" style="enable-background:new 123.8 94.9 349.1 175.3;" xml:space="preserve"> <style type="text/css"> .owlGaugeBg .st0{fill:#EF4137;} .owlGaugeBg .st1{fill:#FAAF42;} .owlGaugeBg .st2{fill:#F15B2A;} .owlGaugeBg .st3{fill:#F69321;} </style> <g id="XMLID_10_"> <path id="XMLID_8_" class="st0" d="M174.3,158c-16.1,0-29.2,13.1-29.2,29.2c0,11.4,6.5,21.2,16,26.1l137.3,57L196.9,168.7 C191.5,162.2,183.4,158,174.3,158z"/> <g id="XMLID_11_"> <path id="XMLID_7_" class="st1" d="M410.2,146.3c0-16.1-13.1-29.2-29.2-29.2c-11.4,0-21.2,6.5-26,16l-57,137.5L399.5,169 C406.1,163.5,410.2,155.4,410.2,146.3z"/> <path id="XMLID_6_" class="st0" d="M464.3,262.2c11.4-11.4,11.4-29.9,0-41.3c-8-8-19.6-10.4-29.7-7.1l-137.4,56.9h143.6 C449.2,271.4,457.9,268.6,464.3,262.2z"/> <path id="XMLID_5_" class="st2" d="M290,103.5c-11.4-11.4-29.9-11.4-41.3,0c-8,8-10.4,19.6-7.1,29.7l56.8,137.5V127 C299.2,118.6,296.4,109.9,290,103.5z"/> <path id="XMLID_4_" class="st3" d="M186.3,146.3c0-16.1,13.1-29.2,29.2-29.2c11.4,0,21.2,6.5,26,16l57,137.5L197,168.8 C190.5,163.5,186.3,155.4,186.3,146.3z"/> <path id="XMLID_3_" class="st2" d="M132.3,262.2c-11.4-11.4-11.4-29.9,0-41.3c8-8,19.6-10.4,29.7-7.1l137.4,56.9H155.8 C147.4,271.5,138.7,268.7,132.3,262.2z"/> <path id="XMLID_2_" class="st3" d="M306.8,103.2c11.4-11.4,29.9-11.4,41.3,0c8,8,10.4,19.6,7.1,29.7l-56.8,137.5V126.7 C297.5,118.3,300.3,109.7,306.8,103.2z"/> <path id="XMLID_1_" class="st2" d="M422.5,157.9c16.1,0,29.2,13.1,29.2,29.2c0,11.4-6.5,21.2-16,26.1l-137.3,57L400,168.6 C405.3,162.1,413.4,157.9,422.5,157.9z"/> </g> </g> </svg>';
70177 OwlGauge.owlBodyHeightMultiplier = 291.2 / 267.7;
70178 OwlGauge.owlTailHeightMultiplier = 295.5 / 587.8;
70179 OwlGauge.visualBgHeightMultiplier = 295.5 / 587.8;
70180 OwlGauge.OwlDemoMode = false;
70181 OwlGauge.capabilities = {
70182 dataRoles: [
70183 {
70184 displayName: 'Category',
70185 name: 'Category',
70186 kind: powerbi.VisualDataRoleKind.Grouping,
70187 },
70188 {
70189 displayName: 'Y Axis',
70190 name: 'Y',
70191 kind: powerbi.VisualDataRoleKind.Measure,
70192 },
70193 ],
70194 dataViewMappings: [{
70195 categories: {
70196 for: { in: 'Category' },
70197 dataReductionAlgorithm: { top: {} }
70198 },
70199 values: {
70200 select: [{ bind: { to: 'Y' } }]
70201 },
70202 }]
70203 };
70204 return OwlGauge;
70205 }());
70206 visuals.OwlGauge = OwlGauge;
70207 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
70208})(powerbi || (powerbi = {}));
70209/*
70210 * Power BI Visualizations
70211 *
70212 * Copyright (c) Microsoft Corporation
70213 * All rights reserved.
70214 * MIT License
70215 *
70216 * Permission is hereby granted, free of charge, to any person obtaining a copy
70217 * of this software and associated documentation files (the ""Software""), to deal
70218 * in the Software without restriction, including without limitation the rights
70219 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
70220 * copies of the Software, and to permit persons to whom the Software is
70221 * furnished to do so, subject to the following conditions:
70222 *
70223 * The above copyright notice and this permission notice shall be included in
70224 * all copies or substantial portions of the Software.
70225 *
70226 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70227 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
70228 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70229 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70230 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70231 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
70232 * THE SOFTWARE.
70233 */
70234var powerbi;
70235(function (powerbi) {
70236 var visuals;
70237 (function (visuals) {
70238 var NoMapLocationWarning = (function () {
70239 function NoMapLocationWarning() {
70240 }
70241 Object.defineProperty(NoMapLocationWarning.prototype, "code", {
70242 get: function () {
70243 return 'NoMapLocation';
70244 },
70245 enumerable: true,
70246 configurable: true
70247 });
70248 NoMapLocationWarning.prototype.getMessages = function (resourceProvider) {
70249 var messageKey = 'NoMapLocationMessage';
70250 var titleKey = 'NoMapLocationKey';
70251 var detailKey = 'NoMapLocationValue';
70252 var visualMessage = {
70253 message: resourceProvider.get(messageKey),
70254 title: resourceProvider.get(titleKey),
70255 detail: resourceProvider.get(detailKey),
70256 };
70257 return visualMessage;
70258 };
70259 return NoMapLocationWarning;
70260 }());
70261 visuals.NoMapLocationWarning = NoMapLocationWarning;
70262 var FilledMapWithoutValidGeotagCategoryWarning = (function () {
70263 function FilledMapWithoutValidGeotagCategoryWarning() {
70264 }
70265 Object.defineProperty(FilledMapWithoutValidGeotagCategoryWarning.prototype, "code", {
70266 get: function () {
70267 return 'NoValidGeotaggedCategory';
70268 },
70269 enumerable: true,
70270 configurable: true
70271 });
70272 FilledMapWithoutValidGeotagCategoryWarning.prototype.getMessages = function (resourceProvider) {
70273 var messageKey = 'NoValidGeotaggedCategoryMessage';
70274 var titleKey = 'NoValidGeotaggedCategoryKey';
70275 var detailKey = 'NoValidGeotaggedCategoryValue';
70276 var visualMessage = {
70277 message: resourceProvider.get(messageKey),
70278 title: resourceProvider.get(titleKey),
70279 detail: resourceProvider.get(detailKey),
70280 };
70281 return visualMessage;
70282 };
70283 return FilledMapWithoutValidGeotagCategoryWarning;
70284 }());
70285 visuals.FilledMapWithoutValidGeotagCategoryWarning = FilledMapWithoutValidGeotagCategoryWarning;
70286 var GeometryCulledWarning = (function () {
70287 function GeometryCulledWarning() {
70288 }
70289 Object.defineProperty(GeometryCulledWarning.prototype, "code", {
70290 get: function () {
70291 return 'GeometryCulledWarning';
70292 },
70293 enumerable: true,
70294 configurable: true
70295 });
70296 GeometryCulledWarning.prototype.getMessages = function (resourceProvider) {
70297 var messageKey = 'GeometryCulledWarningMessage';
70298 var titleKey = 'GeometryCulledWarningKey';
70299 var detailKey = 'GeometryCulledWarningVal';
70300 var visualMessage = {
70301 message: resourceProvider.get(messageKey),
70302 title: resourceProvider.get(titleKey),
70303 detail: resourceProvider.get(detailKey),
70304 };
70305 return visualMessage;
70306 };
70307 return GeometryCulledWarning;
70308 }());
70309 visuals.GeometryCulledWarning = GeometryCulledWarning;
70310 var NegativeValuesNotSupportedWarning = (function () {
70311 function NegativeValuesNotSupportedWarning() {
70312 }
70313 Object.defineProperty(NegativeValuesNotSupportedWarning.prototype, "code", {
70314 get: function () {
70315 return 'NegativeValuesNotSupported';
70316 },
70317 enumerable: true,
70318 configurable: true
70319 });
70320 NegativeValuesNotSupportedWarning.prototype.getMessages = function (resourceProvider) {
70321 var messageKey = 'VisualWarning_NegativeValues';
70322 var visualMessage = {
70323 message: resourceProvider.get(messageKey),
70324 title: '',
70325 detail: '',
70326 };
70327 return visualMessage;
70328 };
70329 return NegativeValuesNotSupportedWarning;
70330 }());
70331 visuals.NegativeValuesNotSupportedWarning = NegativeValuesNotSupportedWarning;
70332 var AllNegativeValuesWarning = (function () {
70333 function AllNegativeValuesWarning() {
70334 }
70335 Object.defineProperty(AllNegativeValuesWarning.prototype, "code", {
70336 get: function () {
70337 return 'AllNegativeValuesNotSupported';
70338 },
70339 enumerable: true,
70340 configurable: true
70341 });
70342 AllNegativeValuesWarning.prototype.getMessages = function (resourceProvider) {
70343 var messageKey = 'VisualWarning_AllNegativeValues';
70344 var visualMessage = {
70345 message: resourceProvider.get(messageKey),
70346 title: '',
70347 detail: '',
70348 };
70349 return visualMessage;
70350 };
70351 return AllNegativeValuesWarning;
70352 }());
70353 visuals.AllNegativeValuesWarning = AllNegativeValuesWarning;
70354 var NaNNotSupportedWarning = (function () {
70355 function NaNNotSupportedWarning() {
70356 }
70357 Object.defineProperty(NaNNotSupportedWarning.prototype, "code", {
70358 get: function () {
70359 return 'NaNNotSupported';
70360 },
70361 enumerable: true,
70362 configurable: true
70363 });
70364 NaNNotSupportedWarning.prototype.getMessages = function (resourceProvider) {
70365 var messageKey = 'VisualWarning_NanValues';
70366 var visualMessage = {
70367 message: resourceProvider.get(messageKey),
70368 title: '',
70369 detail: '',
70370 };
70371 return visualMessage;
70372 };
70373 return NaNNotSupportedWarning;
70374 }());
70375 visuals.NaNNotSupportedWarning = NaNNotSupportedWarning;
70376 var InfinityValuesNotSupportedWarning = (function () {
70377 function InfinityValuesNotSupportedWarning() {
70378 }
70379 Object.defineProperty(InfinityValuesNotSupportedWarning.prototype, "code", {
70380 get: function () {
70381 return 'InfinityValuesNotSupported';
70382 },
70383 enumerable: true,
70384 configurable: true
70385 });
70386 InfinityValuesNotSupportedWarning.prototype.getMessages = function (resourceProvider) {
70387 var messageKey = 'VisualWarning_InfinityValues';
70388 var visualMessage = {
70389 message: resourceProvider.get(messageKey),
70390 title: '',
70391 detail: '',
70392 };
70393 return visualMessage;
70394 };
70395 return InfinityValuesNotSupportedWarning;
70396 }());
70397 visuals.InfinityValuesNotSupportedWarning = InfinityValuesNotSupportedWarning;
70398 var ValuesOutOfRangeWarning = (function () {
70399 function ValuesOutOfRangeWarning() {
70400 }
70401 Object.defineProperty(ValuesOutOfRangeWarning.prototype, "code", {
70402 get: function () {
70403 return 'ValuesOutOfRange';
70404 },
70405 enumerable: true,
70406 configurable: true
70407 });
70408 ValuesOutOfRangeWarning.prototype.getMessages = function (resourceProvider) {
70409 var messageKey = 'VisualWarning_VisualizationOutOfRange';
70410 var visualMessage = {
70411 message: resourceProvider.get(messageKey),
70412 title: '',
70413 detail: '',
70414 };
70415 return visualMessage;
70416 };
70417 return ValuesOutOfRangeWarning;
70418 }());
70419 visuals.ValuesOutOfRangeWarning = ValuesOutOfRangeWarning;
70420 var ZeroValueWarning = (function () {
70421 function ZeroValueWarning() {
70422 }
70423 Object.defineProperty(ZeroValueWarning.prototype, "code", {
70424 get: function () {
70425 return "ZeroValuesNotSupported";
70426 },
70427 enumerable: true,
70428 configurable: true
70429 });
70430 ZeroValueWarning.prototype.getMessages = function (resourceProvider) {
70431 var messageKey = 'VisualWarning_ZeroValues';
70432 var visualMessage = {
70433 message: resourceProvider.get(messageKey),
70434 title: '',
70435 detail: '',
70436 };
70437 return visualMessage;
70438 };
70439 return ZeroValueWarning;
70440 }());
70441 visuals.ZeroValueWarning = ZeroValueWarning;
70442 var VisualKPIDataMissingWarning = (function () {
70443 function VisualKPIDataMissingWarning() {
70444 }
70445 Object.defineProperty(VisualKPIDataMissingWarning.prototype, "code", {
70446 get: function () {
70447 return "VisualKPIDataMissing";
70448 },
70449 enumerable: true,
70450 configurable: true
70451 });
70452 VisualKPIDataMissingWarning.prototype.getMessages = function (resourceProvider) {
70453 var messageKey = 'Visual_KPI_DataMissing';
70454 var visualMessage = {
70455 message: resourceProvider.get(messageKey),
70456 title: '',
70457 detail: '',
70458 };
70459 return visualMessage;
70460 };
70461 return VisualKPIDataMissingWarning;
70462 }());
70463 visuals.VisualKPIDataMissingWarning = VisualKPIDataMissingWarning;
70464 var ScriptVisualRefreshWarning = (function () {
70465 function ScriptVisualRefreshWarning() {
70466 }
70467 Object.defineProperty(ScriptVisualRefreshWarning.prototype, "code", {
70468 get: function () {
70469 return "ScriptVisualNotRefreshed";
70470 },
70471 enumerable: true,
70472 configurable: true
70473 });
70474 ScriptVisualRefreshWarning.prototype.getMessages = function (resourceProvider) {
70475 var messageKey = 'ScriptVisualRefreshWarningMessage';
70476 var detailKey = 'ScriptVisualRefreshWarningValue';
70477 var visualMessage = {
70478 message: resourceProvider.get(messageKey),
70479 title: resourceProvider.get(messageKey),
70480 detail: resourceProvider.get(detailKey),
70481 };
70482 return visualMessage;
70483 };
70484 return ScriptVisualRefreshWarning;
70485 }());
70486 visuals.ScriptVisualRefreshWarning = ScriptVisualRefreshWarning;
70487 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
70488})(powerbi || (powerbi = {}));
70489/*
70490 * Power BI Visualizations
70491 *
70492 * Copyright (c) Microsoft Corporation
70493 * All rights reserved.
70494 * MIT License
70495 *
70496 * Permission is hereby granted, free of charge, to any person obtaining a copy
70497 * of this software and associated documentation files (the ""Software""), to deal
70498 * in the Software without restriction, including without limitation the rights
70499 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
70500 * copies of the Software, and to permit persons to whom the Software is
70501 * furnished to do so, subject to the following conditions:
70502 *
70503 * The above copyright notice and this permission notice shall be included in
70504 * all copies or substantial portions of the Software.
70505 *
70506 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70507 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
70508 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70509 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70510 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70511 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
70512 * THE SOFTWARE.
70513 */
70514var powerbi;
70515(function (powerbi) {
70516 var visuals;
70517 (function (visuals) {
70518 var PixelConverter = jsCommon.PixelConverter;
70519 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
70520 var WaterfallChart = (function () {
70521 function WaterfallChart(options) {
70522 this.isScrollable = options.isScrollable;
70523 this.tooltipsEnabled = options.tooltipsEnabled;
70524 this.interactivityService = options.interactivityService;
70525 }
70526 WaterfallChart.prototype.init = function (options) {
70527 debug.assertValue(options, 'options');
70528 this.svg = options.svg;
70529 this.svg.classed(WaterfallChart.WaterfallClassName, true);
70530 this.style = options.style;
70531 this.currentViewport = options.viewport;
70532 this.hostServices = options.host;
70533 this.interactivity = options.interactivity;
70534 this.cartesianVisualHost = options.cartesianHost;
70535 this.options = options;
70536 this.element = options.element;
70537 this.colors = this.style.colorPalette.dataColors;
70538 this.mainGraphicsSVG = this.svg.append('svg');
70539 this.mainGraphicsContext = this.mainGraphicsSVG.append('g')
70540 .classed(WaterfallChart.MainGraphicsContextClassName, true);
70541 this.labelGraphicsContext = this.mainGraphicsSVG.append('g')
70542 .classed(visuals.NewDataLabelUtils.labelGraphicsContextClass.class, true);
70543 };
70544 WaterfallChart.converter = function (dataView, palette, hostServices, dataLabelSettings, sentimentColors, interactivityService, tooltipsEnabled) {
70545 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
70546 debug.assertValue(palette, 'palette');
70547 var reader = powerbi.data.createIDataViewCategoricalReader(dataView);
70548 var formatStringProp = WaterfallChart.formatStringProp;
70549 var categories = dataView.categorical.categories || [];
70550 var increaseColor = sentimentColors.increaseFill.solid.color;
70551 var decreaseColor = sentimentColors.decreaseFill.solid.color;
70552 var totalColor = sentimentColors.totalFill.solid.color;
70553 var totalLabel = hostServices.getLocalizedString(WaterfallChart.TotalLabel);
70554 var increaseLabel = hostServices.getLocalizedString(WaterfallChart.IncreaseLabel);
70555 var decreaseLabel = hostServices.getLocalizedString(WaterfallChart.DecreaseLabel);
70556 var legend = [
70557 {
70558 label: increaseLabel,
70559 color: increaseColor,
70560 icon: visuals.LegendIcon.Box,
70561 identity: visuals.SelectionIdBuilder.builder().withMeasure('increase').createSelectionId(),
70562 selected: false,
70563 }, {
70564 label: decreaseLabel,
70565 color: decreaseColor,
70566 icon: visuals.LegendIcon.Box,
70567 identity: visuals.SelectionIdBuilder.builder().withMeasure('decrease').createSelectionId(),
70568 selected: false,
70569 }, {
70570 label: totalLabel,
70571 color: totalColor,
70572 icon: visuals.LegendIcon.Box,
70573 identity: visuals.SelectionIdBuilder.builder().withMeasure('total').createSelectionId(),
70574 selected: false,
70575 }];
70576 /**
70577 * The position represents the starting point for each bar,
70578 * for any value it is the sum of all previous values.
70579 * Values > 0 are considered gains, values < 0 are losses.
70580 */
70581 var pos = 0, posMin = 0, posMax = 0;
70582 var dataPoints = [];
70583 var categoryValues = [];
70584 var categoryMetadata;
70585 var valuesMetadata = undefined;
70586 if (reader.hasValues("Y")) {
70587 valuesMetadata = reader.getValueMetadataColumn("Y");
70588 var labelFormatString = valuesMetadata.format;
70589 if (_.isEmpty(categories)) {
70590 // We have values but no category, just show the total bar.
70591 pos = posMax = reader.getValue("Y", 0);
70592 posMin = 0;
70593 }
70594 else {
70595 var categoryColumn = categories[0];
70596 categoryMetadata = categoryColumn.source;
70597 categoryValues = categoryColumn.values.slice();
70598 categoryValues.push(totalLabel);
70599 for (var categoryIndex = 0, catLen = reader.getCategoryCount(); categoryIndex < catLen; categoryIndex++) {
70600 var category = categoryValues[categoryIndex];
70601 var value = reader.getValue("Y", categoryIndex) || 0;
70602 var identity = visuals.SelectionIdBuilder.builder()
70603 .withCategory(categoryColumn, categoryIndex)
70604 .withMeasure(valuesMetadata.queryName)
70605 .createSelectionId();
70606 var tooltipInfo_2 = void 0;
70607 if (tooltipsEnabled) {
70608 tooltipInfo_2 = [];
70609 tooltipInfo_2.push({
70610 displayName: categoryMetadata.displayName,
70611 value: visuals.converterHelper.formatFromMetadataColumn(category, categoryMetadata, formatStringProp),
70612 });
70613 if (value != null) {
70614 tooltipInfo_2.push({
70615 displayName: valuesMetadata.displayName,
70616 value: visuals.converterHelper.formatFromMetadataColumn(value, valuesMetadata, formatStringProp),
70617 });
70618 }
70619 }
70620 var color = value > 0 ? increaseColor : decreaseColor;
70621 dataPoints.push({
70622 value: value,
70623 position: pos,
70624 color: color,
70625 categoryValue: category,
70626 categoryIndex: categoryIndex,
70627 seriesIndex: 0,
70628 selected: false,
70629 identity: identity,
70630 highlight: false,
70631 key: identity.getKey(),
70632 tooltipInfo: tooltipInfo_2,
70633 labelFill: dataLabelSettings.labelColor,
70634 labelFormatString: labelFormatString,
70635 });
70636 pos += value;
70637 if (pos > posMax)
70638 posMax = pos;
70639 if (pos < posMin)
70640 posMin = pos;
70641 }
70642 }
70643 var tooltipInfo = void 0;
70644 if (tooltipsEnabled) {
70645 tooltipInfo = [];
70646 if (categoryMetadata) {
70647 tooltipInfo.push({
70648 displayName: categoryMetadata.displayName,
70649 value: totalLabel,
70650 });
70651 }
70652 if (pos != null) {
70653 tooltipInfo.push({
70654 displayName: valuesMetadata.displayName,
70655 value: visuals.converterHelper.formatFromMetadataColumn(pos, valuesMetadata, formatStringProp),
70656 });
70657 }
70658 }
70659 var totalIdentity = visuals.SelectionId.createNull();
70660 dataPoints.push({
70661 value: pos,
70662 position: 0,
70663 color: totalColor,
70664 categoryValue: totalLabel,
70665 categoryIndex: categoryIndex,
70666 identity: totalIdentity,
70667 seriesIndex: 0,
70668 selected: false,
70669 highlight: false,
70670 key: totalIdentity.getKey(),
70671 tooltipInfo: tooltipInfo,
70672 labelFill: dataLabelSettings.labelColor,
70673 labelFormatString: labelFormatString,
70674 isTotal: true,
70675 });
70676 }
70677 if (interactivityService) {
70678 interactivityService.applySelectionStateToData(dataPoints);
70679 }
70680 var xAxisProperties = visuals.CartesianHelper.getCategoryAxisProperties(dataView.metadata);
70681 var yAxisProperties = visuals.CartesianHelper.getValueAxisProperties(dataView.metadata);
70682 var axesLabels = visuals.converterHelper.createAxesLabels(xAxisProperties, yAxisProperties, categoryMetadata, [valuesMetadata]);
70683 return {
70684 series: [{ data: dataPoints }],
70685 categories: categoryValues,
70686 categoryMetadata: categoryMetadata,
70687 valuesMetadata: valuesMetadata,
70688 legend: { dataPoints: legend },
70689 hasHighlights: false,
70690 positionMin: posMin,
70691 positionMax: posMax,
70692 dataLabelsSettings: dataLabelSettings,
70693 sentimentColors: sentimentColors,
70694 axesLabels: { x: axesLabels.xAxisLabel, y: axesLabels.yAxisLabel },
70695 };
70696 };
70697 WaterfallChart.prototype.setData = function (dataViews) {
70698 debug.assertValue(dataViews, "dataViews");
70699 var sentimentColors = this.getSentimentColorsFromObjects(null);
70700 var dataView = dataViews.length > 0 ? dataViews[0] : undefined;
70701 this.data = {
70702 series: [{ data: [] }],
70703 categories: [],
70704 valuesMetadata: null,
70705 legend: { dataPoints: [], },
70706 hasHighlights: false,
70707 categoryMetadata: null,
70708 scalarCategoryAxis: false,
70709 positionMax: 0,
70710 positionMin: 0,
70711 dataLabelsSettings: visuals.dataLabelUtils.getDefaultLabelSettings(/* show */ false, /* labelColor */ undefined),
70712 sentimentColors: sentimentColors,
70713 axesLabels: { x: null, y: null },
70714 };
70715 if (dataView) {
70716 if (dataView.metadata && dataView.metadata.objects) {
70717 var objects = dataView.metadata.objects;
70718 var labelsObj = objects['labels'];
70719 if (labelsObj) {
70720 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelsObj, this.data.dataLabelsSettings);
70721 }
70722 sentimentColors = this.getSentimentColorsFromObjects(objects);
70723 }
70724 if (dataView.categorical) {
70725 this.data = WaterfallChart.converter(dataView, this.colors, this.hostServices, this.data.dataLabelsSettings, sentimentColors, this.interactivityService, this.tooltipsEnabled);
70726 }
70727 }
70728 };
70729 WaterfallChart.prototype.enumerateObjectInstances = function (enumeration, options) {
70730 switch (options.objectName) {
70731 case 'sentimentColors':
70732 this.enumerateSentimentColors(enumeration);
70733 break;
70734 case 'labels':
70735 var labelSettingOptions = {
70736 enumeration: enumeration,
70737 dataLabelsSettings: this.data.dataLabelsSettings,
70738 show: true,
70739 displayUnits: true,
70740 precision: true,
70741 fontSize: true,
70742 };
70743 visuals.dataLabelUtils.enumerateDataLabels(labelSettingOptions);
70744 break;
70745 }
70746 };
70747 WaterfallChart.prototype.enumerateSentimentColors = function (enumeration) {
70748 var sentimentColors = this.data.sentimentColors;
70749 enumeration.pushInstance({
70750 selector: null,
70751 properties: {
70752 increaseFill: sentimentColors.increaseFill,
70753 decreaseFill: sentimentColors.decreaseFill,
70754 totalFill: sentimentColors.totalFill
70755 },
70756 objectName: 'sentimentColors'
70757 });
70758 };
70759 WaterfallChart.prototype.calculateLegend = function () {
70760 // TODO: support interactive legend
70761 return this.data.legend;
70762 };
70763 WaterfallChart.prototype.hasLegend = function () {
70764 // Waterfall legend is more like a color-key, so just return true
70765 return true;
70766 };
70767 WaterfallChart.createClippedDataIfOverflowed = function (data, renderableDataCount) {
70768 var clipped = data;
70769 var dataPoints = data.series[0].data;
70770 if (data && renderableDataCount < dataPoints.length) {
70771 clipped = powerbi.Prototype.inherit(data);
70772 clipped.series = [{ data: dataPoints.slice(0, renderableDataCount) }];
70773 clipped.categories = data.categories.slice(0, renderableDataCount);
70774 }
70775 return clipped;
70776 };
70777 WaterfallChart.prototype.calculateAxesProperties = function (options) {
70778 var _this = this;
70779 debug.assertValue(options, 'options');
70780 this.currentViewport = options.viewport;
70781 this.margin = options.margin;
70782 var data = this.clippedData = this.data;
70783 var categoryCount = data.categories.length;
70784 var preferredPlotArea = this.getPreferredPlotArea(false, categoryCount, visuals.CartesianChart.MinOrdinalRectThickness);
70785 var cartesianLayout = visuals.CartesianChart.getLayout(null, {
70786 availableWidth: preferredPlotArea.width,
70787 categoryCount: categoryCount,
70788 domain: null,
70789 isScalar: false,
70790 isScrollable: this.isScrollable,
70791 trimOrdinalDataOnOverflow: options.trimOrdinalDataOnOverflow
70792 });
70793 // In the case that we have overflowed horizontally we want to clip the data and use that to calculate the axes on the dashboard.
70794 if (!this.isScrollable) {
70795 data = this.clippedData = WaterfallChart.createClippedDataIfOverflowed(data, cartesianLayout.categoryCount);
70796 }
70797 var xAxisCreationOptions = WaterfallChart.getXAxisCreationOptions(data, preferredPlotArea.width, cartesianLayout, options);
70798 var yAxisCreationOptions = WaterfallChart.getYAxisCreationOptions(data, preferredPlotArea.height, options);
70799 var xAxisProperties = this.xAxisProperties = visuals.AxisHelper.createAxis(xAxisCreationOptions);
70800 var yAxisProperties = this.yAxisProperties = visuals.AxisHelper.createAxis(yAxisCreationOptions);
70801 var categoryWidth = this.xAxisProperties.categoryThickness * (1 - visuals.CartesianChart.InnerPaddingRatio);
70802 var formattersCache = visuals.dataLabelUtils.createColumnFormatterCacheManager();
70803 var labelSettings = data.dataLabelsSettings;
70804 var value2 = WaterfallChart.getDisplayUnitValueFromAxisFormatter(yAxisProperties, labelSettings);
70805 this.layout = {
70806 categoryCount: cartesianLayout.categoryCount,
70807 categoryThickness: cartesianLayout.categoryThickness,
70808 isScalar: cartesianLayout.isScalar,
70809 outerPaddingRatio: cartesianLayout.outerPaddingRatio,
70810 categoryWidth: categoryWidth,
70811 labelText: function (d) {
70812 //total value has no identity
70813 var formatter = formattersCache.getOrCreate(d.labelFormatString, labelSettings, value2);
70814 return visuals.dataLabelUtils.getLabelFormattedText({ label: formatter.format(d.value) });
70815 },
70816 labelLayout: visuals.dataLabelUtils.getLabelLayoutXYForWaterfall(xAxisProperties, categoryWidth, yAxisProperties, yAxisCreationOptions.dataDomain),
70817 filter: function (d) {
70818 return visuals.dataLabelUtils.doesDataLabelFitInShape(d, yAxisProperties, _this.layout);
70819 },
70820 style: {
70821 'fill': function (d) {
70822 if (d.isLabelInside)
70823 return visuals.dataLabelUtils.defaultInsideLabelColor;
70824 return d.labelFill;
70825 },
70826 },
70827 };
70828 this.xAxisProperties.axisLabel = options.showCategoryAxisLabel ? data.axesLabels.x : null;
70829 this.yAxisProperties.axisLabel = options.showValueAxisLabel ? data.axesLabels.y : null;
70830 return [xAxisProperties, yAxisProperties];
70831 };
70832 WaterfallChart.getDisplayUnitValueFromAxisFormatter = function (yAxisProperties, labelSettings) {
70833 return (yAxisProperties.formatter && yAxisProperties.formatter.displayUnit && labelSettings.displayUnits === 0) ? yAxisProperties.formatter.displayUnit.value : null;
70834 };
70835 WaterfallChart.lookupXValue = function (data, index, type) {
70836 var dataPoints = data.series[0].data;
70837 if (index === dataPoints.length - 1)
70838 // Total
70839 return dataPoints[index].categoryValue;
70840 else
70841 return visuals.CartesianHelper.lookupXValue(data, index, type, false);
70842 };
70843 WaterfallChart.getXAxisCreationOptions = function (data, width, layout, options) {
70844 debug.assertValue(data, 'data');
70845 debug.assertValue(options, 'options');
70846 var categoryDataType = visuals.AxisHelper.getCategoryValueType(data.categoryMetadata);
70847 var domain = visuals.AxisHelper.createDomain(data.series, categoryDataType, /* isScalar */ false, options.forcedXDomain, options.ensureXDomain);
70848 var categoryThickness = layout.categoryThickness;
70849 var outerPadding = categoryThickness * layout.outerPaddingRatio;
70850 return {
70851 pixelSpan: width,
70852 dataDomain: domain,
70853 metaDataColumn: data.categoryMetadata,
70854 formatString: visuals.valueFormatter.getFormatString(data.categoryMetadata, WaterfallChart.formatStringProp),
70855 isScalar: false,
70856 outerPadding: outerPadding,
70857 categoryThickness: categoryThickness,
70858 getValueFn: function (index, type) { return WaterfallChart.lookupXValue(data, index, type); },
70859 forcedTickCount: options.forcedTickCount,
70860 isCategoryAxis: true,
70861 axisDisplayUnits: options.categoryAxisDisplayUnits,
70862 axisPrecision: options.categoryAxisPrecision
70863 };
70864 };
70865 WaterfallChart.getYAxisCreationOptions = function (data, height, options) {
70866 debug.assertValue(data, 'data');
70867 debug.assertValue(options, 'options');
70868 var combinedDomain = visuals.AxisHelper.combineDomain(options.forcedYDomain, [data.positionMin, data.positionMax], options.ensureYDomain);
70869 return {
70870 pixelSpan: height,
70871 dataDomain: combinedDomain,
70872 isScalar: true,
70873 isVertical: true,
70874 metaDataColumn: data.valuesMetadata,
70875 formatString: visuals.valueFormatter.getFormatString(data.valuesMetadata, WaterfallChart.formatStringProp),
70876 outerPadding: 0,
70877 forcedTickCount: options.forcedTickCount,
70878 useTickIntervalForDisplayUnits: true,
70879 isCategoryAxis: false,
70880 axisDisplayUnits: options.valueAxisDisplayUnits,
70881 axisPrecision: options.valueAxisPrecision
70882 };
70883 };
70884 WaterfallChart.prototype.getPreferredPlotArea = function (isScalar, categoryCount, categoryThickness) {
70885 return visuals.CartesianChart.getPreferredPlotArea(categoryCount, categoryThickness, this.currentViewport, this.isScrollable, isScalar, this.margin);
70886 };
70887 WaterfallChart.prototype.getVisualCategoryAxisIsScalar = function () {
70888 return false;
70889 };
70890 WaterfallChart.prototype.overrideXScale = function (xProperties) {
70891 this.xAxisProperties = xProperties;
70892 };
70893 WaterfallChart.prototype.setFilteredData = function (startIndex, endIndex) {
70894 var data = this.clippedData = powerbi.Prototype.inherit(this.data);
70895 data.series = [{ data: data.series[0].data.slice(startIndex, endIndex) }];
70896 data.categories = data.categories.slice(startIndex, endIndex);
70897 return data;
70898 };
70899 WaterfallChart.prototype.createRects = function (data) {
70900 var mainGraphicsContext = this.mainGraphicsContext;
70901 var colsSelection = mainGraphicsContext.selectAll(WaterfallChart.CategoryValueClasses.selector);
70902 var cols = colsSelection.data(data, function (d) { return d.key; });
70903 cols
70904 .enter()
70905 .append('rect')
70906 .attr('class', function (d) { return WaterfallChart.CategoryValueClasses.class.concat(d.highlight ? 'highlight' : ''); });
70907 cols.exit().remove();
70908 return cols;
70909 };
70910 WaterfallChart.prototype.createConnectors = function (data) {
70911 var mainGraphicsContext = this.mainGraphicsContext;
70912 var connectorSelection = mainGraphicsContext.selectAll(WaterfallChart.WaterfallConnectorClasses.selector);
70913 var connectors = connectorSelection.data(data.slice(0, data.length - 1), function (d) { return d.key; });
70914 connectors
70915 .enter()
70916 .append('line')
70917 .classed(WaterfallChart.WaterfallConnectorClasses.class, true);
70918 connectors.exit().remove();
70919 return connectors;
70920 };
70921 WaterfallChart.prototype.render = function (suppressAnimations) {
70922 var _this = this;
70923 var dataPoints = this.clippedData.series[0].data;
70924 var bars = this.createRects(dataPoints);
70925 var connectors = this.createConnectors(dataPoints);
70926 if (this.tooltipsEnabled)
70927 visuals.TooltipManager.addTooltip(bars, function (tooltipEvent) { return tooltipEvent.data.tooltipInfo; });
70928 var hasSelection = this.interactivityService && this.interactivityService.hasSelection();
70929 var xScale = this.xAxisProperties.scale;
70930 var yScale = this.yAxisProperties.scale;
70931 var y0 = yScale(0);
70932 this.mainGraphicsSVG.attr('height', this.getAvailableHeight())
70933 .attr('width', this.getAvailableWidth());
70934 /**
70935 * The y-value is always at the top of the rect. If the data value is negative then we can
70936 * use the scaled position directly since we are drawing down. If the data value is positive
70937 * we have to calculate the top of the rect and use that as the y-value. Since the y-value
70938 * is always the top of the rect, height should always be positive.
70939 */
70940 bars
70941 .style('fill', function (d) { return d.color; })
70942 .style('fill-opacity', function (d) { return d.isTotal ? visuals.ColumnUtil.DefaultOpacity : visuals.ColumnUtil.getFillOpacity(d.selected, d.highlight, hasSelection, _this.data.hasHighlights); })
70943 .attr('width', this.layout.categoryWidth)
70944 .attr('x', function (d) { return xScale(d.categoryIndex); })
70945 .attr('y', function (d) { return WaterfallChart.getRectTop(yScale, d.position, d.value); })
70946 .attr('height', function (d) { return y0 - yScale(Math.abs(d.value)); });
70947 connectors
70948 .attr({
70949 'x1': function (d) { return xScale(d.categoryIndex); },
70950 'y1': function (d) { return yScale(d.position + d.value); },
70951 'x2': function (d) { return xScale(d.categoryIndex + 1) + _this.layout.categoryWidth; },
70952 'y2': function (d) { return yScale(d.position + d.value); },
70953 });
70954 var labelSettings = this.data.dataLabelsSettings;
70955 var labelDataPoints = [];
70956 if (labelSettings && labelSettings.show || labelSettings.showCategory) {
70957 labelDataPoints = this.createLabelDataPoints();
70958 }
70959 var behaviorOptions = undefined;
70960 if (this.interactivityService) {
70961 behaviorOptions = {
70962 bars: bars,
70963 datapoints: dataPoints,
70964 };
70965 }
70966 // This should always be the last line in the render code.
70967 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
70968 return { dataPoints: dataPoints, behaviorOptions: behaviorOptions, labelDataPoints: labelDataPoints, labelsAreNumeric: true };
70969 };
70970 WaterfallChart.prototype.onClearSelection = function () {
70971 if (this.interactivityService)
70972 this.interactivityService.clearSelection();
70973 };
70974 WaterfallChart.prototype.getSupportedCategoryAxisType = function () {
70975 return visuals.axisType.categorical;
70976 };
70977 WaterfallChart.getRectTop = function (scale, pos, value) {
70978 if (value < 0)
70979 return scale(pos);
70980 else
70981 return scale(pos) - (scale(0) - scale(value));
70982 };
70983 WaterfallChart.prototype.getAvailableWidth = function () {
70984 return this.currentViewport.width - (this.margin.left + this.margin.right);
70985 };
70986 WaterfallChart.prototype.getAvailableHeight = function () {
70987 return this.currentViewport.height - (this.margin.top + this.margin.bottom);
70988 };
70989 WaterfallChart.prototype.getSentimentColorsFromObjects = function (objects) {
70990 var defaultSentimentColors = this.colors.getSentimentColors();
70991 var increaseColor = powerbi.DataViewObjects.getFillColor(objects, visuals.waterfallChartProps.sentimentColors.increaseFill, defaultSentimentColors[2].value);
70992 var decreaseColor = powerbi.DataViewObjects.getFillColor(objects, visuals.waterfallChartProps.sentimentColors.decreaseFill, defaultSentimentColors[0].value);
70993 var totalColor = powerbi.DataViewObjects.getFillColor(objects, visuals.waterfallChartProps.sentimentColors.totalFill, WaterfallChart.defaultTotalColor);
70994 return {
70995 increaseFill: { solid: { color: increaseColor } },
70996 decreaseFill: { solid: { color: decreaseColor } },
70997 totalFill: { solid: { color: totalColor } }
70998 };
70999 };
71000 // Public for testing
71001 WaterfallChart.prototype.createLabelDataPoints = function () {
71002 var labelDataPoints = [];
71003 var data = this.data;
71004 var xScale = this.xAxisProperties.scale;
71005 var yScale = this.yAxisProperties.scale;
71006 var y0 = yScale(0);
71007 var series = data.series;
71008 var formattersCache = visuals.NewDataLabelUtils.createColumnFormatterCacheManager();
71009 var axisFormatter = visuals.NewDataLabelUtils.getDisplayUnitValueFromAxisFormatter(this.yAxisProperties.formatter, data.dataLabelsSettings);
71010 var labelSettings = this.data.dataLabelsSettings;
71011 for (var _i = 0, series_6 = series; _i < series_6.length; _i++) {
71012 var currentSeries = series_6[_i];
71013 for (var _a = 0, _b = currentSeries.data; _a < _b.length; _a++) {
71014 var dataPoint = _b[_a];
71015 // Calculate parent rectangle
71016 var parentRect = {
71017 left: xScale(dataPoint.categoryIndex),
71018 top: WaterfallChart.getRectTop(yScale, dataPoint.position, dataPoint.value),
71019 width: this.layout.categoryWidth,
71020 height: y0 - yScale(Math.abs(dataPoint.value)),
71021 };
71022 // Calculate label text
71023 var formatString = dataPoint.labelFormatString;
71024 var formatter = formattersCache.getOrCreate(formatString, this.data.dataLabelsSettings, axisFormatter);
71025 var text = visuals.NewDataLabelUtils.getLabelFormattedText(formatter.format(dataPoint.value));
71026 // Calculate text size
71027 var properties = {
71028 text: text,
71029 fontFamily: visuals.NewDataLabelUtils.LabelTextProperties.fontFamily,
71030 fontSize: PixelConverter.fromPoint(labelSettings.fontSize || visuals.NewDataLabelUtils.DefaultLabelFontSizeInPt),
71031 fontWeight: visuals.NewDataLabelUtils.LabelTextProperties.fontWeight,
71032 };
71033 var textWidth = powerbi.TextMeasurementService.measureSvgTextWidth(properties);
71034 var textHeight = powerbi.TextMeasurementService.estimateSvgTextHeight(properties, true /* tightFitForNumeric */);
71035 labelDataPoints.push({
71036 isPreferred: true,
71037 text: text,
71038 textSize: {
71039 width: textWidth,
71040 height: textHeight,
71041 },
71042 outsideFill: labelSettings.labelColor ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultLabelColor,
71043 insideFill: visuals.NewDataLabelUtils.defaultInsideLabelColor,
71044 parentType: 1 /* Rectangle */,
71045 parentShape: {
71046 rect: parentRect,
71047 orientation: dataPoint.value >= 0 ? 1 /* VerticalBottomBased */ : 2 /* VerticalTopBased */,
71048 validPositions: dataPoint.value === 0 ? WaterfallChart.validZeroLabelPosition : WaterfallChart.validLabelPositions,
71049 },
71050 fontSize: labelSettings.fontSize,
71051 identity: undefined,
71052 });
71053 }
71054 }
71055 return labelDataPoints;
71056 };
71057 WaterfallChart.formatStringProp = { objectName: 'general', propertyName: 'formatString' };
71058 WaterfallChart.WaterfallClassName = 'waterfallChart';
71059 WaterfallChart.MainGraphicsContextClassName = 'mainGraphicsContext';
71060 WaterfallChart.IncreaseLabel = "Waterfall_IncreaseLabel";
71061 WaterfallChart.DecreaseLabel = "Waterfall_DecreaseLabel";
71062 WaterfallChart.TotalLabel = "Waterfall_TotalLabel";
71063 WaterfallChart.CategoryValueClasses = createClassAndSelector('column');
71064 WaterfallChart.WaterfallConnectorClasses = createClassAndSelector('waterfall-connector');
71065 WaterfallChart.defaultTotalColor = "#00b8aa";
71066 WaterfallChart.validLabelPositions = [16 /* OutsideEnd */, 4 /* InsideEnd */];
71067 WaterfallChart.validZeroLabelPosition = [16 /* OutsideEnd */, 8 /* OutsideBase */];
71068 return WaterfallChart;
71069 }());
71070 visuals.WaterfallChart = WaterfallChart;
71071 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
71072})(powerbi || (powerbi = {}));
71073/*
71074 * Power BI Visualizations
71075 *
71076 * Copyright (c) Microsoft Corporation
71077 * All rights reserved.
71078 * MIT License
71079 *
71080 * Permission is hereby granted, free of charge, to any person obtaining a copy
71081 * of this software and associated documentation files (the ""Software""), to deal
71082 * in the Software without restriction, including without limitation the rights
71083 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71084 * copies of the Software, and to permit persons to whom the Software is
71085 * furnished to do so, subject to the following conditions:
71086 *
71087 * The above copyright notice and this permission notice shall be included in
71088 * all copies or substantial portions of the Software.
71089 *
71090 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71091 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71092 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
71093 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71094 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71095 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
71096 * THE SOFTWARE.
71097 */
71098var powerbi;
71099(function (powerbi) {
71100 var visuals;
71101 (function (visuals) {
71102 var TouchUtils = powerbi.visuals.controls.TouchUtils;
71103 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
71104 ;
71105 var ContainerClassName = createClassAndSelector("tooltip-container");
71106 var ContentContainerClassName = createClassAndSelector("tooltip-content-container");
71107 var ArrowClassName = createClassAndSelector("arrow");
71108 var TooltipHeaderClassName = createClassAndSelector("tooltip-header");
71109 var TooltipRowClassName = createClassAndSelector("tooltip-row");
71110 var TooltipColorCellClassName = createClassAndSelector("tooltip-color-cell");
71111 var TooltipTitleCellClassName = createClassAndSelector("tooltip-title-cell");
71112 var TooltipValueCellClassName = createClassAndSelector("tooltip-value-cell");
71113 var ToolTipComponent = (function () {
71114 function ToolTipComponent(tooltipOptions) {
71115 this.tooltipOptions = tooltipOptions;
71116 this.isTooltipVisible = false;
71117 if (!tooltipOptions) {
71118 this.tooltipOptions = ToolTipComponent.DefaultTooltipOptions;
71119 }
71120 }
71121 ToolTipComponent.prototype.isTooltipComponentVisible = function () {
71122 return this.isTooltipVisible;
71123 };
71124 /** Note: For tests only */
71125 ToolTipComponent.prototype.setTestScreenSize = function (width, height) {
71126 this.customScreenWidth = width;
71127 this.customScreenHeight = height;
71128 };
71129 ToolTipComponent.prototype.show = function (tooltipData, clickedArea) {
71130 this.isTooltipVisible = true;
71131 if (!this.tooltipContainer) {
71132 this.tooltipContainer = this.createTooltipContainer();
71133 }
71134 this.setTooltipContent(tooltipData);
71135 this.tooltipContainer
71136 .style("visibility", "visible")
71137 .transition()
71138 .duration(0) // Cancel previous transitions
71139 .style("opacity", this.tooltipOptions.opacity);
71140 this.setPosition(clickedArea);
71141 };
71142 ToolTipComponent.prototype.move = function (tooltipData, clickedArea) {
71143 if (this.isTooltipVisible) {
71144 if (tooltipData) {
71145 this.setTooltipContent(tooltipData);
71146 }
71147 this.setPosition(clickedArea);
71148 }
71149 };
71150 ToolTipComponent.prototype.hide = function () {
71151 if (this.isTooltipVisible) {
71152 this.isTooltipVisible = false;
71153 this.tooltipContainer
71154 .transition()
71155 .duration(this.tooltipOptions.animationDuration)
71156 .style("opacity", 0)
71157 .each('end', function () { this.style.visibility = "hidden"; });
71158 }
71159 };
71160 ToolTipComponent.prototype.createTooltipContainer = function () {
71161 var container = d3.select(ToolTipComponent.parentContainerSelector)
71162 .append("div")
71163 .attr("class", ContainerClassName.class);
71164 container.append("div").attr("class", ArrowClassName.class);
71165 container.append("div").attr("class", ContentContainerClassName.class);
71166 return container;
71167 };
71168 ToolTipComponent.prototype.setTooltipContent = function (tooltipData) {
71169 if (_.isEqual(tooltipData, this.currentTooltipData))
71170 return;
71171 this.currentTooltipData = tooltipData;
71172 var rowsSelector = TooltipRowClassName.selector;
71173 var contentContainer = this.tooltipContainer.select(ContentContainerClassName.selector);
71174 // Clear existing content
71175 contentContainer.selectAll(TooltipHeaderClassName.selector).remove();
71176 contentContainer.selectAll(TooltipRowClassName.selector).remove();
71177 if (tooltipData.length === 0)
71178 return;
71179 if (tooltipData[0].header) {
71180 contentContainer.append("div").attr("class", TooltipHeaderClassName.class).text(tooltipData[0].header);
71181 }
71182 var tooltipRow = contentContainer.selectAll(rowsSelector).data(tooltipData);
71183 var newRow = tooltipRow.enter().append("div").attr("class", TooltipRowClassName.class);
71184 if (tooltipData[0].color) {
71185 var newColorCell = newRow.append("div").attr("class", TooltipColorCellClassName.class);
71186 newColorCell
71187 .append('svg')
71188 .attr({
71189 'width': '100%',
71190 'height': '15px'
71191 })
71192 .append('circle')
71193 .attr({
71194 'cx': '5',
71195 'cy': '8',
71196 'r': '5'
71197 })
71198 .style({
71199 'fill': function (d) { return d.color; }
71200 });
71201 }
71202 var newTitleCell = newRow.append("div").attr("class", TooltipTitleCellClassName.class);
71203 var newValueCell = newRow.append("div").attr("class", TooltipValueCellClassName.class);
71204 newTitleCell.text(function (d) { return d.displayName; });
71205 newValueCell.text(function (d) { return d.value; });
71206 };
71207 ToolTipComponent.prototype.getTooltipPosition = function (clickedArea, clickedScreenArea) {
71208 var tooltipContainerBounds = this.tooltipContainer.node().getBoundingClientRect();
71209 var centerPointOffset = Math.floor(clickedArea.width / 2);
71210 var offsetX = 0;
71211 var offsetY = 0;
71212 var centerPoint = new TouchUtils.Point(clickedArea.x + centerPointOffset, clickedArea.y + centerPointOffset);
71213 var arrowOffset = 7;
71214 if (clickedScreenArea === 0 /* TopLeft */) {
71215 offsetX += 3 * arrowOffset + centerPointOffset;
71216 offsetY -= 2 * arrowOffset + centerPointOffset;
71217 }
71218 else if (clickedScreenArea === 1 /* TopRight */) {
71219 offsetX -= (2 * arrowOffset + tooltipContainerBounds.width + centerPointOffset);
71220 offsetY -= 2 * arrowOffset + centerPointOffset;
71221 }
71222 else if (clickedScreenArea === 3 /* BottomLeft */) {
71223 offsetX += 3 * arrowOffset + centerPointOffset;
71224 offsetY -= (tooltipContainerBounds.height - 2 * arrowOffset + centerPointOffset);
71225 }
71226 else if (clickedScreenArea === 2 /* BottomRight */) {
71227 offsetX -= (2 * arrowOffset + tooltipContainerBounds.width + centerPointOffset);
71228 offsetY -= (tooltipContainerBounds.height - 2 * arrowOffset + centerPointOffset);
71229 }
71230 centerPoint.offset(offsetX, offsetY);
71231 return centerPoint;
71232 };
71233 ToolTipComponent.prototype.setPosition = function (clickedArea) {
71234 var clickedScreenArea = this.getClickedScreenArea(clickedArea);
71235 var tooltipPosition = this.getTooltipPosition(clickedArea, clickedScreenArea);
71236 this.tooltipContainer.style({ "left": tooltipPosition.x + "px", "top": tooltipPosition.y + "px" });
71237 this.setArrowPosition(clickedArea, clickedScreenArea);
71238 };
71239 ToolTipComponent.prototype.setArrowPosition = function (clickedArea, clickedScreenArea) {
71240 var arrow = this.getArrowElement();
71241 var arrowClassName;
71242 if (clickedScreenArea === 0 /* TopLeft */) {
71243 arrowClassName = "top left";
71244 }
71245 else if (clickedScreenArea === 1 /* TopRight */) {
71246 arrowClassName = "top right";
71247 }
71248 else if (clickedScreenArea === 3 /* BottomLeft */) {
71249 arrowClassName = "bottom left";
71250 }
71251 else if (clickedScreenArea === 2 /* BottomRight */) {
71252 arrowClassName = "bottom right";
71253 }
71254 arrow
71255 .attr('class', 'arrow') // Reset all classes
71256 .classed(arrowClassName, true);
71257 };
71258 ToolTipComponent.prototype.getArrowElement = function () {
71259 return this.tooltipContainer.select(ArrowClassName.selector);
71260 };
71261 ToolTipComponent.prototype.getClickedScreenArea = function (clickedArea) {
71262 var screenWidth = this.customScreenWidth || window.innerWidth;
71263 var screenHeight = this.customScreenHeight || window.innerHeight;
71264 var centerPointOffset = clickedArea.width / 2;
71265 var centerPoint = new TouchUtils.Point(clickedArea.x + centerPointOffset, clickedArea.y + centerPointOffset);
71266 var halfWidth = screenWidth / 2;
71267 var halfHeight = screenHeight / 2;
71268 if (centerPoint.x < halfWidth && centerPoint.y < halfHeight) {
71269 return 0 /* TopLeft */;
71270 }
71271 else if (centerPoint.x >= halfWidth && centerPoint.y < halfHeight) {
71272 return 1 /* TopRight */;
71273 }
71274 else if (centerPoint.x < halfWidth && centerPoint.y >= halfHeight) {
71275 return 3 /* BottomLeft */;
71276 }
71277 else if (centerPoint.x >= halfWidth && centerPoint.y >= halfHeight) {
71278 return 2 /* BottomRight */;
71279 }
71280 };
71281 ToolTipComponent.DefaultTooltipOptions = {
71282 opacity: 1,
71283 animationDuration: 250,
71284 offsetX: 10,
71285 offsetY: 10
71286 };
71287 ToolTipComponent.parentContainerSelector = "body";
71288 ToolTipComponent.highlightedValueDisplayNameResorceKey = "Tooltip_HighlightedValueDisplayName";
71289 return ToolTipComponent;
71290 }());
71291 visuals.ToolTipComponent = ToolTipComponent;
71292 var TooltipManager;
71293 (function (TooltipManager) {
71294 TooltipManager.ShowTooltips = true;
71295 TooltipManager.ToolTipInstance = new ToolTipComponent();
71296 var GlobalTooltipEventsAttached = false;
71297 var tooltipMouseOverDelay = 350;
71298 var tooltipMouseOutDelay = 500;
71299 var tooltipTouchDelay = 350;
71300 var tooltipTimeoutId;
71301 var handleTouchDelay = 1000;
71302 var handleTouchTimeoutId = 0;
71303 var mouseCoordinates;
71304 var tooltipData;
71305 function addTooltip(selection, getTooltipInfoDelegate, reloadTooltipDataOnMouseMove, onMouseOutDelegate) {
71306 if (!TooltipManager.ShowTooltips) {
71307 return;
71308 }
71309 debug.assertValue(selection, "selection");
71310 var rootNode = d3.select(ToolTipComponent.parentContainerSelector).node();
71311 // Mouse events
71312 selection.on("mouseover", function () {
71313 var target = d3.event.target;
71314 var data = d3.select(target).datum();
71315 // Ignore mouseover while handling touch events
71316 if (handleTouchTimeoutId || !canDisplayTooltip(d3.event))
71317 return;
71318 mouseCoordinates = getCoordinates(rootNode, true);
71319 var elementCoordinates = getCoordinates(target, true);
71320 var tooltipEvent = {
71321 data: data,
71322 coordinates: mouseCoordinates,
71323 elementCoordinates: elementCoordinates,
71324 context: target,
71325 isTouchEvent: false
71326 };
71327 clearTooltipTimeout();
71328 // if it is already visible, change contents immediately (use 16ms minimum perceivable frame rate to prevent thrashing)
71329 var delay = TooltipManager.ToolTipInstance.isTooltipComponentVisible() ? 16 : tooltipMouseOverDelay;
71330 tooltipTimeoutId = showDelayedTooltip(tooltipEvent, getTooltipInfoDelegate, delay);
71331 });
71332 selection.on("mouseout", function () {
71333 if (!handleTouchTimeoutId) {
71334 clearTooltipTimeout();
71335 tooltipTimeoutId = hideDelayedTooltip(tooltipMouseOutDelay);
71336 }
71337 if (onMouseOutDelegate) {
71338 onMouseOutDelegate();
71339 }
71340 });
71341 selection.on("mousemove", function () {
71342 var target = d3.event.target;
71343 var data = d3.select(target).datum();
71344 // Ignore mousemove while handling touch events
71345 if (handleTouchTimeoutId || !canDisplayTooltip(d3.event))
71346 return;
71347 mouseCoordinates = getCoordinates(rootNode, true);
71348 var elementCoordinates = getCoordinates(target, true);
71349 var tooltipEvent = {
71350 data: data,
71351 coordinates: mouseCoordinates,
71352 elementCoordinates: elementCoordinates,
71353 context: target,
71354 isTouchEvent: false
71355 };
71356 moveTooltipEventHandler(tooltipEvent, getTooltipInfoDelegate, reloadTooltipDataOnMouseMove);
71357 });
71358 // --- Touch events ---
71359 // TODO: static?
71360 var touchStartEventName = getTouchStartEventName();
71361 var touchEndEventName = getTouchEndEventName();
71362 var isPointerEvent = touchStartEventName === "pointerdown" || touchStartEventName === "MSPointerDown";
71363 if (!GlobalTooltipEventsAttached) {
71364 // Add root container hide tooltip event
71365 attachGlobalEvents(touchStartEventName);
71366 GlobalTooltipEventsAttached = true;
71367 }
71368 selection.on(touchStartEventName, function () {
71369 var target = d3.event.target;
71370 var data = d3.select(target).datum();
71371 hideTooltipEventHandler();
71372 var coordinates = getCoordinates(rootNode, isPointerEvent);
71373 var elementCoordinates = getCoordinates(target, isPointerEvent);
71374 var tooltipEvent = {
71375 data: data,
71376 coordinates: coordinates,
71377 elementCoordinates: elementCoordinates,
71378 context: target,
71379 isTouchEvent: true
71380 };
71381 clearTooltipTimeout();
71382 tooltipTimeoutId = showDelayedTooltip(tooltipEvent, getTooltipInfoDelegate, tooltipTouchDelay);
71383 });
71384 selection.on(touchEndEventName, function () {
71385 clearTooltipTimeout();
71386 if (handleTouchTimeoutId)
71387 clearTimeout(handleTouchTimeoutId);
71388 // At the end of touch action, set a timeout that will let us ignore the incoming mouse events for a small amount of time
71389 handleTouchTimeoutId = setTimeout(function () {
71390 handleTouchTimeoutId = 0;
71391 }, handleTouchDelay);
71392 });
71393 }
71394 TooltipManager.addTooltip = addTooltip;
71395 function showDelayedTooltip(tooltipEvent, getTooltipInfoDelegate, delayInMs) {
71396 return setTimeout(function () { return showTooltipEventHandler(tooltipEvent, getTooltipInfoDelegate); }, delayInMs);
71397 }
71398 TooltipManager.showDelayedTooltip = showDelayedTooltip;
71399 function hideDelayedTooltip(delayInMs) {
71400 return setTimeout(function () { return hideTooltipEventHandler(); }, delayInMs);
71401 }
71402 TooltipManager.hideDelayedTooltip = hideDelayedTooltip;
71403 function setLocalizedStrings(localizationOptions) {
71404 ToolTipComponent.localizationOptions = localizationOptions;
71405 }
71406 TooltipManager.setLocalizedStrings = setLocalizedStrings;
71407 function showTooltipEventHandler(tooltipEvent, getTooltipInfoDelegate) {
71408 var tooltipInfo = tooltipData || getTooltipInfoDelegate(tooltipEvent);
71409 if (!_.isEmpty(tooltipInfo)) {
71410 var coordinates = mouseCoordinates || tooltipEvent.coordinates;
71411 var clickedArea = getClickedArea(coordinates[0], coordinates[1], tooltipEvent.isTouchEvent);
71412 TooltipManager.ToolTipInstance.show(tooltipInfo, clickedArea);
71413 }
71414 }
71415 function moveTooltipEventHandler(tooltipEvent, getTooltipInfoDelegate, reloadTooltipDataOnMouseMove) {
71416 tooltipData = undefined;
71417 if (reloadTooltipDataOnMouseMove) {
71418 tooltipData = getTooltipInfoDelegate(tooltipEvent);
71419 }
71420 var clickedArea = getClickedArea(tooltipEvent.coordinates[0], tooltipEvent.coordinates[1], tooltipEvent.isTouchEvent);
71421 TooltipManager.ToolTipInstance.move(tooltipData, clickedArea);
71422 }
71423 ;
71424 function hideTooltipEventHandler() {
71425 TooltipManager.ToolTipInstance.hide();
71426 }
71427 ;
71428 function clearTooltipTimeout() {
71429 if (tooltipTimeoutId) {
71430 clearTimeout(tooltipTimeoutId);
71431 }
71432 }
71433 function canDisplayTooltip(d3Event) {
71434 var cadDisplay = true;
71435 var mouseEvent = d3Event;
71436 if (mouseEvent.buttons !== undefined) {
71437 // Check mouse buttons state
71438 var hasMouseButtonPressed = mouseEvent.buttons !== 0;
71439 cadDisplay = !hasMouseButtonPressed;
71440 }
71441 return cadDisplay;
71442 }
71443 function getTouchStartEventName() {
71444 var eventName = "touchstart";
71445 if (window["PointerEvent"]) {
71446 // IE11
71447 eventName = "pointerdown";
71448 }
71449 else if (window["MSPointerEvent"]) {
71450 // IE10
71451 eventName = "MSPointerDown";
71452 }
71453 return eventName;
71454 }
71455 function getTouchEndEventName() {
71456 var eventName = "touchend";
71457 if (window["PointerEvent"]) {
71458 // IE11
71459 eventName = "pointerup";
71460 }
71461 else if (window["MSPointerEvent"]) {
71462 // IE10
71463 eventName = "MSPointerUp";
71464 }
71465 return eventName;
71466 }
71467 function getCoordinates(rootNode, isPointerEvent) {
71468 var coordinates;
71469 if (isPointerEvent) {
71470 // DO NOT USE - WebKit bug in getScreenCTM with nested SVG results in slight negative coordinate shift
71471 // Also, IE will incorporate transform scale but WebKit does not, forcing us to detect browser and adjust appropriately.
71472 // Just use non-scaled coordinates for all browsers, and adjust for the transform scale later (see lineChart.findIndex)
71473 //coordinates = d3.mouse(rootNode);
71474 // copied from d3_eventSource (which is not exposed)
71475 var e = d3.event, s = void 0;
71476 while (s = e.sourceEvent)
71477 e = s;
71478 var rect = rootNode.getBoundingClientRect();
71479 coordinates = [e.clientX - rect.left - rootNode.clientLeft, e.clientY - rect.top - rootNode.clientTop];
71480 }
71481 else {
71482 var touchCoordinates = d3.touches(rootNode);
71483 if (touchCoordinates && touchCoordinates.length > 0) {
71484 coordinates = touchCoordinates[0];
71485 }
71486 }
71487 return coordinates;
71488 }
71489 function attachGlobalEvents(touchStartEventName) {
71490 d3.select(ToolTipComponent.parentContainerSelector).on(touchStartEventName, function (d, i) {
71491 TooltipManager.ToolTipInstance.hide();
71492 });
71493 }
71494 function getClickedArea(x, y, isTouchEvent) {
71495 var width = 0;
71496 var pointX = x;
71497 var pointY = y;
71498 if (isTouchEvent) {
71499 width = 12;
71500 var offset = width / 2;
71501 pointX = Math.max(x - offset, 0);
71502 pointY = Math.max(y - offset, 0);
71503 }
71504 return new TouchUtils.Rectangle(pointX, pointY, width, width);
71505 }
71506 })(TooltipManager = visuals.TooltipManager || (visuals.TooltipManager = {}));
71507 var TooltipBuilder;
71508 (function (TooltipBuilder) {
71509 // TODO: implement options bag as input parameter
71510 function createTooltipInfo(formatStringProp, dataViewCat, categoryValue, value, categories, seriesData, seriesIndex, categoryIndex, highlightedValue, gradientValueColumn) {
71511 var categorySource;
71512 var seriesSource = [];
71513 var valuesSource = undefined;
71514 seriesIndex = seriesIndex | 0;
71515 var categoriesData = dataViewCat ? dataViewCat.categories : categories;
71516 if (categoriesData && categoriesData.length > 0) {
71517 if (categoriesData.length > 1) {
71518 var compositeCategoriesData = [];
71519 for (var i = 0, ilen = categoriesData.length; i < ilen; i++) {
71520 compositeCategoriesData.push(categoriesData[i].source);
71521 }
71522 categorySource = { value: categoryValue, metadata: compositeCategoriesData };
71523 }
71524 else {
71525 categorySource = { value: categoryValue, metadata: [categoriesData[0].source] };
71526 }
71527 }
71528 if (dataViewCat && dataViewCat.values) {
71529 if (categorySource && categorySource.metadata[0] === dataViewCat.values.source) {
71530 }
71531 else {
71532 valuesSource = dataViewCat.values.source;
71533 }
71534 if (dataViewCat.values.length > 0) {
71535 var valueColumn = dataViewCat.values[seriesIndex];
71536 var isAutoGeneratedColumn = !!(valueColumn && valueColumn.source && valueColumn.source.isAutoGeneratedColumn);
71537 if (!isAutoGeneratedColumn) {
71538 seriesSource.push({ value: value, highlightedValue: highlightedValue, metadata: valueColumn });
71539 }
71540 }
71541 //Create Gradient tooltip value
71542 var gradientToolTipData = createGradientToolTipData(gradientValueColumn, categoryIndex);
71543 if (gradientToolTipData != null)
71544 seriesSource.push(gradientToolTipData);
71545 }
71546 if (seriesData) {
71547 for (var i = 0, len = seriesData.length; i < len; i++) {
71548 var singleSeriesData = seriesData[i];
71549 if (categorySource && categorySource.metadata[0] === singleSeriesData.metadata.source)
71550 continue;
71551 seriesSource.push({ value: singleSeriesData.value, metadata: singleSeriesData.metadata });
71552 }
71553 }
71554 var tooltipInfo = createTooltipData(formatStringProp, categorySource, valuesSource, seriesSource);
71555 return tooltipInfo;
71556 }
71557 TooltipBuilder.createTooltipInfo = createTooltipInfo;
71558 function createGradientToolTipData(gradientValueColumn, categoryIndex) {
71559 if (gradientValueColumn) {
71560 // Saturation color
71561 return { value: gradientValueColumn.values[categoryIndex], metadata: { source: gradientValueColumn.source, values: [] } };
71562 }
71563 return null;
71564 }
71565 TooltipBuilder.createGradientToolTipData = createGradientToolTipData;
71566 function createTooltipData(formatStringProp, categoryValue, valuesSource, seriesValues) {
71567 debug.assertValue(seriesValues, "seriesSource");
71568 debug.assertValue(ToolTipComponent.localizationOptions, "ToolTipComponent.localizationOptions");
71569 debug.assertAnyValue(formatStringProp, 'formatStringProp');
71570 var items = [];
71571 if (categoryValue) {
71572 if (categoryValue.metadata.length > 1) {
71573 var displayName = '';
71574 // This is being done simply for lat/long for now, as that's the only composite category we use. If we ever have tooltips
71575 // involving other composite categories, we need to do a more thorough design and be more careful here.
71576 for (var i = 0, ilen = categoryValue.metadata.length; i < ilen; i++) {
71577 if (i !== 0)
71578 displayName += '/';
71579 displayName += categoryValue.metadata[i].displayName;
71580 }
71581 var categoryFormattedValue = getFormattedValue(categoryValue.metadata[0], formatStringProp, categoryValue.value);
71582 items.push({ displayName: displayName, value: categoryFormattedValue });
71583 }
71584 else {
71585 var categoryFormattedValue = getFormattedValue(categoryValue.metadata[0], formatStringProp, categoryValue.value);
71586 items.push({ displayName: categoryValue.metadata[0].displayName, value: categoryFormattedValue });
71587 }
71588 }
71589 if (valuesSource) {
71590 // Dynamic series value
71591 var dynamicValue = void 0;
71592 if (seriesValues.length > 0) {
71593 var dynamicValueMetadata = seriesValues[0].metadata.source;
71594 dynamicValue = getFormattedValue(valuesSource, formatStringProp, dynamicValueMetadata.groupName);
71595 }
71596 items.push({ displayName: valuesSource.displayName, value: dynamicValue });
71597 }
71598 for (var i = 0; i < seriesValues.length; i++) {
71599 var seriesData = seriesValues[i];
71600 if (seriesData && seriesData.metadata) {
71601 var seriesMetadataColumn = seriesData.metadata.source;
71602 var value = seriesData.value;
71603 var highlightedValue = seriesData.highlightedValue;
71604 if (value || value === 0) {
71605 var formattedValue = getFormattedValue(seriesMetadataColumn, formatStringProp, value);
71606 items.push({ displayName: seriesMetadataColumn.displayName, value: formattedValue });
71607 }
71608 if (highlightedValue || highlightedValue === 0) {
71609 var formattedHighlightedValue = getFormattedValue(seriesMetadataColumn, formatStringProp, highlightedValue);
71610 var displayName = ToolTipComponent.localizationOptions.highlightedValueDisplayName;
71611 items.push({ displayName: displayName, value: formattedHighlightedValue });
71612 }
71613 }
71614 }
71615 return items;
71616 }
71617 function getFormattedValue(column, formatStringProp, value) {
71618 var formatString = getFormatStringFromColumn(column, formatStringProp);
71619 return visuals.valueFormatter.format(value, formatString);
71620 }
71621 function getFormatStringFromColumn(column, formatStringProp) {
71622 if (column) {
71623 var formatString = visuals.valueFormatter.getFormatString(column, formatStringProp, true);
71624 return formatString || column.format;
71625 }
71626 return null;
71627 }
71628 })(TooltipBuilder = visuals.TooltipBuilder || (visuals.TooltipBuilder = {}));
71629 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
71630})(powerbi || (powerbi = {}));
71631/*
71632 * Power BI Visualizations
71633 *
71634 * Copyright (c) Microsoft Corporation
71635 * All rights reserved.
71636 * MIT License
71637 *
71638 * Permission is hereby granted, free of charge, to any person obtaining a copy
71639 * of this software and associated documentation files (the ""Software""), to deal
71640 * in the Software without restriction, including without limitation the rights
71641 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71642 * copies of the Software, and to permit persons to whom the Software is
71643 * furnished to do so, subject to the following conditions:
71644 *
71645 * The above copyright notice and this permission notice shall be included in
71646 * all copies or substantial portions of the Software.
71647 *
71648 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71649 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71650 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
71651 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71652 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71653 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
71654 * THE SOFTWARE.
71655 */
71656var powerbi;
71657(function (powerbi) {
71658 var visuals;
71659 (function (visuals) {
71660 var visualStyles;
71661 (function (visualStyles) {
71662 function create(dataColors) {
71663 if (dataColors === undefined)
71664 dataColors = new visuals.DataColorPalette();
71665 return {
71666 titleText: {
71667 color: { value: 'rgba(51,51,51,1)' }
71668 },
71669 subTitleText: {
71670 color: { value: 'rgba(145,145,145,1)' }
71671 },
71672 colorPalette: {
71673 dataColors: dataColors,
71674 },
71675 labelText: {
71676 color: {
71677 value: 'rgba(51,51,51,1)',
71678 },
71679 fontSize: '11px'
71680 },
71681 isHighContrast: false,
71682 };
71683 }
71684 visualStyles.create = create;
71685 })(visualStyles = visuals.visualStyles || (visuals.visualStyles = {}));
71686 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
71687})(powerbi || (powerbi = {}));
71688/*
71689 * Power BI Visualizations
71690 *
71691 * Copyright (c) Microsoft Corporation
71692 * All rights reserved.
71693 * MIT License
71694 *
71695 * Permission is hereby granted, free of charge, to any person obtaining a copy
71696 * of this software and associated documentation files (the ""Software""), to deal
71697 * in the Software without restriction, including without limitation the rights
71698 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71699 * copies of the Software, and to permit persons to whom the Software is
71700 * furnished to do so, subject to the following conditions:
71701 *
71702 * The above copyright notice and this permission notice shall be included in
71703 * all copies or substantial portions of the Software.
71704 *
71705 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71706 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71707 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
71708 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71709 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71710 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
71711 * THE SOFTWARE.
71712 */
71713var powerbi;
71714(function (powerbi) {
71715 var visuals;
71716 (function (visuals) {
71717 var createClassAndSelector = jsCommon.CssConstants.createClassAndSelector;
71718 /**
71719 * Renders a donut chart.
71720 */
71721 var DonutChart = (function () {
71722 function DonutChart(options) {
71723 if (options) {
71724 this.sliceWidthRatio = options.sliceWidthRatio;
71725 this.animator = options.animator;
71726 this.isScrollable = options.isScrollable ? options.isScrollable : false;
71727 this.disableGeometricCulling = options.disableGeometricCulling ? options.disableGeometricCulling : false;
71728 this.behavior = options.behavior;
71729 this.tooltipsEnabled = options.tooltipsEnabled;
71730 if (options.smallViewPortProperties) {
71731 this.maxHeightToScaleDonutLegend = options.smallViewPortProperties.maxHeightToScaleDonutLegend;
71732 }
71733 }
71734 if (this.sliceWidthRatio == null) {
71735 this.sliceWidthRatio = DonutChart.defaultSliceWidthRatio;
71736 }
71737 }
71738 DonutChart.converter = function (dataView, colors, defaultDataPointColor, viewport, disableGeometricCulling, interactivityService, tooltipsEnabled) {
71739 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
71740 var converter = new DonutChartConversion.DonutChartConverter(dataView, colors, defaultDataPointColor, tooltipsEnabled);
71741 converter.convert();
71742 var d3PieLayout = d3.layout.pie()
71743 .sort(null)
71744 .value(function (d) {
71745 return d.percentage;
71746 });
71747 if (interactivityService) {
71748 interactivityService.applySelectionStateToData(converter.dataPoints);
71749 interactivityService.applySelectionStateToData(converter.legendData.dataPoints);
71750 }
71751 var culledDataPoints = (!disableGeometricCulling && viewport) ? DonutChart.cullDataByViewport(converter.dataPoints, converter.maxValue, viewport) : converter.dataPoints;
71752 return {
71753 dataPointsToDeprecate: culledDataPoints,
71754 dataPoints: d3PieLayout(culledDataPoints),
71755 unCulledDataPoints: converter.dataPoints,
71756 dataPointsToEnumerate: converter.legendData.dataPoints,
71757 legendData: converter.legendData,
71758 hasHighlights: converter.hasHighlights,
71759 dataLabelsSettings: converter.dataLabelsSettings,
71760 legendObjectProperties: converter.legendObjectProperties,
71761 maxValue: converter.maxValue,
71762 visibleGeometryCulled: converter.dataPoints.length !== culledDataPoints.length,
71763 };
71764 };
71765 DonutChart.prototype.init = function (options) {
71766 this.options = options;
71767 var element = options.element;
71768 // Ensure viewport is empty on init
71769 element.empty();
71770 this.parentViewport = options.viewport;
71771 // avoid deep copy
71772 this.currentViewport = {
71773 height: options.viewport.height,
71774 width: options.viewport.width,
71775 };
71776 this.formatter = visuals.valueFormatter.format;
71777 this.data = {
71778 dataPointsToDeprecate: [],
71779 dataPointsToEnumerate: [],
71780 dataPoints: [],
71781 unCulledDataPoints: [],
71782 legendData: { title: "", dataPoints: [], fontSize: visuals.SVGLegend.DefaultFontSizeInPt },
71783 hasHighlights: false,
71784 dataLabelsSettings: visuals.dataLabelUtils.getDefaultDonutLabelSettings(),
71785 };
71786 this.drilled = false;
71787 // Leaving this false for now, will depend on the datacategory in the future
71788 this.allowDrilldown = false;
71789 this.style = options.style;
71790 this.colors = this.style.colorPalette.dataColors;
71791 this.radius = 0;
71792 this.isInteractive = options.interactivity && options.interactivity.isInteractiveLegend;
71793 var donutChartSettings = this.settings;
71794 if (this.behavior) {
71795 this.interactivityService = visuals.createInteractivityService(options.host);
71796 }
71797 this.legend = visuals.createLegend(element, options.interactivity && options.interactivity.isInteractiveLegend, this.interactivityService, this.isScrollable);
71798 this.hostService = options.host;
71799 if (this.isInteractive) {
71800 this.chartRotationAnimationDuration = (donutChartSettings && donutChartSettings.chartRotationAnimationDuration) ? donutChartSettings.chartRotationAnimationDuration : 0;
71801 // Create interactive legend
71802 var legendContainer = this.legendContainer = d3.select(element.get(0))
71803 .append('div')
71804 .classed(DonutChart.InteractiveLegendClassName, true);
71805 this.interactivityState = {
71806 interactiveLegend: new DonutChartInteractiveLegend(this, legendContainer, this.colors, options, this.settings),
71807 valueToAngleFactor: 0,
71808 sliceAngles: [],
71809 currentRotate: 0,
71810 interactiveChosenSliceFinishedSetting: false,
71811 lastChosenInteractiveSliceIndex: 0,
71812 totalDragAngleDifference: 0,
71813 currentIndexDrag: 0,
71814 previousIndexDrag: 0,
71815 previousDragAngle: 0,
71816 donutCenter: { x: 0, y: 0 },
71817 };
71818 }
71819 this.svg = d3.select(element.get(0))
71820 .append('svg')
71821 .style('position', 'absolute')
71822 .classed(DonutChart.ClassName, true);
71823 if (this.behavior)
71824 this.clearCatcher = visuals.appendClearCatcher(this.svg);
71825 this.mainGraphicsContext = this.svg.append('g');
71826 this.mainGraphicsContext.append("g")
71827 .classed('slices', true);
71828 this.labelGraphicsContext = this.svg
71829 .append("g")
71830 .classed(visuals.NewDataLabelUtils.labelGraphicsContextClass.class, true);
71831 this.pie = d3.layout.pie()
71832 .sort(null)
71833 .value(function (d) {
71834 return d.percentage;
71835 });
71836 };
71837 DonutChart.prototype.update = function (options) {
71838 debug.assertValue(options, 'options');
71839 // Viewport resizing
71840 var viewport = options.viewport;
71841 this.parentViewport = viewport;
71842 var dataViews = this.dataViews = options.dataViews;
71843 if (dataViews && dataViews.length > 0 && dataViews[0].categorical) {
71844 var dataViewMetadata = dataViews[0].metadata;
71845 var defaultDataPointColor = undefined;
71846 if (dataViewMetadata) {
71847 var objects = dataViewMetadata.objects;
71848 if (objects) {
71849 defaultDataPointColor = powerbi.DataViewObjects.getFillColor(objects, visuals.donutChartProps.dataPoint.defaultColor);
71850 }
71851 }
71852 this.data = DonutChart.converter(dataViews[0], this.colors, defaultDataPointColor, this.currentViewport, this.disableGeometricCulling, this.interactivityService, this.tooltipsEnabled);
71853 this.data.defaultDataPointColor = defaultDataPointColor;
71854 if (!(this.options.interactivity && this.options.interactivity.isInteractiveLegend))
71855 this.renderLegend();
71856 }
71857 else {
71858 this.data = {
71859 dataPointsToDeprecate: [],
71860 dataPointsToEnumerate: [],
71861 dataPoints: [],
71862 unCulledDataPoints: [],
71863 legendData: { title: "", dataPoints: [] },
71864 hasHighlights: false,
71865 dataLabelsSettings: visuals.dataLabelUtils.getDefaultDonutLabelSettings(),
71866 };
71867 }
71868 this.initViewportDependantProperties();
71869 this.initDonutProperties();
71870 this.updateInternal(this.data, options.suppressAnimations);
71871 this.hasSetData = true;
71872 if (dataViews) {
71873 var warnings = visuals.getInvalidValueWarnings(dataViews, false /*supportsNaN*/, false /*supportsNegativeInfinity*/, false /*supportsPositiveInfinity*/);
71874 this.hostService.setWarnings(warnings);
71875 }
71876 };
71877 DonutChart.prototype.onDataChanged = function (options) {
71878 debug.assertValue(options, 'options');
71879 this.update({
71880 dataViews: options.dataViews,
71881 suppressAnimations: options.suppressAnimations,
71882 viewport: this.currentViewport,
71883 });
71884 };
71885 DonutChart.prototype.onResizing = function (viewport) {
71886 this.update({
71887 dataViews: this.dataViews,
71888 suppressAnimations: true,
71889 viewport: viewport,
71890 });
71891 };
71892 DonutChart.prototype.enumerateObjectInstances = function (options) {
71893 var enumeration = new visuals.ObjectEnumerationBuilder();
71894 var dataLabelsSettings = this.data && this.data.dataLabelsSettings
71895 ? this.data.dataLabelsSettings
71896 : visuals.dataLabelUtils.getDefaultDonutLabelSettings();
71897 switch (options.objectName) {
71898 case 'legend':
71899 this.enumerateLegend(enumeration);
71900 break;
71901 case 'dataPoint':
71902 this.enumerateDataPoints(enumeration);
71903 break;
71904 case 'labels':
71905 var labelSettingOptions = {
71906 enumeration: enumeration,
71907 dataLabelsSettings: dataLabelsSettings,
71908 show: true,
71909 displayUnits: true,
71910 precision: true,
71911 fontSize: true,
71912 labelStyle: true,
71913 };
71914 visuals.dataLabelUtils.enumerateDataLabels(labelSettingOptions);
71915 break;
71916 }
71917 return enumeration.complete();
71918 };
71919 DonutChart.prototype.enumerateDataPoints = function (enumeration) {
71920 var data = this.data;
71921 if (!data)
71922 return;
71923 var dataPoints = data.dataPointsToEnumerate;
71924 var dataPointsLength = dataPoints.length;
71925 for (var i = 0; i < dataPointsLength; i++) {
71926 var dataPoint = dataPoints[i];
71927 enumeration.pushInstance({
71928 objectName: 'dataPoint',
71929 displayName: dataPoint.label,
71930 selector: visuals.ColorHelper.normalizeSelector(dataPoint.identity.getSelector()),
71931 properties: {
71932 fill: { solid: { color: dataPoint.color } }
71933 },
71934 });
71935 }
71936 };
71937 DonutChart.prototype.enumerateLegend = function (enumeration) {
71938 var data = this.data;
71939 if (!data)
71940 return;
71941 var legendObjectProperties = { legend: data.legendObjectProperties };
71942 var show = powerbi.DataViewObjects.getValue(legendObjectProperties, visuals.donutChartProps.legend.show, this.legend.isVisible());
71943 var showTitle = powerbi.DataViewObjects.getValue(legendObjectProperties, visuals.donutChartProps.legend.showTitle, true);
71944 var titleText = powerbi.DataViewObjects.getValue(legendObjectProperties, visuals.donutChartProps.legend.titleText, this.data.legendData.title);
71945 var labelColor = powerbi.DataViewObject.getValue(legendObjectProperties, visuals.legendProps.labelColor, this.data.legendData.labelColor);
71946 var labelFontSize = powerbi.DataViewObject.getValue(legendObjectProperties, visuals.legendProps.fontSize, this.data.legendData.fontSize);
71947 enumeration.pushInstance({
71948 selector: null,
71949 objectName: 'legend',
71950 properties: {
71951 show: show,
71952 position: visuals.LegendPosition[this.legend.getOrientation()],
71953 showTitle: showTitle,
71954 titleText: titleText,
71955 labelColor: labelColor,
71956 fontSize: labelFontSize
71957 }
71958 });
71959 };
71960 DonutChart.prototype.setInteractiveChosenSlice = function (sliceIndex) {
71961 var _this = this;
71962 if (this.interactivityState.sliceAngles.length === 0)
71963 return;
71964 this.interactivityState.lastChosenInteractiveSliceIndex = sliceIndex;
71965 this.interactivityState.interactiveChosenSliceFinishedSetting = false;
71966 var viewport = this.currentViewport;
71967 var moduledIndex = sliceIndex % this.data.dataPoints.length;
71968 var angle = this.interactivityState.sliceAngles[moduledIndex];
71969 this.svg.select('g')
71970 .transition()
71971 .duration(this.chartRotationAnimationDuration)
71972 .ease('elastic')
71973 .attr('transform', visuals.SVGUtil.translateAndRotate(viewport.width / 2, viewport.height / 2, 0, 0, angle))
71974 .each('end', function () { _this.interactivityState.interactiveChosenSliceFinishedSetting = true; });
71975 this.interactivityState.currentRotate = angle;
71976 this.interactivityState.interactiveLegend.updateLegend(moduledIndex);
71977 // Set the opacity of chosen slice to full and the others to semi-transparent
71978 this.svg.selectAll('.slice').attr('opacity', function (d, index) {
71979 return index === moduledIndex ? 1 : 0.6;
71980 });
71981 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
71982 };
71983 DonutChart.prototype.calculateRadius = function () {
71984 var viewport = this.currentViewport;
71985 if (!this.isInteractive && this.data && this.data.dataLabelsSettings.show) {
71986 // if we have category or data labels, use a sigmoid to blend the desired denominator from 2 to 3.
71987 // if we are taller than we are wide, we need to use a larger denominator to leave horizontal room for the labels.
71988 var hw = viewport.height / viewport.width;
71989 var denom = 2 + (1 / (1 + Math.exp(-5 * (hw - 1))));
71990 return Math.min(viewport.height, viewport.width) / denom;
71991 }
71992 // no labels (isInteractive does not have labels since the interactive legend shows extra info)
71993 return Math.min(viewport.height, viewport.width) / 2;
71994 };
71995 DonutChart.prototype.getScaleForLegendArrow = function () {
71996 var ratio = 1.0;
71997 if (this.maxHeightToScaleDonutLegend && this.currentViewport.height < this.maxHeightToScaleDonutLegend) {
71998 ratio = this.currentViewport.height / this.maxHeightToScaleDonutLegend;
71999 }
72000 return ratio;
72001 };
72002 DonutChart.prototype.initViewportDependantProperties = function (duration) {
72003 if (duration === void 0) { duration = 0; }
72004 this.currentViewport.height = this.parentViewport.height;
72005 this.currentViewport.width = this.parentViewport.width;
72006 var viewport = this.currentViewport;
72007 if (this.isInteractive) {
72008 viewport.height -= DonutChart.InteractiveLegendContainerHeight; // leave space for the legend
72009 }
72010 else {
72011 var legendMargins = this.legend.getMargins();
72012 viewport.height -= legendMargins.height;
72013 viewport.width -= legendMargins.width;
72014 }
72015 this.svg.attr({
72016 'width': viewport.width,
72017 'height': viewport.height
72018 });
72019 if (this.isInteractive) {
72020 this.legendContainer
72021 .style({
72022 'width': '100%',
72023 'height': DonutChart.InteractiveLegendContainerHeight + 'px',
72024 'overflow': 'hidden',
72025 'top': 0
72026 });
72027 this.svg
72028 .style('top', DonutChart.InteractiveLegendContainerHeight);
72029 }
72030 else {
72031 visuals.Legend.positionChartArea(this.svg, this.legend);
72032 }
72033 this.previousRadius = this.radius;
72034 var radius = this.radius = this.calculateRadius();
72035 var halfViewportWidth = viewport.width / 2;
72036 var halfViewportHeight = viewport.height / 2;
72037 this.arc = d3.svg.arc();
72038 this.outerArc = d3.svg.arc()
72039 .innerRadius(radius * DonutChart.OuterArcRadiusRatio)
72040 .outerRadius(radius * DonutChart.OuterArcRadiusRatio);
72041 if (this.isInteractive) {
72042 this.mainGraphicsContext.attr('transform', visuals.SVGUtil.translate(halfViewportWidth, halfViewportHeight));
72043 this.labelGraphicsContext.attr('transform', visuals.SVGUtil.translate(halfViewportWidth, halfViewportHeight));
72044 }
72045 else {
72046 this.mainGraphicsContext.transition().duration(duration).attr('transform', visuals.SVGUtil.translate(halfViewportWidth, halfViewportHeight));
72047 this.labelGraphicsContext.transition().duration(duration).attr('transform', visuals.SVGUtil.translate(halfViewportWidth, halfViewportHeight));
72048 }
72049 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
72050 };
72051 DonutChart.prototype.initDonutProperties = function () {
72052 this.donutProperties = {
72053 viewport: this.currentViewport,
72054 radius: this.radius,
72055 arc: this.arc.innerRadius(0).outerRadius(this.radius * DonutChart.InnerArcRadiusRatio),
72056 outerArc: this.outerArc,
72057 innerArcRadiusRatio: DonutChart.InnerArcRadiusRatio,
72058 outerArcRadiusRatio: DonutChart.OuterArcRadiusRatio,
72059 dataLabelsSettings: this.data.dataLabelsSettings,
72060 };
72061 };
72062 DonutChart.prototype.mergeDatasets = function (first, second) {
72063 var secondSet = d3.set();
72064 second.forEach(function (d) {
72065 secondSet.add(d.identity ? d.identity.getKey() : d.data.identity.getKey());
72066 });
72067 var onlyFirst = first.filter(function (d) {
72068 return !secondSet.has(d.identity ? d.identity.getKey() : d.data.identity.getKey());
72069 }).map(function (d) {
72070 var derived = powerbi.Prototype.inherit(d);
72071 derived.percentage === undefined ? derived.data.percentage = 0 : derived.percentage = 0;
72072 return derived;
72073 });
72074 return d3.merge([second, onlyFirst]);
72075 };
72076 DonutChart.prototype.updateInternal = function (data, suppressAnimations, duration) {
72077 if (duration === void 0) { duration = 0; }
72078 var viewport = this.currentViewport;
72079 duration = duration || visuals.AnimatorCommon.GetAnimationDuration(this.animator, suppressAnimations);
72080 if (this.animator) {
72081 var layout = DonutChart.getLayout(this.radius, this.sliceWidthRatio, viewport);
72082 var result = void 0;
72083 var shapes_1;
72084 var highlightShapes = void 0;
72085 var labelSettings = data.dataLabelsSettings;
72086 var labels = [];
72087 if (labelSettings && labelSettings.show) {
72088 labels = this.createLabels();
72089 }
72090 if (!suppressAnimations) {
72091 var animationOptions = {
72092 viewModel: data,
72093 colors: this.colors,
72094 graphicsContext: this.mainGraphicsContext,
72095 labelGraphicsContext: this.labelGraphicsContext,
72096 interactivityService: this.interactivityService,
72097 layout: layout,
72098 radius: this.radius,
72099 sliceWidthRatio: this.sliceWidthRatio,
72100 viewport: viewport,
72101 labels: labels,
72102 innerArcRadiusRatio: DonutChart.InnerArcRadiusRatio,
72103 };
72104 result = this.animator.animate(animationOptions);
72105 shapes_1 = result.shapes;
72106 highlightShapes = result.highlightShapes;
72107 }
72108 if (suppressAnimations || result.failed) {
72109 shapes_1 = DonutChart.drawDefaultShapes(this.svg, data, layout, this.colors, this.radius, this.interactivityService && this.interactivityService.hasSelection(), this.sliceWidthRatio, this.data.defaultDataPointColor);
72110 highlightShapes = DonutChart.drawDefaultHighlightShapes(this.svg, data, layout, this.colors, this.radius, this.sliceWidthRatio);
72111 visuals.NewDataLabelUtils.drawDefaultLabels(this.labelGraphicsContext, labels, false, true, true /*has tooltip */);
72112 visuals.NewDataLabelUtils.drawLabelLeaderLines(this.labelGraphicsContext, labels);
72113 }
72114 this.assignInteractions(shapes_1, highlightShapes, data);
72115 if (this.tooltipsEnabled) {
72116 visuals.TooltipManager.addTooltip(shapes_1, function (tooltipEvent) { return tooltipEvent.data.data.tooltipInfo; });
72117 visuals.TooltipManager.addTooltip(highlightShapes, function (tooltipEvent) { return tooltipEvent.data.data.tooltipInfo; });
72118 }
72119 }
72120 else {
72121 this.updateInternalToMove(data, duration);
72122 }
72123 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
72124 };
72125 DonutChart.prototype.createLabels = function () {
72126 var labelLayout = new powerbi.DonutLabelLayout({
72127 maximumOffset: visuals.NewDataLabelUtils.maxLabelOffset,
72128 startingOffset: visuals.NewDataLabelUtils.startingLabelOffset
72129 }, this.donutProperties);
72130 var labelDataPoints = this.createLabelDataPoints();
72131 return labelLayout.layout(labelDataPoints);
72132 };
72133 DonutChart.prototype.createLabelDataPoints = function () {
72134 var data = this.data;
72135 var labelDataPoints = [];
72136 var measureFormatterCache = visuals.dataLabelUtils.createColumnFormatterCacheManager();
72137 var alternativeScale = null;
72138 if (data.dataLabelsSettings.displayUnits === 0)
72139 alternativeScale = d3.max(data.dataPoints, function (d) { return Math.abs(d.data.measure); });
72140 for (var i = 0; i < this.data.dataPoints.length; i++) {
72141 var label = this.createLabelDataPoint(data.dataPoints[i], alternativeScale, measureFormatterCache);
72142 labelDataPoints.push(label);
72143 }
72144 return labelDataPoints;
72145 };
72146 DonutChart.prototype.createLabelDataPoint = function (d, alternativeScale, measureFormatterCache) {
72147 var labelPoint = this.outerArc.centroid(d);
72148 var labelX = visuals.DonutLabelUtils.getXPositionForDonutLabel(labelPoint[0]);
72149 var labelY = labelPoint[1];
72150 var labelSettings = this.data.dataLabelsSettings;
72151 var measureFormatter = measureFormatterCache.getOrCreate(d.data.labelFormatString, labelSettings, alternativeScale);
72152 var position = labelX < 0 ? 4 /* Left */ : 8 /* Right */;
72153 var pointPosition = {
72154 point: {
72155 x: labelX,
72156 y: labelY,
72157 },
72158 validPositions: [position],
72159 radius: 0,
72160 };
72161 var outsideFill = labelSettings.labelColor ? labelSettings.labelColor : visuals.NewDataLabelUtils.defaultLabelColor;
72162 var dataLabel;
72163 var dataLabelSize;
72164 var categoryLabel;
72165 var categoryLabelSize;
72166 var textSize;
72167 var labelSettingsStyle = labelSettings.labelStyle;
72168 var fontSize = labelSettings.fontSize;
72169 var tooltip = "";
72170 if (labelSettingsStyle === visuals.labelStyle.both || labelSettingsStyle === visuals.labelStyle.data) {
72171 dataLabel = measureFormatter.format(d.data.highlightValue != null ? d.data.highlightValue : d.data.measure);
72172 dataLabelSize = visuals.NewDataLabelUtils.getTextSize(dataLabel, fontSize);
72173 }
72174 if (labelSettingsStyle === visuals.labelStyle.both || labelSettingsStyle === visuals.labelStyle.category) {
72175 categoryLabel = d.data.label;
72176 categoryLabelSize = visuals.NewDataLabelUtils.getTextSize(categoryLabel, fontSize);
72177 }
72178 switch (labelSettingsStyle) {
72179 case visuals.labelStyle.both:
72180 var text = categoryLabel + " (" + dataLabel + ")";
72181 tooltip = text;
72182 textSize = visuals.NewDataLabelUtils.getTextSize(text, fontSize);
72183 break;
72184 case visuals.labelStyle.category:
72185 textSize = _.clone(categoryLabelSize);
72186 tooltip = categoryLabel;
72187 break;
72188 case visuals.labelStyle.data:
72189 textSize = _.clone(dataLabelSize);
72190 tooltip = dataLabel;
72191 break;
72192 }
72193 var leaderLinePoints = visuals.DonutLabelUtils.getLabelLeaderLineForDonutChart(d, this.donutProperties, pointPosition.point);
72194 var leaderLinesSize = visuals.DonutLabelUtils.getLabelLeaderLinesSizeForDonutChart(leaderLinePoints);
72195 return {
72196 isPreferred: true,
72197 text: "",
72198 tooltip: tooltip,
72199 textSize: textSize,
72200 outsideFill: outsideFill,
72201 fontSize: fontSize,
72202 identity: d.data.identity,
72203 parentShape: pointPosition,
72204 insideFill: visuals.NewDataLabelUtils.defaultInsideLabelColor,
72205 parentType: 0 /* Point */,
72206 alternativeScale: alternativeScale,
72207 donutArcDescriptor: d,
72208 angle: (d.startAngle + d.endAngle) / 2 - (Math.PI / 2),
72209 dataLabel: dataLabel,
72210 dataLabelSize: dataLabelSize,
72211 categoryLabel: categoryLabel,
72212 categoryLabelSize: categoryLabelSize,
72213 leaderLinePoints: leaderLinePoints,
72214 linesSize: leaderLinesSize,
72215 };
72216 };
72217 DonutChart.prototype.renderLegend = function () {
72218 if (!this.isInteractive) {
72219 var legendObjectProperties = this.data.legendObjectProperties;
72220 if (legendObjectProperties) {
72221 var legendData = this.data.legendData;
72222 visuals.LegendData.update(legendData, legendObjectProperties);
72223 var position = legendObjectProperties[visuals.legendProps.position];
72224 if (position)
72225 this.legend.changeOrientation(visuals.LegendPosition[position]);
72226 this.legend.drawLegend(legendData, this.parentViewport);
72227 }
72228 else {
72229 this.legend.changeOrientation(visuals.LegendPosition.Top);
72230 this.legend.drawLegend({ dataPoints: [] }, this.parentViewport);
72231 }
72232 }
72233 };
72234 DonutChart.prototype.addInteractiveLegendArrow = function () {
72235 if (!this.data || !this.data.dataPoints || this.data.dataPoints.length === 0)
72236 return;
72237 var arrowHeightOffset = 11;
72238 var arrowWidthOffset = 33 / 2;
72239 if (!this.interactiveLegendArrow) {
72240 var interactiveLegendArrow = this.svg.append('g');
72241 interactiveLegendArrow.append('path')
72242 .classed(DonutChart.InteractiveLegendArrowClassName, true)
72243 .attr('d', 'M1.5,2.6C0.65,1.15,1.85,0,3,0l27,0c1.65,0,2.35,1.15,1.5,2.6L18,26.45c-0.8,1.45-2.15,1.45-2.95,0L1.95,2.6z');
72244 this.interactiveLegendArrow = interactiveLegendArrow;
72245 }
72246 var viewport = this.currentViewport;
72247 // Calculate the offsets from the legend container to the arrow.
72248 var scaleRatio = this.getScaleForLegendArrow();
72249 var distanceBetweenLegendAndArrow = (viewport.height - 2 * this.radius) / 2 + (arrowHeightOffset * scaleRatio);
72250 var middleOfChart = viewport.width / 2 - (arrowWidthOffset * scaleRatio);
72251 this.interactiveLegendArrow.attr('transform', visuals.SVGUtil.translateAndScale(middleOfChart, distanceBetweenLegendAndArrow, scaleRatio));
72252 };
72253 DonutChart.prototype.calculateSliceAngles = function () {
72254 var angles = [];
72255 var data = this.data.dataPoints;
72256 if (data.length === 0) {
72257 this.interactivityState.valueToAngleFactor = 0;
72258 this.interactivityState.sliceAngles = [];
72259 return;
72260 }
72261 var sum = 0;
72262 for (var i = 0, ilen = data.length; i < ilen; i++) {
72263 sum += data[i].data.percentage; // value is an absolute number
72264 }
72265 debug.assert(sum !== 0, 'sum of slices values cannot be zero');
72266 this.interactivityState.valueToAngleFactor = 360 / sum; // Calculate the ratio between 360 and the sum to know the angles to rotate by
72267 var currentAngle = 0;
72268 for (var i = 0, ilen = data.length; i < ilen; i++) {
72269 var relativeAngle = data[i].data.percentage * this.interactivityState.valueToAngleFactor;
72270 currentAngle += relativeAngle;
72271 angles.push((relativeAngle / 2) - currentAngle);
72272 }
72273 this.interactivityState.sliceAngles = angles;
72274 };
72275 DonutChart.prototype.assignInteractions = function (slices, highlightSlices, data) {
72276 // assign interactions according to chart interactivity type
72277 if (this.isInteractive) {
72278 this.assignInteractiveChartInteractions(slices);
72279 }
72280 else if (this.interactivityService) {
72281 var dataPoints = data.dataPoints.map(function (value) { return value.data; });
72282 var behaviorOptions = {
72283 clearCatcher: this.clearCatcher,
72284 slices: slices,
72285 highlightSlices: highlightSlices,
72286 allowDrilldown: this.allowDrilldown,
72287 visual: this,
72288 hasHighlights: data.hasHighlights,
72289 svg: this.svg,
72290 };
72291 this.interactivityService.bind(dataPoints, this.behavior, behaviorOptions);
72292 }
72293 };
72294 DonutChart.prototype.setDrilldown = function (selection) {
72295 if (selection) {
72296 var d3PieLayout = d3.layout.pie()
72297 .sort(null)
72298 .value(function (d) {
72299 return d.percentage;
72300 });
72301 // Drill into the current selection.
72302 var legendDataPoints = [{ label: selection.label, color: selection.color, icon: visuals.LegendIcon.Box, identity: selection.identity, selected: selection.selected }];
72303 var legendData = { title: "", dataPoints: legendDataPoints };
72304 var drilledDataPoints = d3PieLayout(selection.internalDataPoints);
72305 this.updateInternal({
72306 dataPointsToDeprecate: selection.internalDataPoints,
72307 dataPoints: drilledDataPoints,
72308 unCulledDataPoints: drilledDataPoints.map(function (value) { return value.data; }),
72309 legendData: legendData,
72310 hasHighlights: false,
72311 dataLabelsSettings: this.data.dataLabelsSettings,
72312 }, false /* suppressAnimations */, DonutChart.DrillDownAnimationDuration);
72313 }
72314 else {
72315 // Pop out of drill down to view the "outer" data.
72316 this.updateInternal(this.data, false /* suppressAnimations */, DonutChart.DrillDownAnimationDuration);
72317 }
72318 };
72319 DonutChart.prototype.assignInteractiveChartInteractions = function (slice) {
72320 var _this = this;
72321 var svg = this.svg;
72322 this.interactivityState.interactiveChosenSliceFinishedSetting = true;
72323 var svgRect = svg.node().getBoundingClientRect();
72324 this.interactivityState.donutCenter = { x: svgRect.left + svgRect.width / 2, y: svgRect.top + svgRect.height / 2 }; // Center of the donut chart
72325 this.interactivityState.totalDragAngleDifference = 0;
72326 this.interactivityState.currentRotate = 0;
72327 this.calculateSliceAngles();
72328 // Set the on click method for the slices so thsete pie chart will turn according to each slice's corresponding angle [the angle its on top]
72329 slice.on('click', function (d, clickedIndex) {
72330 if (d3.event.defaultPrevented)
72331 return; // click was suppressed, for example from drag event
72332 _this.setInteractiveChosenSlice(clickedIndex);
72333 });
72334 // Set the drag events
72335 var drag = d3.behavior.drag()
72336 .origin(Object)
72337 .on('dragstart', function () { return _this.interactiveDragStart(); })
72338 .on('drag', function () { return _this.interactiveDragMove(); })
72339 .on('dragend', function () { return _this.interactiveDragEnd(); });
72340 svg
72341 .style('touch-action', 'none')
72342 .call(drag);
72343 };
72344 /**
72345 * Get the angle (in degrees) of the drag event coordinates.
72346 * The angle is calculated against the plane of the center of the donut
72347 * (meaning, when the center of the donut is at (0,0) coordinates).
72348 */
72349 DonutChart.prototype.getAngleFromDragEvent = function () {
72350 var interactivityState = this.interactivityState;
72351 // get pageX and pageY (coordinates of the drag event) according to event type
72352 var pageX, pageY;
72353 var sourceEvent = d3.event.sourceEvent;
72354 // check if that's a touch event or not
72355 if (sourceEvent.type.toLowerCase().indexOf('touch') !== -1) {
72356 if (sourceEvent.touches.length !== 1)
72357 return null; // in case there isn't a single touch - return null and do nothing.
72358 // take the first, single, touch surface.
72359 var touch = sourceEvent.touches[0];
72360 pageX = touch.pageX;
72361 pageY = touch.pageY;
72362 }
72363 else {
72364 pageX = sourceEvent.pageX;
72365 pageY = sourceEvent.pageY;
72366 }
72367 // Adjust the coordinates, putting the donut center as the (0,0) coordinates
72368 var adjustedCoordinates = { x: pageX - interactivityState.donutCenter.x, y: -pageY + interactivityState.donutCenter.y };
72369 // Move to polar axis - take only the angle (theta), and convert to degrees
72370 var angleToThePlane = Math.atan2(adjustedCoordinates.y, adjustedCoordinates.x) * 180 / Math.PI;
72371 return angleToThePlane;
72372 };
72373 DonutChart.prototype.interactiveDragStart = function () {
72374 this.interactivityState.totalDragAngleDifference = 0;
72375 this.interactivityState.previousDragAngle = this.getAngleFromDragEvent();
72376 };
72377 DonutChart.prototype.interactiveDragMove = function () {
72378 var data = this.data.dataPoints;
72379 var viewport = this.currentViewport;
72380 var interactivityState = this.interactivityState;
72381 if (interactivityState.interactiveChosenSliceFinishedSetting === true) {
72382 // get current angle from the drag event
72383 var currentDragAngle = this.getAngleFromDragEvent();
72384 if (!currentDragAngle)
72385 return; // if no angle was returned, do nothing
72386 // compare it to the previous drag event angle
72387 var angleDragDiff = interactivityState.previousDragAngle - currentDragAngle;
72388 interactivityState.totalDragAngleDifference += angleDragDiff;
72389 interactivityState.previousDragAngle = currentDragAngle;
72390 // Rotate the chart by the difference in angles
72391 interactivityState.currentRotate += angleDragDiff;
72392 // Rotate the chart to the current rotate angle
72393 this.svg.select('g')
72394 .attr('transform', visuals.SVGUtil.translateAndRotate(viewport.width / 2, viewport.height / 2, 0, 0, this.interactivityState.currentRotate));
72395 var currentHigherLimit = data[0].data.percentage * interactivityState.valueToAngleFactor;
72396 var currentAngle = interactivityState.currentRotate <= 0 ? (interactivityState.currentRotate * -1) % 360 : (360 - (interactivityState.currentRotate % 360));
72397 interactivityState.currentIndexDrag = 0;
72398 //consider making this ++interactivityState.currentIndexDrag ? then you don't need the if statement, the interactivityState.currentIndexDrag +1 and interactivityState.currentIndexDrag++
72399 // Check the current index according to the angle
72400 var dataLength = data.length;
72401 while ((interactivityState.currentIndexDrag < dataLength) && (currentAngle > currentHigherLimit)) {
72402 if (interactivityState.currentIndexDrag < (dataLength - 1)) {
72403 currentHigherLimit += (data[interactivityState.currentIndexDrag + 1].data.percentage * interactivityState.valueToAngleFactor);
72404 }
72405 interactivityState.currentIndexDrag++;
72406 }
72407 // If the index changed update the legend and opacity
72408 if (interactivityState.currentIndexDrag !== interactivityState.previousIndexDrag) {
72409 interactivityState.interactiveLegend.updateLegend(interactivityState.currentIndexDrag);
72410 // set the opacticity of the top slice to full and the others to semi-transparent
72411 this.svg.selectAll('.slice').attr('opacity', function (d, index) {
72412 return index === interactivityState.currentIndexDrag ? DonutChart.OpaqueOpacity : DonutChart.SemiTransparentOpacity;
72413 });
72414 interactivityState.previousIndexDrag = interactivityState.currentIndexDrag;
72415 }
72416 }
72417 };
72418 DonutChart.prototype.interactiveDragEnd = function () {
72419 // If totalDragDifference was changed, means we have a drag event (compared to a click event)
72420 if (this.interactivityState.totalDragAngleDifference !== 0) {
72421 this.setInteractiveChosenSlice(this.interactivityState.currentIndexDrag);
72422 // drag happened - disable click event
72423 d3.event.sourceEvent.stopPropagation();
72424 }
72425 };
72426 DonutChart.prototype.updateInternalToMove = function (data, duration) {
72427 if (duration === void 0) { duration = 0; }
72428 // Cache for performance
72429 var svg = this.svg;
72430 var pie = this.pie;
72431 var key = this.key;
72432 var arc = this.arc;
72433 var radius = this.radius;
72434 var previousRadius = this.previousRadius;
72435 var sliceWidthRatio = this.sliceWidthRatio;
72436 var existingData = this.svg.select('.slices')
72437 .selectAll('path' + DonutChart.sliceClass.selector)
72438 .data().map(function (d) { return d.data; });
72439 if (existingData.length === 0) {
72440 existingData = data.dataPointsToDeprecate;
72441 }
72442 var is = this.mergeDatasets(existingData, data.dataPointsToDeprecate);
72443 var slice = svg.select('.slices')
72444 .selectAll('path' + DonutChart.sliceClass.selector)
72445 .data(pie(data.dataPointsToDeprecate), key);
72446 slice.enter()
72447 .insert('path')
72448 .classed(DonutChart.sliceClass.class, true)
72449 .each(function (d) { this._current = d; });
72450 slice = svg.select('.slices')
72451 .selectAll('path' + DonutChart.sliceClass.selector)
72452 .data(pie(is), key);
72453 var innerRadius = radius * sliceWidthRatio;
72454 DonutChart.isSingleColor(data.dataPoints);
72455 slice
72456 .style('fill', function (d) { return d.data.color; })
72457 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, false, data.hasHighlights); })
72458 .style('stroke', 'white')
72459 .style('stroke-dasharray', function (d) { return DonutChart.drawStrokeForDonutChart(radius, DonutChart.InnerArcRadiusRatio, d, sliceWidthRatio); })
72460 .style('stroke-width', function (d) { return d.data.strokeWidth; })
72461 .transition().duration(duration)
72462 .attrTween('d', function (d) {
72463 var i = d3.interpolate(this._current, d), k = d3.interpolate(previousRadius * DonutChart.InnerArcRadiusRatio, radius * DonutChart.InnerArcRadiusRatio);
72464 this._current = i(0);
72465 return function (t) {
72466 return arc.innerRadius(innerRadius).outerRadius(k(t))(i(t));
72467 };
72468 });
72469 slice = svg.select('.slices')
72470 .selectAll('path' + DonutChart.sliceClass.selector)
72471 .data(pie(data.dataPointsToDeprecate), key);
72472 slice.exit()
72473 .transition()
72474 .delay(duration)
72475 .duration(0)
72476 .remove();
72477 // For interactive chart, there shouldn't be slice labels (as you have the legend).
72478 if (!this.isInteractive) {
72479 var labelSettings = data.dataLabelsSettings;
72480 var labels = [];
72481 if (labelSettings && labelSettings.show) {
72482 labels = this.createLabels();
72483 }
72484 visuals.NewDataLabelUtils.drawDefaultLabels(this.labelGraphicsContext, labels, false, true);
72485 visuals.NewDataLabelUtils.drawLabelLeaderLines(this.labelGraphicsContext, labels);
72486 }
72487 var highlightSlices = undefined;
72488 if (data.hasHighlights) {
72489 // Draw partial highlight slices.
72490 highlightSlices = svg
72491 .select('.slices')
72492 .selectAll('path' + DonutChart.sliceHighlightClass.selector)
72493 .data(pie(data.dataPointsToDeprecate), key);
72494 highlightSlices
72495 .enter()
72496 .insert('path')
72497 .classed(DonutChart.sliceHighlightClass.class, true)
72498 .each(function (d) { this._current = d; });
72499 DonutChart.isSingleColor(data.dataPoints);
72500 highlightSlices
72501 .style('fill', function (d) { return d.data.color; })
72502 .style('fill-opacity', 1.0)
72503 .style('stroke', 'white')
72504 .style('stroke-dasharray', function (d) { return DonutChart.drawStrokeForDonutChart(radius, DonutChart.InnerArcRadiusRatio, d, sliceWidthRatio, d.data.highlightRatio); })
72505 .style('stroke-width', function (d) { return d.data.highlightRatio === 0 ? 0 : d.data.strokeWidth; })
72506 .transition().duration(duration)
72507 .attrTween('d', function (d) {
72508 var i = d3.interpolate(this._current, d), k = d3.interpolate(previousRadius * DonutChart.InnerArcRadiusRatio, DonutChart.getHighlightRadius(radius, sliceWidthRatio, d.data.highlightRatio));
72509 this._current = i(0);
72510 return function (t) {
72511 return arc.innerRadius(innerRadius).outerRadius(k(t))(i(t));
72512 };
72513 });
72514 highlightSlices
72515 .exit()
72516 .transition()
72517 .delay(duration)
72518 .duration(0)
72519 .remove();
72520 }
72521 else {
72522 svg
72523 .selectAll('path' + DonutChart.sliceHighlightClass.selector)
72524 .transition()
72525 .delay(duration)
72526 .duration(0)
72527 .remove();
72528 }
72529 this.assignInteractions(slice, highlightSlices, data);
72530 if (this.tooltipsEnabled) {
72531 visuals.TooltipManager.addTooltip(slice, function (tooltipEvent) { return tooltipEvent.data.data.tooltipInfo; });
72532 if (data.hasHighlights) {
72533 visuals.TooltipManager.addTooltip(highlightSlices, function (tooltipEvent) { return tooltipEvent.data.data.tooltipInfo; });
72534 }
72535 }
72536 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.options);
72537 if (this.isInteractive) {
72538 this.addInteractiveLegendArrow();
72539 this.interactivityState.interactiveLegend.drawLegend(this.data.dataPointsToDeprecate);
72540 this.setInteractiveChosenSlice(this.interactivityState.lastChosenInteractiveSliceIndex ? this.interactivityState.lastChosenInteractiveSliceIndex : 0);
72541 }
72542 };
72543 DonutChart.drawDefaultShapes = function (graphicsContext, donutData, layout, colors, radius, hasSelection, sliceWidthRatio, defaultColor) {
72544 var shapes = graphicsContext.select('.slices')
72545 .selectAll('path' + DonutChart.sliceClass.selector)
72546 .data(donutData.dataPoints, function (d) { return d.data.identity.getKey(); });
72547 shapes.enter()
72548 .insert('path')
72549 .classed(DonutChart.sliceClass.class, true);
72550 DonutChart.isSingleColor(donutData.dataPoints);
72551 shapes
72552 .style('fill', function (d) { return d.data.color; })
72553 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, false, hasSelection, donutData.hasHighlights); })
72554 .style('stroke-dasharray', function (d) { return DonutChart.drawStrokeForDonutChart(radius, DonutChart.InnerArcRadiusRatio, d, sliceWidthRatio); })
72555 .style('stroke-width', function (d) { return d.data.strokeWidth; })
72556 .attr(layout.shapeLayout);
72557 shapes.exit()
72558 .remove();
72559 return shapes;
72560 };
72561 DonutChart.drawDefaultHighlightShapes = function (graphicsContext, donutData, layout, colors, radius, sliceWidthRatio) {
72562 var shapes = graphicsContext.select('.slices')
72563 .selectAll('path' + DonutChart.sliceHighlightClass.selector)
72564 .data(donutData.dataPoints.filter(function (value) { return value.data.highlightRatio != null; }), function (d) { return d.data.identity.getKey(); });
72565 shapes.enter()
72566 .insert('path')
72567 .classed(DonutChart.sliceHighlightClass.class, true)
72568 .each(function (d) { this._current = d; });
72569 DonutChart.isSingleColor(donutData.dataPoints);
72570 shapes
72571 .style('fill', function (d) { return d.data.color; })
72572 .style('fill-opacity', function (d) { return visuals.ColumnUtil.getFillOpacity(d.data.selected, true, false, donutData.hasHighlights); })
72573 .style('stroke', 'white')
72574 .style('stroke-dasharray', function (d) { return DonutChart.drawStrokeForDonutChart(radius, DonutChart.InnerArcRadiusRatio, d, sliceWidthRatio, d.data.highlightRatio); })
72575 .style('stroke-width', function (d) { return d.data.highlightRatio === 0 ? 0 : d.data.strokeWidth; })
72576 .attr(layout.highlightShapeLayout);
72577 shapes.exit()
72578 .remove();
72579 return shapes;
72580 };
72581 /**
72582 Set true to the last data point when all slices have the same color
72583 */
72584 DonutChart.isSingleColor = function (dataPoints) {
72585 if (dataPoints.length > 1) {
72586 var lastPoint = dataPoints.length - 1;
72587 dataPoints[lastPoint].data.isLastInDonut = dataPoints[lastPoint].data.color === dataPoints[0].data.color;
72588 }
72589 };
72590 DonutChart.drawStrokeForDonutChart = function (radius, innerArcRadiusRatio, d, sliceWidthRatio, highlightRatio) {
72591 if (highlightRatio === void 0) { highlightRatio = 1; }
72592 var sliceRadius = radius * innerArcRadiusRatio * highlightRatio;
72593 var sliceArc = (d.endAngle - d.startAngle) * sliceRadius;
72594 var sectionWithoutStroke;
72595 var sectionWithStroke;
72596 /*Donut chart*/
72597 if (sliceWidthRatio) {
72598 var innerRadius = radius * sliceWidthRatio;
72599 var outerRadius = highlightRatio * radius * (DonutChart.InnerArcRadiusRatio - sliceWidthRatio);
72600 var innerSliceArc = (d.endAngle - d.startAngle) * innerRadius;
72601 if (d.data.highlightRatio)
72602 sliceArc = (d.endAngle - d.startAngle) * (outerRadius + innerRadius);
72603 if (d.data.isLastInDonut) {
72604 //if all slices have the same color, the stroke of the last slice needs to be drawn on both radiuses
72605 return 0 + " " + sliceArc + " " + outerRadius + " " + innerSliceArc + " " + outerRadius;
72606 }
72607 sectionWithoutStroke = sliceArc + outerRadius + innerSliceArc;
72608 sectionWithStroke = outerRadius;
72609 }
72610 else {
72611 if (d.data.isLastInDonut) {
72612 //if all slices have the same color, the stroke of the last slice needs to be drawn on both radiuses
72613 sectionWithoutStroke = sliceArc;
72614 sectionWithStroke = sliceRadius * 2;
72615 }
72616 else {
72617 sectionWithoutStroke = sliceArc + sliceRadius;
72618 sectionWithStroke = sliceRadius;
72619 }
72620 }
72621 return 0 + " " + sectionWithoutStroke + " " + sectionWithStroke;
72622 };
72623 DonutChart.prototype.onClearSelection = function () {
72624 if (this.interactivityService)
72625 this.interactivityService.clearSelection();
72626 };
72627 DonutChart.getLayout = function (radius, sliceWidthRatio, viewport) {
72628 var innerRadius = radius * sliceWidthRatio;
72629 var arc = d3.svg.arc().innerRadius(innerRadius);
72630 var arcWithRadius = arc.outerRadius(radius * DonutChart.InnerArcRadiusRatio);
72631 return {
72632 shapeLayout: {
72633 d: function (d) {
72634 return arcWithRadius(d);
72635 }
72636 },
72637 highlightShapeLayout: {
72638 d: function (d) {
72639 var highlightArc = arc.outerRadius(DonutChart.getHighlightRadius(radius, sliceWidthRatio, d.data.highlightRatio));
72640 return highlightArc(d);
72641 }
72642 },
72643 zeroShapeLayout: {
72644 d: function (d) {
72645 var zeroWithZeroRadius = arc.outerRadius(innerRadius || DonutChart.EffectiveZeroValue);
72646 return zeroWithZeroRadius(d);
72647 }
72648 },
72649 };
72650 };
72651 DonutChart.getHighlightRadius = function (radius, sliceWidthRatio, highlightRatio) {
72652 var innerRadius = radius * sliceWidthRatio;
72653 return innerRadius + highlightRatio * radius * (DonutChart.InnerArcRadiusRatio - sliceWidthRatio);
72654 };
72655 DonutChart.cullDataByViewport = function (dataPoints, maxValue, viewport) {
72656 var estimatedRadius = Math.min(viewport.width, viewport.height) / 2;
72657 // Ratio of slice too small to show (invisible) = invisbleArcLength / circumference
72658 var cullRatio = this.invisibleArcLengthInPixels / (estimatedRadius * DonutChart.twoPi);
72659 var cullableValue = cullRatio * maxValue;
72660 var culledDataPoints = [];
72661 var prevPointColor;
72662 for (var _i = 0, dataPoints_6 = dataPoints; _i < dataPoints_6.length; _i++) {
72663 var datapoint = dataPoints_6[_i];
72664 if (datapoint.measure >= cullableValue) {
72665 //updates the stroke width
72666 datapoint.strokeWidth = prevPointColor === datapoint.color ? 1 : 0;
72667 prevPointColor = datapoint.color;
72668 culledDataPoints.push(datapoint);
72669 }
72670 }
72671 return culledDataPoints;
72672 };
72673 DonutChart.ClassName = 'donutChart';
72674 DonutChart.InteractiveLegendClassName = 'donutLegend';
72675 DonutChart.InteractiveLegendArrowClassName = 'donutLegendArrow';
72676 DonutChart.DrillDownAnimationDuration = 1000;
72677 DonutChart.OuterArcRadiusRatio = 0.9;
72678 DonutChart.InnerArcRadiusRatio = 0.8;
72679 DonutChart.OpaqueOpacity = 1.0;
72680 DonutChart.SemiTransparentOpacity = 0.6;
72681 DonutChart.defaultSliceWidthRatio = 0.48;
72682 DonutChart.invisibleArcLengthInPixels = 3;
72683 DonutChart.sliceClass = createClassAndSelector('slice');
72684 DonutChart.sliceHighlightClass = createClassAndSelector('slice-highlight');
72685 DonutChart.twoPi = 2 * Math.PI;
72686 DonutChart.InteractiveLegendContainerHeight = 70;
72687 DonutChart.EffectiveZeroValue = 0.000000001; // Very small multiplier so that we have a properly shaped zero arc to animate to/from.
72688 DonutChart.PolylineOpacity = 0.5;
72689 return DonutChart;
72690 }());
72691 visuals.DonutChart = DonutChart;
72692 /**
72693 * This class is an interactive legend for the Donut Chart.
72694 *
72695 * Features: It is scrollable indefinitely, using drag gesture
72696 * when you interact with it, it updates the donut chart itself.
72697 */
72698 var DonutChartInteractiveLegend = (function () {
72699 function DonutChartInteractiveLegend(donutChart, legendContainer, colors, visualInitOptions, settings) {
72700 this.legendContainerParent = legendContainer;
72701 this.colors = colors;
72702 this.donutChart = donutChart;
72703 this.visualInitOptions = visualInitOptions;
72704 this.legendItemsPositions = [];
72705 this.legendTransitionAnimationDuration = settings && settings.legendTransitionAnimationDuration ? settings.legendTransitionAnimationDuration : 0;
72706 }
72707 DonutChartInteractiveLegend.prototype.drawLegend = function (data) {
72708 var _this = this;
72709 this.data = data;
72710 this.currentNumberOfLegendItems = data.length;
72711 this.currentIndex = 0;
72712 this.leftMostIndex = 0;
72713 this.rightMostIndex = data.length - 1;
72714 if (this.legendContainerParent.select(DonutChartInteractiveLegend.LegendContainerSelector).empty()) {
72715 this.legendContainer = this.legendContainerParent.append('div').classed(DonutChartInteractiveLegend.LegendContainerClassName, true);
72716 }
72717 var legendItems = this.legendContainer.selectAll(DonutChartInteractiveLegend.LegendItemSelector).data(data);
72718 var legendContainerWidth = this.legendContainerWidth = this.legendContainer.node().getBoundingClientRect().width;
72719 var initialXOffset = legendContainerWidth / 2 - (legendContainerWidth * 0.4 / 2) + DonutChartInteractiveLegend.ItemMargin;
72720 var currX = initialXOffset;
72721 this.currentXOffset = initialXOffset;
72722 // Given the legend item div, create the item values (category, percentage and measure) on top of it.
72723 var createLegendItem = function (itemDiv, datum) {
72724 // position the legend item
72725 itemDiv
72726 .attr('data-legend-index', datum.index) // assign index for later use
72727 .css({
72728 'position': 'absolute',
72729 'left': currX,
72730 });
72731 // Add the category, percentage and value
72732 var itemCategory = visuals.valueFormatter.format(datum.label);
72733 var itemValue = visuals.valueFormatter.format(datum.measure, datum.measureFormat);
72734 var itemPercentage = visuals.valueFormatter.format(datum.percentage, '0.00 %;-0.00 %;0.00 %');
72735 var itemColor = datum.color;
72736 // Create basic spans for width calculations
72737 var itemValueSpan = DonutChartInteractiveLegend.createBasicLegendItemSpan(DonutChartInteractiveLegend.LegendItemValueClassName, itemValue, 11);
72738 var itemCategorySpan = DonutChartInteractiveLegend.createBasicLegendItemSpan(DonutChartInteractiveLegend.LegendItemCategoryClassName, itemCategory, 11);
72739 var itemPercentageSpan = DonutChartInteractiveLegend.createBasicLegendItemSpan(DonutChartInteractiveLegend.LegendItemPercentageClassName, itemPercentage, 20);
72740 // Calculate Legend Box size according to widths and set the width accordingly
72741 var valueSpanWidth = DonutChartInteractiveLegend.spanWidth(itemValueSpan);
72742 var categorySpanWidth = DonutChartInteractiveLegend.spanWidth(itemCategorySpan);
72743 var precentageSpanWidth = DonutChartInteractiveLegend.spanWidth(itemPercentageSpan);
72744 var currentLegendBoxWidth = DonutChartInteractiveLegend.legendBoxSize(valueSpanWidth, categorySpanWidth, precentageSpanWidth);
72745 itemDiv.css('width', currentLegendBoxWidth);
72746 // Calculate margins so that all the spans will be placed in the middle
72747 var getLeftValue = function (spanWidth) {
72748 return currentLegendBoxWidth - spanWidth > 0 ? (currentLegendBoxWidth - spanWidth) / 2 : 0;
72749 };
72750 var marginLeftValue = getLeftValue(valueSpanWidth);
72751 var marginLeftCategory = getLeftValue(categorySpanWidth);
72752 var marginLeftPrecentage = getLeftValue(precentageSpanWidth);
72753 // Create the actual spans with the right styling and margins so it will be center aligned and add them
72754 DonutChartInteractiveLegend.createLegendItemSpan(itemCategorySpan, marginLeftCategory);
72755 DonutChartInteractiveLegend.createLegendItemSpan(itemValueSpan, marginLeftValue);
72756 DonutChartInteractiveLegend.createLegendItemSpan(itemPercentageSpan, marginLeftPrecentage).css('color', itemColor);
72757 itemDiv.append(itemCategorySpan);
72758 itemDiv.append(itemPercentageSpan);
72759 itemDiv.append(itemValueSpan);
72760 _this.legendItemsPositions.push({
72761 startX: currX,
72762 boxWidth: currentLegendBoxWidth,
72763 });
72764 currX += currentLegendBoxWidth + DonutChartInteractiveLegend.ItemMargin;
72765 };
72766 // Create the Legend Items
72767 legendItems.enter()
72768 .insert('div')
72769 .classed(DonutChartInteractiveLegend.LegendItemClassName, true)
72770 .each(function (d) {
72771 createLegendItem($(this), d);
72772 });
72773 legendItems.exit().remove();
72774 // Assign interactions on the legend
72775 this.assignInteractions();
72776 };
72777 DonutChartInteractiveLegend.prototype.updateLegend = function (sliceIndex) {
72778 var _this = this;
72779 var legendContainerWidth = this.legendContainerWidth;
72780 this.currentIndex = sliceIndex;
72781 // "rearrange" legend items if needed, so we would have contnious endless scrolling
72782 this.updateLabelBlocks(sliceIndex);
72783 var legendTransitionAnimationDuration = this.legendTransitionAnimationDuration;
72784 // Transform the legend so that the selected slice would be in the middle
72785 var nextXOffset = (this.legendItemsPositions[sliceIndex].startX + (this.legendItemsPositions[sliceIndex].boxWidth / 2) - (legendContainerWidth / 2)) * (-1);
72786 this.legendContainer
72787 .transition()
72788 .styleTween('-webkit-transform', function (d, i, a) {
72789 return d3.interpolate(visuals.SVGUtil.translateWithPixels(_this.currentXOffset, 0), visuals.SVGUtil.translateWithPixels(nextXOffset, 0));
72790 })
72791 .styleTween('transform', function (d, i, a) {
72792 return d3.interpolate(visuals.SVGUtil.translateWithPixels(_this.currentXOffset, 0), visuals.SVGUtil.translateWithPixels(nextXOffset, 0));
72793 })
72794 .duration(legendTransitionAnimationDuration)
72795 .ease('bounce')
72796 .each('end', function () {
72797 _this.currentXOffset = nextXOffset;
72798 });
72799 visuals.SVGUtil.flushAllD3TransitionsIfNeeded(this.visualInitOptions);
72800 };
72801 DonutChartInteractiveLegend.prototype.assignInteractions = function () {
72802 var _this = this;
72803 var currentDX = 0; // keep how much drag had happened
72804 var hasChanged = false; // flag to indicate if we changed the "center" value in the legend. We only change it once per swipe.
72805 var dragStart = function () {
72806 currentDX = 0; // start of drag gesture
72807 hasChanged = false;
72808 };
72809 var dragMove = function () {
72810 currentDX += d3.event.dx;
72811 // Detect if swipe occured and if the index already changed in this drag
72812 if (hasChanged || Math.abs(currentDX) < DonutChartInteractiveLegend.MinimumSwipeDX)
72813 return;
72814 var dragDirectionLeft = (currentDX < 0);
72815 _this.dragLegend(dragDirectionLeft);
72816 hasChanged = true;
72817 };
72818 var drag = d3.behavior.drag()
72819 .origin(Object)
72820 .on('drag', dragMove)
72821 .on('dragstart', dragStart);
72822 this.legendContainer
72823 .style({
72824 'touch-action': 'none',
72825 'cursor': 'pointer'
72826 })
72827 .call(drag);
72828 };
72829 DonutChartInteractiveLegend.prototype.dragLegend = function (dragDirectionLeft) {
72830 if (this.currentNumberOfLegendItems > (DonutChartInteractiveLegend.MinimumItemsInLegendForCycled - 1)) {
72831 this.currentIndex = this.getCyclingCurrentIndex(dragDirectionLeft);
72832 }
72833 else {
72834 if (this.shouldChangeIndexInNonCycling(dragDirectionLeft)) {
72835 if (dragDirectionLeft) {
72836 this.currentIndex++;
72837 }
72838 else {
72839 this.currentIndex--;
72840 }
72841 }
72842 }
72843 this.donutChart.setInteractiveChosenSlice(this.currentIndex);
72844 };
72845 DonutChartInteractiveLegend.prototype.shouldChangeIndexInNonCycling = function (dragDirectionLeft) {
72846 if ((this.currentIndex === 0 && !dragDirectionLeft) || (this.currentIndex === (this.currentNumberOfLegendItems - 1) && dragDirectionLeft)) {
72847 return false;
72848 }
72849 return true;
72850 };
72851 DonutChartInteractiveLegend.prototype.getCyclingCurrentIndex = function (dragDirectionLeft) {
72852 var dataLen = this.data.length;
72853 var delta = dragDirectionLeft ? 1 : -1;
72854 var newIndex = (this.currentIndex + delta) % (dataLen || 1); // modolu of negative number stays negative on javascript
72855 return (newIndex < 0) ? newIndex + dataLen : newIndex;
72856 };
72857 DonutChartInteractiveLegend.prototype.updateLegendItemsBlocks = function (rightSidedShift, numberOfLegendItemsBlocksToShift) {
72858 var legendContainer$ = $(this.legendContainer[0]);
72859 if (rightSidedShift) {
72860 var smallestItem = legendContainer$.find('[data-legend-index=' + this.leftMostIndex + ']');
72861 smallestItem.remove().insertAfter(legendContainer$.find('[data-legend-index=' + this.rightMostIndex + ']'));
72862 var newX = this.legendItemsPositions[this.rightMostIndex].startX + this.legendItemsPositions[this.rightMostIndex].boxWidth + DonutChartInteractiveLegend.ItemMargin;
72863 this.legendItemsPositions[this.leftMostIndex].startX = newX;
72864 smallestItem.css('left', newX);
72865 this.rightMostIndex = this.leftMostIndex;
72866 this.leftMostIndex = (this.leftMostIndex + 1) % this.data.length;
72867 }
72868 else {
72869 var highestItem = legendContainer$.find('[data-legend-index=' + this.rightMostIndex + ']');
72870 highestItem.remove().insertBefore(legendContainer$.find('[data-legend-index=' + this.leftMostIndex + ']'));
72871 var newX = this.legendItemsPositions[this.leftMostIndex].startX - this.legendItemsPositions[this.rightMostIndex].boxWidth - DonutChartInteractiveLegend.ItemMargin;
72872 this.legendItemsPositions[this.rightMostIndex].startX = newX;
72873 highestItem.css('left', newX);
72874 this.leftMostIndex = this.rightMostIndex;
72875 this.rightMostIndex = (this.rightMostIndex - 1) === -1 ? (this.legendItemsPositions.length - 1) : (this.rightMostIndex - 1);
72876 }
72877 if ((numberOfLegendItemsBlocksToShift - 1) !== 0) {
72878 this.updateLegendItemsBlocks(rightSidedShift, (numberOfLegendItemsBlocksToShift - 1));
72879 }
72880 };
72881 /** Update the legend items, allowing for endless rotation */
72882 DonutChartInteractiveLegend.prototype.updateLabelBlocks = function (index) {
72883 if (this.currentNumberOfLegendItems > DonutChartInteractiveLegend.MinimumItemsInLegendForCycled) {
72884 // The idea of the four if's is to keep two labels before and after the current one so it will fill the screen.
72885 // If the index of the slice is the highest currently availble add 2 labels "ahead" of it
72886 if (this.rightMostIndex === index)
72887 this.updateLegendItemsBlocks(true, 2);
72888 // If the index of the slice is the lowest currently availble add 2 labels "before" it
72889 if (this.leftMostIndex === index)
72890 this.updateLegendItemsBlocks(false, 2);
72891 // If the index of the slice is the second highest currently availble add a labels "ahead" of it
72892 if (this.rightMostIndex === (index + 1) || ((this.rightMostIndex === 0) && (index === (this.currentNumberOfLegendItems - 1))))
72893 this.updateLegendItemsBlocks(true, 1);
72894 // If the index of the slice is the second lowest currently availble add a labels "before" it
72895 if (this.leftMostIndex === (index - 1) || ((this.leftMostIndex === (this.currentNumberOfLegendItems - 1) && (index === 0))))
72896 this.updateLegendItemsBlocks(false, 1);
72897 }
72898 else {
72899 if (this.currentNumberOfLegendItems === DonutChartInteractiveLegend.MinimumItemsInLegendForCycled) {
72900 // If the index of the slice is the highest currently availble add a label "ahead" of it
72901 if (this.rightMostIndex === index)
72902 this.updateLegendItemsBlocks(true, 1);
72903 // If the index of the slice is the lowest currently availble add a label "before" it
72904 if (this.leftMostIndex === index)
72905 this.updateLegendItemsBlocks(false, 1);
72906 }
72907 }
72908 };
72909 DonutChartInteractiveLegend.createBasicLegendItemSpan = function (spanClass, text, fontSize) {
72910 return $('<span/>')
72911 .addClass(spanClass)
72912 .css({
72913 'white-space': 'nowrap',
72914 'font-size': fontSize + 'px',
72915 })
72916 .text(text);
72917 };
72918 /** This method alters the given span and sets it to the final legen item span style. */
72919 DonutChartInteractiveLegend.createLegendItemSpan = function (existingSpan, marginLeft) {
72920 existingSpan
72921 .css({
72922 'overflow': 'hidden',
72923 'text-overflow': 'ellipsis',
72924 'display': 'inline-block',
72925 'width': '100%',
72926 'margin-left': marginLeft
72927 });
72928 return existingSpan;
72929 };
72930 /** Caclulte entire legend box size according to its building spans */
72931 DonutChartInteractiveLegend.legendBoxSize = function (valueSpanWidth, categorySpanWidth, precentageSpanWidth) {
72932 var boxSize = valueSpanWidth > categorySpanWidth ? valueSpanWidth : categorySpanWidth;
72933 boxSize = boxSize > precentageSpanWidth ? boxSize : precentageSpanWidth;
72934 boxSize = boxSize > DonutChartInteractiveLegend.MaxLegendItemBoxSize ? DonutChartInteractiveLegend.MaxLegendItemBoxSize : (boxSize + 2);
72935 return boxSize;
72936 };
72937 DonutChartInteractiveLegend.spanWidth = function (span) {
72938 if (!this.FakeElementSpan) {
72939 this.FakeElementSpan = $('<span>').hide().appendTo(document.body);
72940 }
72941 this.FakeElementSpan.empty();
72942 this.FakeElementSpan.append(span);
72943 return this.FakeElementSpan.width();
72944 };
72945 DonutChartInteractiveLegend.LegendContainerClassName = 'legend-container';
72946 DonutChartInteractiveLegend.LegendContainerSelector = '.legend-container';
72947 DonutChartInteractiveLegend.LegendItemClassName = 'legend-item';
72948 DonutChartInteractiveLegend.LegendItemSelector = '.legend-item';
72949 DonutChartInteractiveLegend.LegendItemCategoryClassName = 'category';
72950 DonutChartInteractiveLegend.LegendItemPercentageClassName = 'percentage';
72951 DonutChartInteractiveLegend.LegendItemValueClassName = 'value';
72952 DonutChartInteractiveLegend.MaxLegendItemBoxSize = 160;
72953 DonutChartInteractiveLegend.ItemMargin = 30; // Margin between items
72954 DonutChartInteractiveLegend.MinimumSwipeDX = 15; // Minimup swipe gesture to create a change in the legend
72955 DonutChartInteractiveLegend.MinimumItemsInLegendForCycled = 3; // Minimum items in the legend before we cycle it
72956 return DonutChartInteractiveLegend;
72957 }());
72958 var DonutChartConversion;
72959 (function (DonutChartConversion) {
72960 ;
72961 var DonutChartConverter = (function () {
72962 function DonutChartConverter(dataView, colors, defaultDataPointColor, tooltipsEnabled) {
72963 if (tooltipsEnabled === void 0) { tooltipsEnabled = true; }
72964 var reader = this.reader = powerbi.data.createIDataViewCategoricalReader(dataView);
72965 var dataViewCategorical = dataView.categorical;
72966 this.dataViewCategorical = dataViewCategorical;
72967 this.dataViewMetadata = dataView.metadata;
72968 this.tooltipsEnabled = tooltipsEnabled;
72969 this.colorHelper = new visuals.ColorHelper(colors, visuals.donutChartProps.dataPoint.fill, defaultDataPointColor);
72970 this.maxValue = 0;
72971 if (dataViewCategorical.categories && dataViewCategorical.categories.length > 0) {
72972 var category = dataViewCategorical.categories[0];
72973 this.categoryIdentities = category.identity;
72974 this.categoryValues = category.values;
72975 this.allCategoryObjects = category.objects;
72976 this.categoryColumnRef = category.identityFields;
72977 this.categoryFormatString = visuals.valueFormatter.getFormatString(category.source, visuals.donutChartProps.general.formatString);
72978 }
72979 var grouped = this.grouped = dataViewCategorical && dataViewCategorical.values ? dataViewCategorical.values.grouped() : undefined;
72980 this.isMultiMeasure = grouped && grouped.length > 0 && grouped[0].values && grouped[0].values.length > 1;
72981 this.isSingleMeasure = grouped && grouped.length === 1 && grouped[0].values && grouped[0].values.length === 1;
72982 this.isDynamicSeries = !!(dataViewCategorical.values && dataViewCategorical.values.source);
72983 this.highlightsOverflow = false;
72984 this.total = 0;
72985 this.highlightTotal = 0;
72986 this.dataPoints = [];
72987 this.legendDataPoints = [];
72988 this.dataLabelsSettings = null;
72989 if (reader.hasValues("Y")) {
72990 var seriesCount = this.seriesCount = reader.getSeriesCount("Y");
72991 this.hasHighlights = this.seriesCount > 0 && !_.isEmpty(dataViewCategorical.values) && !!dataViewCategorical.values[0].highlights;
72992 // We iterate over all categories, or if we have no categories, we just iterate over the series (category index = 0 is fine in that case)
72993 for (var categoryIndex = 0, categoryCount = reader.getCategoryCount() || 1; categoryIndex < categoryCount; categoryIndex++) {
72994 for (var seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
72995 this.total += Math.abs(reader.getValue("Y", categoryIndex, seriesIndex));
72996 this.highlightTotal += this.hasHighlights ? Math.abs(reader.getHighlight("Y", categoryIndex, seriesIndex)) : 0;
72997 }
72998 }
72999 }
73000 this.total = visuals.AxisHelper.normalizeNonFiniteNumber(this.total);
73001 this.highlightTotal = visuals.AxisHelper.normalizeNonFiniteNumber(this.highlightTotal);
73002 }
73003 DonutChartConverter.normalizedMeasureAndValue = function (measureAndValue) {
73004 var normalized = $.extend(true, {}, measureAndValue);
73005 normalized.measure = visuals.AxisHelper.normalizeNonFiniteNumber(normalized.measure);
73006 normalized.value = visuals.AxisHelper.normalizeNonFiniteNumber(normalized.value);
73007 return normalized;
73008 };
73009 DonutChartConverter.prototype.convert = function () {
73010 var reader = this.reader;
73011 var convertedData;
73012 if (this.total !== 0) {
73013 // We render based on categories, series, or measures in that order of preference
73014 if (this.categoryValues) {
73015 convertedData = this.convertCategoricalWithSlicing();
73016 }
73017 else if (this.isDynamicSeries) {
73018 // Series but no category.
73019 convertedData = this.convertSeries();
73020 }
73021 else {
73022 // No category or series; only measures.
73023 convertedData = this.convertMeasures();
73024 }
73025 }
73026 else {
73027 convertedData = [];
73028 }
73029 // Check if any of the highlight values are > non-highlight values
73030 var highlightsOverflow = false;
73031 for (var i = 0, dataPointCount = convertedData.length; i < dataPointCount && !highlightsOverflow; i++) {
73032 var point = convertedData[i];
73033 if (Math.abs(point.highlightMeasureValue.measure) > Math.abs(point.measureValue.measure)) {
73034 highlightsOverflow = true;
73035 }
73036 }
73037 // Create data labels settings
73038 this.dataLabelsSettings = this.convertDataLabelSettings();
73039 var dataViewMetadata = this.dataViewMetadata;
73040 if (dataViewMetadata) {
73041 var objects = dataViewMetadata.objects;
73042 if (objects) {
73043 this.legendObjectProperties = objects['legend'];
73044 }
73045 }
73046 var category = !_.isEmpty(this.dataViewCategorical.categories) ? this.dataViewCategorical.categories[0] : null;
73047 this.dataPoints = [];
73048 var formatStringProp = visuals.donutChartProps.general.formatString;
73049 var prevPointColor;
73050 var pctFormatString = visuals.valueFormatter.getLocalizedString('Percentage');
73051 for (var i = 0, dataPointCount = convertedData.length; i < dataPointCount; i++) {
73052 var point = convertedData[i];
73053 // Normalize the values here and then handle tooltip value as infinity
73054 var normalizedHighlight = DonutChartConverter.normalizedMeasureAndValue(point.highlightMeasureValue);
73055 var normalizedNonHighlight = DonutChartConverter.normalizedMeasureAndValue(point.measureValue);
73056 var measure = normalizedNonHighlight.measure;
73057 var percentage = (this.total > 0) ? normalizedNonHighlight.value / this.total : 0.0;
73058 var highlightRatio = void 0;
73059 var highlightPercentage = void 0;
73060 if (normalizedNonHighlight.value > this.maxValue)
73061 this.maxValue = normalizedNonHighlight.value;
73062 if (normalizedHighlight.value > this.maxValue)
73063 this.maxValue = normalizedHighlight.value;
73064 if (this.hasHighlights) {
73065 // When any highlight value is greater than the corresponding non-highlight value
73066 // we just render all of the highlight values and discard the non-highlight values.
73067 if (highlightsOverflow) {
73068 measure = normalizedHighlight.measure;
73069 percentage = (this.highlightTotal > 0) ? normalizedHighlight.value / this.highlightTotal : 0.0;
73070 highlightRatio = 1;
73071 }
73072 else {
73073 highlightRatio = normalizedNonHighlight.value !== 0 ? normalizedHighlight.value / normalizedNonHighlight.value : 0;
73074 }
73075 if (!highlightRatio) {
73076 highlightRatio = DonutChart.EffectiveZeroValue;
73077 }
73078 highlightPercentage = percentage * highlightRatio;
73079 }
73080 var categoryValue = point.categoryLabel;
73081 var categorical = this.dataViewCategorical;
73082 var valueIndex = void 0;
73083 if (point.seriesIndex != null) {
73084 valueIndex = point.seriesIndex;
73085 }
73086 else {
73087 // Static series with no categories
73088 valueIndex = i;
73089 }
73090 var valuesMetadata = reader.getValueMetadataColumn("Y", valueIndex);
73091 var value = this.hasHighlights && highlightsOverflow ? point.highlightMeasureValue.measure : point.measureValue.measure;
73092 var highlightValue = this.hasHighlights && !highlightsOverflow ? point.highlightMeasureValue.measure : undefined;
73093 var formatString = visuals.valueFormatter.getFormatString(valuesMetadata, formatStringProp);
73094 var pct = visuals.valueFormatter.format(percentage, pctFormatString);
73095 var valueAndPct = void 0;
73096 valueAndPct = visuals.valueFormatter.format(value, formatString) + ' (' + pct + ')';
73097 var highlightValueAndPct = void 0;
73098 if (this.hasHighlights && highlightValue != null && highlightPercentage != null) {
73099 var highlightedPct = visuals.valueFormatter.format(highlightPercentage, pctFormatString);
73100 highlightValueAndPct = visuals.valueFormatter.format(highlightValue, formatString) + ' (' + highlightedPct + ')';
73101 }
73102 var tooltipInfo = void 0;
73103 if (this.tooltipsEnabled) {
73104 tooltipInfo = [];
73105 if (category) {
73106 tooltipInfo.push({
73107 displayName: category.source.displayName,
73108 value: categoryValue,
73109 });
73110 }
73111 if (this.isDynamicSeries) {
73112 if (!category || category.source !== categorical.values.source) {
73113 // Category/series on the same column -- don't repeat its value in the tooltip.
73114 tooltipInfo.push({
73115 displayName: categorical.values.source.displayName,
73116 value: point.label,
73117 });
73118 }
73119 }
73120 if (valueAndPct != null) {
73121 tooltipInfo.push({
73122 displayName: valuesMetadata.displayName,
73123 value: valueAndPct,
73124 });
73125 }
73126 if (highlightValueAndPct != null) {
73127 tooltipInfo.push({
73128 displayName: visuals.ToolTipComponent.localizationOptions.highlightedValueDisplayName,
73129 value: highlightValueAndPct,
73130 });
73131 }
73132 }
73133 var strokeWidth = prevPointColor === point.color && value && value > 0 ? 1 : 0;
73134 prevPointColor = value && value > 0 ? point.color : prevPointColor;
73135 this.dataPoints.push({
73136 identity: point.identity,
73137 measure: measure,
73138 measureFormat: point.measureFormat,
73139 percentage: percentage,
73140 index: point.index,
73141 label: point.label,
73142 highlightRatio: highlightRatio,
73143 highlightValue: highlightValue,
73144 selected: false,
73145 tooltipInfo: tooltipInfo,
73146 color: point.color,
73147 strokeWidth: strokeWidth,
73148 labelFormatString: valuesMetadata.format,
73149 });
73150 }
73151 this.legendData = this.convertLegendData();
73152 };
73153 DonutChartConverter.prototype.getLegendTitle = function () {
73154 if (this.total !== 0) {
73155 // If category exists, we render title using category source. If not, we render title
73156 // using measure.
73157 var dvValuesSourceName = this.dataViewCategorical.values && this.dataViewCategorical.values.source
73158 ? this.dataViewCategorical.values.source.displayName : "";
73159 var dvCategorySourceName = this.dataViewCategorical.categories && this.dataViewCategorical.categories.length > 0 && this.dataViewCategorical.categories[0].source
73160 ? this.dataViewCategorical.categories[0].source.displayName : "";
73161 if (this.categoryValues) {
73162 return dvCategorySourceName;
73163 }
73164 else {
73165 return dvValuesSourceName;
73166 }
73167 }
73168 else {
73169 return "";
73170 }
73171 };
73172 DonutChartConverter.prototype.convertCategoricalWithSlicing = function () {
73173 var reader = this.reader;
73174 var dataViewCategorical = this.dataViewCategorical;
73175 var formatStringProp = visuals.donutChartProps.general.formatString;
73176 var dataPoints = [];
73177 for (var categoryIndex = 0, categoryCount = this.categoryValues.length; categoryIndex < categoryCount; categoryIndex++) {
73178 var categoryValue = this.categoryValues[categoryIndex];
73179 var thisCategoryObjects = this.allCategoryObjects ? this.allCategoryObjects[categoryIndex] : undefined;
73180 var legendIdentity = visuals.SelectionId.createWithId(this.categoryIdentities[categoryIndex]);
73181 var color = this.colorHelper.getColorForSeriesValue(thisCategoryObjects, this.categoryColumnRef, categoryValue);
73182 var categoryLabel = visuals.valueFormatter.format(categoryValue, this.categoryFormatString);
73183 // Series are either measures in the multi-measure case, or the single series otherwise
73184 for (var seriesIndex = 0; seriesIndex < this.seriesCount; seriesIndex++) {
73185 var valueColumn = reader.getValueColumn("Y", seriesIndex);
73186 var label = this.isSingleMeasure
73187 ? categoryLabel
73188 : visuals.converterHelper.getFormattedLegendLabel(valueColumn.source, dataViewCategorical.values, formatStringProp);
73189 var nonHighlight = reader.getValue("Y", categoryIndex, seriesIndex) || 0;
73190 var highlight = void 0;
73191 if (this.hasHighlights) {
73192 highlight = reader.getHighlight("Y", categoryIndex, seriesIndex);
73193 }
73194 var measure = valueColumn.source.queryName;
73195 var identity = visuals.SelectionIdBuilder.builder()
73196 .withCategory(dataViewCategorical.categories[0], categoryIndex)
73197 .withSeries(dataViewCategorical.values, this.isDynamicSeries ? valueColumn : undefined)
73198 .withMeasure(measure)
73199 .createSelectionId();
73200 var dataPoint = {
73201 identity: identity,
73202 measureFormat: visuals.valueFormatter.getFormatString(valueColumn.source, formatStringProp, true),
73203 measureValue: {
73204 measure: nonHighlight,
73205 value: Math.abs(nonHighlight),
73206 },
73207 highlightMeasureValue: {
73208 measure: highlight,
73209 value: highlight != null ? Math.abs(highlight) : null,
73210 },
73211 index: categoryIndex * this.seriesCount + seriesIndex,
73212 label: label,
73213 categoryLabel: categoryLabel,
73214 color: color,
73215 seriesIndex: seriesIndex
73216 };
73217 dataPoints.push(dataPoint);
73218 }
73219 this.legendDataPoints.push({
73220 label: categoryLabel,
73221 color: color,
73222 icon: visuals.LegendIcon.Box,
73223 identity: legendIdentity,
73224 selected: false
73225 });
73226 }
73227 return dataPoints;
73228 };
73229 DonutChartConverter.prototype.convertMeasures = function () {
73230 var reader = this.reader;
73231 var dataPoints = [];
73232 var formatStringProp = visuals.donutChartProps.general.formatString;
73233 for (var measureIndex = 0; measureIndex < this.seriesCount; measureIndex++) {
73234 var valueColumn = reader.getValueColumn("Y", measureIndex);
73235 var measureFormat = visuals.valueFormatter.getFormatString(valueColumn.source, formatStringProp, true);
73236 var measureLabel = valueColumn.source.displayName;
73237 var identity = visuals.SelectionId.createWithMeasure(valueColumn.source.queryName);
73238 var nonHighlight = reader.getValue("Y", 0, measureIndex) || 0;
73239 var highlight = this.hasHighlights ? reader.getHighlight("Y", 0, measureIndex) : 0;
73240 var color = this.colorHelper.getColorForMeasure(valueColumn.source.objects, valueColumn.source.queryName);
73241 var dataPoint = {
73242 identity: identity,
73243 measureFormat: measureFormat,
73244 measureValue: {
73245 measure: nonHighlight,
73246 value: Math.abs(nonHighlight),
73247 },
73248 highlightMeasureValue: {
73249 measure: highlight,
73250 value: Math.abs(highlight),
73251 },
73252 index: measureIndex,
73253 label: measureLabel,
73254 categoryLabel: measureLabel,
73255 color: color
73256 };
73257 dataPoints.push(dataPoint);
73258 this.legendDataPoints.push({
73259 label: dataPoint.label,
73260 color: dataPoint.color,
73261 icon: visuals.LegendIcon.Box,
73262 identity: dataPoint.identity,
73263 selected: false
73264 });
73265 }
73266 return dataPoints;
73267 };
73268 DonutChartConverter.prototype.convertSeries = function () {
73269 var reader = this.reader;
73270 var dataViewCategorical = this.dataViewCategorical;
73271 var dataPoints = [];
73272 var formatStringProp = visuals.donutChartProps.general.formatString;
73273 for (var seriesIndex = 0; seriesIndex < this.seriesCount; seriesIndex++) {
73274 var valueColumn = reader.getValueColumn("Y", seriesIndex);
73275 var seriesFormat = visuals.valueFormatter.getFormatString(valueColumn.source, formatStringProp, true);
73276 var label = visuals.converterHelper.getFormattedLegendLabel(valueColumn.source, dataViewCategorical.values, formatStringProp);
73277 var identity = new visuals.SelectionIdBuilder()
73278 .withSeries(dataViewCategorical.values, valueColumn)
73279 .withMeasure(valueColumn.source.queryName)
73280 .createSelectionId();
73281 var seriesName = visuals.converterHelper.getSeriesName(valueColumn.source);
73282 var objects = this.grouped && this.grouped[seriesIndex] && this.grouped[seriesIndex].objects;
73283 var nonHighlight = reader.getValue("Y", 0, seriesIndex) || 0;
73284 var highlight = this.hasHighlights ? reader.getHighlight("Y", 0, seriesIndex) || 0 : 0;
73285 var color = this.colorHelper.getColorForSeriesValue(objects, dataViewCategorical.values.identityFields, seriesName);
73286 var dataPoint = {
73287 identity: identity,
73288 measureFormat: seriesFormat,
73289 measureValue: {
73290 measure: nonHighlight,
73291 value: Math.abs(nonHighlight),
73292 },
73293 highlightMeasureValue: {
73294 measure: highlight,
73295 value: Math.abs(highlight),
73296 },
73297 index: seriesIndex,
73298 label: label,
73299 categoryLabel: label,
73300 color: color,
73301 seriesIndex: seriesIndex
73302 };
73303 dataPoints.push(dataPoint);
73304 this.legendDataPoints.push({
73305 label: dataPoint.label,
73306 color: dataPoint.color,
73307 icon: visuals.LegendIcon.Box,
73308 identity: dataPoint.identity,
73309 selected: false
73310 });
73311 }
73312 return dataPoints;
73313 };
73314 DonutChartConverter.prototype.convertDataLabelSettings = function () {
73315 var dataViewMetadata = this.dataViewMetadata;
73316 var dataLabelsSettings = visuals.dataLabelUtils.getDefaultDonutLabelSettings();
73317 if (dataViewMetadata) {
73318 var objects = dataViewMetadata.objects;
73319 if (objects) {
73320 // Handle lables settings
73321 var labelsObj = objects['labels'];
73322 if (labelsObj) {
73323 visuals.dataLabelUtils.updateLabelSettingsFromLabelsObject(labelsObj, dataLabelsSettings);
73324 }
73325 }
73326 }
73327 return dataLabelsSettings;
73328 };
73329 DonutChartConverter.prototype.convertLegendData = function () {
73330 return {
73331 dataPoints: this.legendDataPoints,
73332 labelColor: visuals.LegendData.DefaultLegendLabelFillColor,
73333 title: this.getLegendTitle(),
73334 fontSize: visuals.SVGLegend.DefaultFontSizeInPt,
73335 };
73336 };
73337 return DonutChartConverter;
73338 }());
73339 DonutChartConversion.DonutChartConverter = DonutChartConverter;
73340 })(DonutChartConversion || (DonutChartConversion = {}));
73341 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
73342})(powerbi || (powerbi = {}));
73343/*
73344 * Power BI Visualizations
73345 *
73346 * Copyright (c) Microsoft Corporation
73347 * All rights reserved.
73348 * MIT License
73349 *
73350 * Permission is hereby granted, free of charge, to any person obtaining a copy
73351 * of this software and associated documentation files (the ""Software""), to deal
73352 * in the Software without restriction, including without limitation the rights
73353 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73354 * copies of the Software, and to permit persons to whom the Software is
73355 * furnished to do so, subject to the following conditions:
73356 *
73357 * The above copyright notice and this permission notice shall be included in
73358 * all copies or substantial portions of the Software.
73359 *
73360 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73361 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73362 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73363 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73364 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73365 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73366 * THE SOFTWARE.
73367 */
73368var powerbi;
73369(function (powerbi) {
73370 var visuals;
73371 (function (visuals) {
73372 var Utility = jsCommon.Utility;
73373 var ScriptVisual = (function () {
73374 function ScriptVisual(options) {
73375 this.canRefresh = options.canRefresh;
73376 }
73377 ScriptVisual.prototype.init = function (options) {
73378 this.element = options.element;
73379 this.hostServices = options.host;
73380 if (!this.canRefresh) {
73381 this.hostServices.setWarnings([new visuals.ScriptVisualRefreshWarning()]);
73382 }
73383 };
73384 ScriptVisual.prototype.update = function (options) {
73385 debug.assertValue(options, 'options');
73386 var dataViews = options.dataViews;
73387 if (!dataViews || dataViews.length === 0)
73388 return;
73389 var dataView = dataViews[0];
73390 if (!dataView || !dataView.metadata)
73391 return;
73392 var imageUrl = this.getImageUrl(dataView);
73393 var div = this.ensureHtmlElement();
73394 if (imageUrl && Utility.isValidImageDataUrl(imageUrl)) {
73395 var viewport = options.viewport;
73396 div.css({ height: viewport.height, width: viewport.width, backgroundImage: 'url(' + imageUrl + ')' });
73397 }
73398 else {
73399 div.css({ backgroundImage: 'none' });
73400 }
73401 };
73402 ScriptVisual.prototype.onResizing = function (finalViewport) {
73403 var div = this.ensureHtmlElement();
73404 div.css({ height: finalViewport.height, width: finalViewport.width });
73405 };
73406 ScriptVisual.prototype.getImageUrl = function (dataView) {
73407 debug.assertValue(dataView, 'dataView');
73408 if (dataView.scriptResult && dataView.scriptResult.imageBase64) {
73409 return "data:image/png;base64," + dataView.scriptResult.imageBase64;
73410 }
73411 return null;
73412 };
73413 ScriptVisual.prototype.ensureHtmlElement = function () {
73414 var div = this.imageBackgroundElement;
73415 if (!div) {
73416 div = $("<div class='imageBackground' />");
73417 this.imageBackgroundElement = div;
73418 this.imageBackgroundElement.appendTo(this.element);
73419 }
73420 return div;
73421 };
73422 return ScriptVisual;
73423 }());
73424 visuals.ScriptVisual = ScriptVisual;
73425 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
73426})(powerbi || (powerbi = {}));
73427/*
73428 * Power BI Visualizations
73429 *
73430 * Copyright (c) Microsoft Corporation
73431 * All rights reserved.
73432 * MIT License
73433 *
73434 * Permission is hereby granted, free of charge, to any person obtaining a copy
73435 * of this software and associated documentation files (the ""Software""), to deal
73436 * in the Software without restriction, including without limitation the rights
73437 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73438 * copies of the Software, and to permit persons to whom the Software is
73439 * furnished to do so, subject to the following conditions:
73440 *
73441 * The above copyright notice and this permission notice shall be included in
73442 * all copies or substantial portions of the Software.
73443 *
73444 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73445 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73446 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73447 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73448 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73449 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73450 * THE SOFTWARE.
73451 */
73452var powerbi;
73453(function (powerbi) {
73454 var visuals;
73455 (function (visuals) {
73456 var plugins;
73457 (function (plugins) {
73458 // This file registers the built-in visualizations
73459 plugins.animatedNumber = {
73460 name: 'animatedNumber',
73461 capabilities: visuals.capabilities.animatedNumber,
73462 create: function () { return new visuals.AnimatedNumber(); }
73463 };
73464 plugins.areaChart = {
73465 name: 'areaChart',
73466 watermarkKey: 'area',
73467 capabilities: visuals.capabilities.lineChart,
73468 create: function () { return new visuals.CartesianChart({ chartType: 1 /* Area */ }); },
73469 customizeQuery: visuals.LineChart.customizeQuery,
73470 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73471 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73472 };
73473 plugins.barChart = {
73474 name: 'barChart',
73475 watermarkKey: 'bar',
73476 capabilities: visuals.capabilities.barChart,
73477 create: function () { return new visuals.CartesianChart({ chartType: 6 /* StackedBar */ }); },
73478 customizeQuery: visuals.ColumnChart.customizeQuery,
73479 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73480 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73481 };
73482 plugins.basicShape = {
73483 name: 'basicShape',
73484 capabilities: visuals.basicShapeCapabilities,
73485 create: function () { return new visuals.BasicShapeVisual(); }
73486 };
73487 plugins.card = {
73488 name: 'card',
73489 watermarkKey: 'card',
73490 capabilities: visuals.capabilities.card,
73491 create: function () { return new visuals.Card(); }
73492 };
73493 plugins.multiRowCard = {
73494 name: 'multiRowCard',
73495 watermarkKey: 'multiRowCard',
73496 capabilities: visuals.capabilities.multiRowCard,
73497 create: function () { return new visuals.MultiRowCard(); },
73498 getSortableRoles: function (visualSortableOptions) { return visuals.MultiRowCard.getSortableRoles(visualSortableOptions); },
73499 };
73500 plugins.clusteredBarChart = {
73501 name: 'clusteredBarChart',
73502 watermarkKey: 'clusteredBar',
73503 capabilities: visuals.capabilities.clusteredBarChart,
73504 create: function () { return new visuals.CartesianChart({ chartType: 5 /* ClusteredBar */ }); },
73505 customizeQuery: visuals.ColumnChart.customizeQuery,
73506 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73507 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73508 };
73509 plugins.clusteredColumnChart = {
73510 name: 'clusteredColumnChart',
73511 watermarkKey: 'clusteredColumn',
73512 capabilities: visuals.capabilities.clusteredColumnChart,
73513 create: function () { return new visuals.CartesianChart({ chartType: 3 /* ClusteredColumn */ }); },
73514 customizeQuery: visuals.ColumnChart.customizeQuery,
73515 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73516 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73517 };
73518 plugins.columnChart = {
73519 name: 'columnChart',
73520 watermarkKey: 'column',
73521 capabilities: visuals.capabilities.columnChart,
73522 create: function () { return new visuals.CartesianChart({ chartType: 4 /* StackedColumn */ }); },
73523 customizeQuery: visuals.ColumnChart.customizeQuery,
73524 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73525 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73526 };
73527 plugins.comboChart = {
73528 name: 'comboChart',
73529 watermarkKey: 'combo',
73530 capabilities: visuals.capabilities.comboChart,
73531 customizeQuery: visuals.ComboChart.customizeQuery,
73532 create: function () { return new visuals.CartesianChart({ chartType: 10 /* ComboChart */ }); },
73533 getSortableRoles: function (visualSortableOptions) { return visuals.ComboChart.getSortableRoles(visualSortableOptions); },
73534 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73535 };
73536 plugins.dataDotChart = {
73537 name: 'dataDotChart',
73538 capabilities: visuals.capabilities.dataDotChart,
73539 create: function () { return new visuals.CartesianChart({ chartType: 11 /* DataDot */ }); },
73540 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73541 };
73542 plugins.dataDotClusteredColumnComboChart = {
73543 name: 'dataDotClusteredColumnComboChart',
73544 watermarkKey: 'combo',
73545 capabilities: visuals.capabilities.dataDotClusteredColumnComboChart,
73546 customizeQuery: visuals.ComboChart.customizeQuery,
73547 create: function () { return new visuals.CartesianChart({ chartType: 15 /* DataDotClusteredColumnCombo */ }); },
73548 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73549 };
73550 plugins.dataDotStackedColumnComboChart = {
73551 name: 'dataDotStackedColumnComboChart',
73552 watermarkKey: 'combo',
73553 capabilities: visuals.capabilities.dataDotStackedColumnComboChart,
73554 customizeQuery: visuals.ComboChart.customizeQuery,
73555 create: function () { return new visuals.CartesianChart({ chartType: 16 /* DataDotStackedColumnCombo */ }); },
73556 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73557 };
73558 plugins.donutChart = {
73559 name: 'donutChart',
73560 watermarkKey: 'donut',
73561 capabilities: visuals.capabilities.donutChart,
73562 create: function () { return new visuals.DonutChart(); }
73563 };
73564 plugins.funnel = {
73565 name: 'funnel',
73566 watermarkKey: 'funnel',
73567 capabilities: visuals.capabilities.funnel,
73568 create: function () { return new visuals.FunnelChart(); }
73569 };
73570 plugins.gauge = {
73571 name: 'gauge',
73572 watermarkKey: 'gauge',
73573 capabilities: visuals.capabilities.gauge,
73574 create: function () { return new visuals.Gauge(); }
73575 };
73576 plugins.hundredPercentStackedBarChart = {
73577 name: 'hundredPercentStackedBarChart',
73578 watermarkKey: '100stackedbar',
73579 capabilities: visuals.capabilities.hundredPercentStackedBarChart,
73580 create: function () { return new visuals.CartesianChart({ chartType: 7 /* HundredPercentStackedBar */ }); },
73581 customizeQuery: visuals.ColumnChart.customizeQuery,
73582 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73583 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73584 };
73585 plugins.hundredPercentStackedColumnChart = {
73586 name: 'hundredPercentStackedColumnChart',
73587 watermarkKey: '100stackedcolumn',
73588 capabilities: visuals.capabilities.hundredPercentStackedColumnChart,
73589 create: function () { return new visuals.CartesianChart({ chartType: 8 /* HundredPercentStackedColumn */ }); },
73590 customizeQuery: visuals.ColumnChart.customizeQuery,
73591 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73592 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73593 };
73594 plugins.image = {
73595 name: 'image',
73596 capabilities: visuals.capabilities.image,
73597 create: function () { return new visuals.ImageVisual(); }
73598 };
73599 plugins.lineChart = {
73600 name: 'lineChart',
73601 watermarkKey: 'line',
73602 capabilities: visuals.capabilities.lineChart,
73603 create: function () { return new visuals.CartesianChart({ chartType: 0 /* Line */ }); },
73604 customizeQuery: visuals.LineChart.customizeQuery,
73605 getSortableRoles: function (visualSortableOptions) { return visuals.LineChart.getSortableRoles(visualSortableOptions); },
73606 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73607 };
73608 plugins.lineStackedColumnComboChart = {
73609 name: 'lineStackedColumnComboChart',
73610 watermarkKey: 'combo',
73611 capabilities: visuals.capabilities.lineStackedColumnComboChart,
73612 customizeQuery: visuals.ComboChart.customizeQuery,
73613 create: function () { return new visuals.CartesianChart({ chartType: 14 /* LineStackedColumnCombo */ }); },
73614 getSortableRoles: function (visualSortableOptions) { return visuals.ComboChart.getSortableRoles(visualSortableOptions); },
73615 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73616 };
73617 plugins.lineClusteredColumnComboChart = {
73618 name: 'lineClusteredColumnComboChart',
73619 watermarkKey: 'combo',
73620 capabilities: visuals.capabilities.lineClusteredColumnComboChart,
73621 customizeQuery: visuals.ComboChart.customizeQuery,
73622 create: function () { return new visuals.CartesianChart({ chartType: 13 /* LineClusteredColumnCombo */ }); },
73623 getSortableRoles: function (visualSortableOptions) { return visuals.ComboChart.getSortableRoles(visualSortableOptions); },
73624 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73625 };
73626 plugins.map = {
73627 name: 'map',
73628 watermarkKey: 'map',
73629 capabilities: visuals.capabilities.map,
73630 create: function () { return new visuals.Map({ filledMap: false }); }
73631 };
73632 plugins.filledMap = {
73633 name: 'filledMap',
73634 watermarkKey: 'filledMap',
73635 capabilities: visuals.capabilities.filledMap,
73636 create: function () { return new visuals.Map({ filledMap: true }); }
73637 };
73638 plugins.treemap = {
73639 name: 'treemap',
73640 watermarkKey: 'tree',
73641 capabilities: visuals.capabilities.treemap,
73642 create: function () { return new visuals.Treemap(); }
73643 };
73644 plugins.pieChart = {
73645 name: 'pieChart',
73646 watermarkKey: 'pie',
73647 capabilities: visuals.capabilities.donutChart,
73648 create: function () { return new visuals.DonutChart({ sliceWidthRatio: 0 }); }
73649 };
73650 plugins.scatterChart = {
73651 name: 'scatterChart',
73652 watermarkKey: 'scatterplot',
73653 capabilities: visuals.capabilities.scatterChart,
73654 create: function () { return new visuals.CartesianChart({ chartType: 9 /* Scatter */ }); },
73655 getAdditionalTelemetry: function (dataView) { return visuals.ScatterChart.getAdditionalTelemetry(dataView); },
73656 };
73657 plugins.stackedAreaChart = {
73658 name: 'stackedAreaChart',
73659 watermarkKey: 'stackedarea',
73660 capabilities: visuals.capabilities.lineChart,
73661 create: function () { return new visuals.CartesianChart({ chartType: 2 /* StackedArea */ }); },
73662 customizeQuery: visuals.LineChart.customizeQuery,
73663 getSortableRoles: function (visualSortableOptions) { return visuals.ColumnChart.getSortableRoles(visualSortableOptions); },
73664 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73665 };
73666 plugins.table = {
73667 name: 'table',
73668 watermarkKey: 'table',
73669 capabilities: visuals.capabilities.table,
73670 create: function () { return new visuals.Table(); },
73671 customizeQuery: visuals.Table.customizeQuery,
73672 getSortableRoles: function (visualSortableOptions) { return visuals.Table.getSortableRoles(); },
73673 };
73674 plugins.matrix = {
73675 name: 'matrix',
73676 watermarkKey: 'matrix',
73677 capabilities: visuals.capabilities.matrix,
73678 create: function () { return new visuals.Matrix(); },
73679 customizeQuery: visuals.Matrix.customizeQuery,
73680 getSortableRoles: function (visualSortableOptions) { return visuals.Matrix.getSortableRoles(); },
73681 };
73682 plugins.slicer = {
73683 name: 'slicer',
73684 watermarkKey: 'slicer',
73685 capabilities: visuals.capabilities.slicer,
73686 create: function () { return new visuals.Slicer(); }
73687 };
73688 plugins.textbox = {
73689 name: 'textbox',
73690 capabilities: visuals.capabilities.textbox,
73691 create: function () { return new visuals.Textbox(); }
73692 };
73693 plugins.waterfallChart = {
73694 name: 'waterfallChart',
73695 watermarkKey: 'waterfall',
73696 capabilities: visuals.capabilities.waterfallChart,
73697 create: function () { return new visuals.CartesianChart({ chartType: 12 /* Waterfall */ }); },
73698 getAdditionalTelemetry: function (dataView) { return visuals.CartesianChart.getAdditionalTelemetry(dataView); },
73699 };
73700 plugins.cheerMeter = {
73701 name: 'cheerMeter',
73702 capabilities: visuals.CheerMeter.capabilities,
73703 create: function () { return new visuals.CheerMeter(); }
73704 };
73705 plugins.consoleWriter = {
73706 name: 'consoleWriter',
73707 capabilities: visuals.samples.consoleWriterCapabilities,
73708 create: function () { return new visuals.samples.ConsoleWriter(); }
73709 };
73710 plugins.helloIVisual = {
73711 name: 'helloIVisual',
73712 capabilities: visuals.samples.HelloIVisual.capabilities,
73713 create: function () { return new visuals.samples.HelloIVisual(); }
73714 };
73715 plugins.owlGauge = {
73716 name: 'owlGauge',
73717 watermarkKey: 'gauge',
73718 capabilities: visuals.OwlGauge.capabilities,
73719 create: function () { return new visuals.OwlGauge(); }
73720 };
73721 plugins.scriptVisual = {
73722 name: 'scriptVisual',
73723 watermarkKey: 'scriptvisual',
73724 capabilities: visuals.capabilities.scriptVisual,
73725 create: function () { return new visuals.ScriptVisual({ canRefresh: false }); }
73726 };
73727 plugins.kpi = {
73728 name: 'kpi',
73729 watermarkKey: 'kpi',
73730 capabilities: visuals.capabilities.kpi,
73731 create: function () { return new visuals.KPIStatusWithHistory(); }
73732 };
73733 })(plugins = visuals.plugins || (visuals.plugins = {}));
73734 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
73735})(powerbi || (powerbi = {}));
73736/*
73737 * Power BI Visualizations
73738 *
73739 * Copyright (c) Microsoft Corporation
73740 * All rights reserved.
73741 * MIT License
73742 *
73743 * Permission is hereby granted, free of charge, to any person obtaining a copy
73744 * of this software and associated documentation files (the ""Software""), to deal
73745 * in the Software without restriction, including without limitation the rights
73746 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73747 * copies of the Software, and to permit persons to whom the Software is
73748 * furnished to do so, subject to the following conditions:
73749 *
73750 * The above copyright notice and this permission notice shall be included in
73751 * all copies or substantial portions of the Software.
73752 *
73753 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73754 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73755 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73756 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73757 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73758 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73759 * THE SOFTWARE.
73760 */
73761var powerbi;
73762(function (powerbi) {
73763 var visuals;
73764 (function (visuals) {
73765 var CanvasBackgroundHelper;
73766 (function (CanvasBackgroundHelper) {
73767 function getDefaultColor() {
73768 return '#FFFFFF';
73769 }
73770 CanvasBackgroundHelper.getDefaultColor = getDefaultColor;
73771 function getDefaultValues() {
73772 return {
73773 color: getDefaultColor(),
73774 };
73775 }
73776 CanvasBackgroundHelper.getDefaultValues = getDefaultValues;
73777 })(CanvasBackgroundHelper = visuals.CanvasBackgroundHelper || (visuals.CanvasBackgroundHelper = {}));
73778 })(visuals = powerbi.visuals || (powerbi.visuals = {}));
73779})(powerbi || (powerbi = {}));
73780
73781
73782
73783//# sourceMappingURL=powerbi-visuals.js.map