|
| 1 | +import { MarkType } from '@tableau/extensions-api-types'; |
| 2 | + |
| 3 | +// Wrap everything in an anonymous function to avoid polluting the global namespace |
| 4 | +(async () => { |
| 5 | + class VizImage { |
| 6 | + // Avoid globals. |
| 7 | + constructor(private _$: JQueryStatic) { } |
| 8 | + |
| 9 | + /** |
| 10 | + * Initializes the extension |
| 11 | + */ |
| 12 | + public async initialize() { |
| 13 | + console.log('Waiting for DOM ready'); |
| 14 | + await this._$.ready; |
| 15 | + console.log('Initializing extension API'); |
| 16 | + await tableau.extensions.initializeAsync(); |
| 17 | + |
| 18 | + await this.addVizImage(tableau.MarkType.Bar, 'tableau20_10_0'); |
| 19 | + |
| 20 | + const markSelector = this._$('#mark-select'); |
| 21 | + const colorSelector = this._$('#color-select'); |
| 22 | + |
| 23 | + markSelector.prop('disabled', false); |
| 24 | + colorSelector.prop('disabled', false); |
| 25 | + |
| 26 | + // updating viz images with new values upon a selector change |
| 27 | + markSelector.change(() => { |
| 28 | + this.addVizImage(markSelector.val() as MarkType, colorSelector.val() as string); |
| 29 | + }); |
| 30 | + colorSelector.change(() => { |
| 31 | + this.addVizImage(markSelector.val() as MarkType, colorSelector.val() as string); |
| 32 | + }); |
| 33 | + } |
| 34 | + |
| 35 | + /** |
| 36 | + * Builds the input specifications and displays the created viz image |
| 37 | + * @param markType |
| 38 | + * @param colorPalette |
| 39 | + */ |
| 40 | + private async addVizImage(markType: MarkType, palette: string) { |
| 41 | + // Building the input specification object that is used to create the viz image |
| 42 | + // Data values used in the viz image are prefilled |
| 43 | + const vizInputSpec = { |
| 44 | + data: { |
| 45 | + values: [ |
| 46 | + {Product: 'Paper', Sales: 28, Region: 'Central'}, |
| 47 | + {Product: 'Pens', Sales: 45, Region: 'East'}, |
| 48 | + {Product: 'Rulers', Sales: 35, Region: 'East'}, |
| 49 | + {Product: 'Rulers', Sales: 43, Region: 'South'}, |
| 50 | + {Product: 'Paper', Sales: 50, Region: 'West'}, |
| 51 | + {Product: 'Pens', Sales: 56, Region: 'West'} |
| 52 | + ] |
| 53 | + }, |
| 54 | + description: 'A sample viz', // optional parameter |
| 55 | + encoding: { |
| 56 | + color: {field: 'Product', type: tableau.VizImageEncodingType.Discrete, palette}, |
| 57 | + columns: {field: 'Region', type: tableau.VizImageEncodingType.Discrete}, |
| 58 | + rows: {field: 'Sales', type: tableau.VizImageEncodingType.Continuous} |
| 59 | + }, |
| 60 | + mark: markType, |
| 61 | + markcolor: '#FFED5F', // may not get used in viz if color is encoded in viz |
| 62 | + size: {width: 400, height: 300} |
| 63 | + }; |
| 64 | + |
| 65 | + // defaulting values if null |
| 66 | + if (markType === null) { |
| 67 | + vizInputSpec.mark = tableau.MarkType.Bar; |
| 68 | + } |
| 69 | + if (palette === null) { |
| 70 | + vizInputSpec.encoding.color.palette = 'tableau20_10_0'; |
| 71 | + } |
| 72 | + |
| 73 | + const svg = await tableau.extensions.createVizImageAsync(vizInputSpec); |
| 74 | + // making call to create viz image from the input specifications |
| 75 | + const blob = new Blob([svg], { type: 'image/svg+xml' }); |
| 76 | + const url = URL.createObjectURL(blob); |
| 77 | + const image = document.createElement('img'); |
| 78 | + image.src = url; |
| 79 | + image.style.maxWidth = '100%'; |
| 80 | + image.style.maxHeight = '100%'; |
| 81 | + image.className = 'center-block'; |
| 82 | + const vizApiElement = document.getElementById('viz-container'); |
| 83 | + // clearing UI and adding in new viz |
| 84 | + vizApiElement.innerHTML = ''; |
| 85 | + vizApiElement.appendChild(image); |
| 86 | + image.addEventListener('load', () => URL.revokeObjectURL(url), { once: true }); |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + console.log('Initializing VizImage extension.'); |
| 91 | + await new VizImage($).initialize(); |
| 92 | +})(); |
0 commit comments