diff --git a/Samples-Typescript/VizImage/VizImage.trex b/Samples-Typescript/VizImage/VizImage.trex
new file mode 100644
index 00000000..fdddc5f3
--- /dev/null
+++ b/Samples-Typescript/VizImage/VizImage.trex
@@ -0,0 +1,19 @@
+
+
+
+ en_US
+
+ Viz Image Sample
+
+ 1.6
+
+ http://localhost:8765/Samples-Typescript/VizImage/vizImage.html
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAlhJREFUOI2Nkt9vy1EYh5/3bbsvRSySCZbIxI+ZCKsN2TKtSFyIrV2WuRCJuBiJWxfuxCVXbvwFgiEtposgLFJElnbU1SxIZIIRJDKTrdu+53Uhra4mce7Oe57Pcz7JOULFisViwZ+29LAzOSjQYDgz1ZcCvWuXV11MJpN+OS/lm6179teqH0yDqxPTCyKSA8DcDsyOmOprnCaeP7459pdgy969i0LTC3IO/RQMyoHcQN+3cnljW3dNIFC47qDaK3g7BwdTkwBaBELT4ZPOUVWgKl4ZBnjxJPUlMDnTDrp0pmr6RHFeEjjcUUXPDGeSEwDN0Xg8sivxMhJNjGzbHd8PkM3eHRfkrBM5NkcQaY2vUnTlrDIA0NoaX+KLXFFlowr14tvVpqb2MICzmQcKqxvbumv+NAhZGCCIPwEw6QWXKYRL/VUXO0+rAUJiPwAk5MIlgVfwPjjHLCL1APmHN94ZdqeYN+NW/mn6I4BvwQYchcLnwFhJMDiYmlRxAzjpKWZkYkUCcZ2I61wi37tLbYyjiN0fHk5Oz3nGSLSzBbNHCF35R7f6K1/hN9PRhek11FrymfQQQKB4+Gl05P2qNRtmETlXW7e+b2z01dfycGNbfFMAbqNyKp9Jp4rzOT8RYFs0njJkc2iqsCObvTsOsDWWqA5C1uFy+Uz/oXJeKwVT4h0RmPUXhi79vuC0Ku6yOffTK3g9lfxfDQAisY516sg5kfOCiJk7HoLt2cf9b/9LANAc7dznm98PagG1fUOZ9IP5uMB8Q4CPoyNvausapkTt3rNMuvdf3C/o6+czhtdwmwAAAABJRU5ErkJggg==
+
+
+
+ Viz Image Sample
+
+
+
diff --git a/Samples-Typescript/VizImage/vizImage.html b/Samples-Typescript/VizImage/vizImage.html
new file mode 100644
index 00000000..77062d2e
--- /dev/null
+++ b/Samples-Typescript/VizImage/vizImage.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ Viz Image Sample
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Viz Image Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples-Typescript/VizImage/vizImage.ts b/Samples-Typescript/VizImage/vizImage.ts
new file mode 100644
index 00000000..ab0484c1
--- /dev/null
+++ b/Samples-Typescript/VizImage/vizImage.ts
@@ -0,0 +1,92 @@
+import { MarkType } from '@tableau/extensions-api-types';
+
+// Wrap everything in an anonymous function to avoid polluting the global namespace
+(async () => {
+ class VizImage {
+ // Avoid globals.
+ constructor(private _$: JQueryStatic) { }
+
+ /**
+ * Initializes the extension
+ */
+ public async initialize() {
+ console.log('Waiting for DOM ready');
+ await this._$.ready;
+ console.log('Initializing extension API');
+ await tableau.extensions.initializeAsync();
+
+ await this.addVizImage(tableau.MarkType.Bar, 'tableau20_10_0');
+
+ const markSelector = this._$('#mark-select');
+ const colorSelector = this._$('#color-select');
+
+ markSelector.prop('disabled', false);
+ colorSelector.prop('disabled', false);
+
+ // updating viz images with new values upon a selector change
+ markSelector.change(() => {
+ this.addVizImage(markSelector.val() as MarkType, colorSelector.val() as string);
+ });
+ colorSelector.change(() => {
+ this.addVizImage(markSelector.val() as MarkType, colorSelector.val() as string);
+ });
+ }
+
+ /**
+ * Builds the input specifications and displays the created viz image
+ * @param markType
+ * @param colorPalette
+ */
+ private async addVizImage(markType: MarkType, palette: string) {
+ // Building the input specification object that is used to create the viz image
+ // Data values used in the viz image are prefilled
+ const vizInputSpec = {
+ data: {
+ values: [
+ {Product: 'Paper', Sales: 28, Region: 'Central'},
+ {Product: 'Pens', Sales: 45, Region: 'East'},
+ {Product: 'Rulers', Sales: 35, Region: 'East'},
+ {Product: 'Rulers', Sales: 43, Region: 'South'},
+ {Product: 'Paper', Sales: 50, Region: 'West'},
+ {Product: 'Pens', Sales: 56, Region: 'West'}
+ ]
+ },
+ description: 'A sample viz', // optional parameter
+ encoding: {
+ color: {field: 'Product', type: tableau.VizImageEncodingType.Discrete, palette},
+ columns: {field: 'Region', type: tableau.VizImageEncodingType.Discrete},
+ rows: {field: 'Sales', type: tableau.VizImageEncodingType.Continuous}
+ },
+ mark: markType,
+ markcolor: '#FFED5F', // may not get used in viz if color is encoded in viz
+ size: {width: 400, height: 300}
+ };
+
+ // defaulting values if null
+ if (markType === null) {
+ vizInputSpec.mark = tableau.MarkType.Bar;
+ }
+ if (palette === null) {
+ vizInputSpec.encoding.color.palette = 'tableau20_10_0';
+ }
+
+ const svg = await tableau.extensions.createVizImageAsync(vizInputSpec);
+ // making call to create viz image from the input specifications
+ const blob = new Blob([svg], { type: 'image/svg+xml' });
+ const url = URL.createObjectURL(blob);
+ const image = document.createElement('img');
+ image.src = url;
+ image.style.maxWidth = '100%';
+ image.style.maxHeight = '100%';
+ image.className = 'center-block';
+ const vizApiElement = document.getElementById('viz-container');
+ // clearing UI and adding in new viz
+ vizApiElement.innerHTML = '';
+ vizApiElement.appendChild(image);
+ image.addEventListener('load', () => URL.revokeObjectURL(url), { once: true });
+ }
+ }
+
+ console.log('Initializing VizImage extension.');
+ await new VizImage($).initialize();
+})();
diff --git a/Samples/VizImage/VizImage.trex b/Samples/VizImage/VizImage.trex
new file mode 100644
index 00000000..684f9612
--- /dev/null
+++ b/Samples/VizImage/VizImage.trex
@@ -0,0 +1,19 @@
+
+
+
+ en_US
+
+ Viz Image Sample
+
+ 1.6
+
+ http://localhost:8765/Samples/VizImage/vizImage.html
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAlhJREFUOI2Nkt9vy1EYh5/3bbsvRSySCZbIxI+ZCKsN2TKtSFyIrV2WuRCJuBiJWxfuxCVXbvwFgiEtposgLFJElnbU1SxIZIIRJDKTrdu+53Uhra4mce7Oe57Pcz7JOULFisViwZ+29LAzOSjQYDgz1ZcCvWuXV11MJpN+OS/lm6179teqH0yDqxPTCyKSA8DcDsyOmOprnCaeP7459pdgy969i0LTC3IO/RQMyoHcQN+3cnljW3dNIFC47qDaK3g7BwdTkwBaBELT4ZPOUVWgKl4ZBnjxJPUlMDnTDrp0pmr6RHFeEjjcUUXPDGeSEwDN0Xg8sivxMhJNjGzbHd8PkM3eHRfkrBM5NkcQaY2vUnTlrDIA0NoaX+KLXFFlowr14tvVpqb2MICzmQcKqxvbumv+NAhZGCCIPwEw6QWXKYRL/VUXO0+rAUJiPwAk5MIlgVfwPjjHLCL1APmHN94ZdqeYN+NW/mn6I4BvwQYchcLnwFhJMDiYmlRxAzjpKWZkYkUCcZ2I61wi37tLbYyjiN0fHk5Oz3nGSLSzBbNHCF35R7f6K1/hN9PRhek11FrymfQQQKB4+Gl05P2qNRtmETlXW7e+b2z01dfycGNbfFMAbqNyKp9Jp4rzOT8RYFs0njJkc2iqsCObvTsOsDWWqA5C1uFy+Uz/oXJeKwVT4h0RmPUXhi79vuC0Ku6yOffTK3g9lfxfDQAisY516sg5kfOCiJk7HoLt2cf9b/9LANAc7dznm98PagG1fUOZ9IP5uMB8Q4CPoyNvausapkTt3rNMuvdf3C/o6+czhtdwmwAAAABJRU5ErkJggg==
+
+
+
+ Viz Image Sample
+
+
+
diff --git a/Samples/VizImage/vizImage.html b/Samples/VizImage/vizImage.html
new file mode 100644
index 00000000..df3d5ade
--- /dev/null
+++ b/Samples/VizImage/vizImage.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ Viz Image Sample
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Viz Image Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/VizImage/vizImage.js b/Samples/VizImage/vizImage.js
new file mode 100644
index 00000000..00117564
--- /dev/null
+++ b/Samples/VizImage/vizImage.js
@@ -0,0 +1,77 @@
+'use strict';
+
+// Wrap everything in an anonymous function to avoid polluting the global namespace
+(function () {
+ $(document).ready(function () {
+ tableau.extensions.initializeAsync().then(function () {
+ addVizImage(tableau.MarkType.Bar, 'tableau20_10_0');
+
+ let markSelector = $('#mark-select');
+ let colorSelector = $('#color-select');
+
+ markSelector.prop('disabled', false);
+ colorSelector.prop('disabled', false);
+
+ // updating viz images with new values upon a selector change.
+ markSelector.change(function () {
+ addVizImage(markSelector.val(), colorSelector.val());
+ });
+ colorSelector.change(function () {
+ addVizImage(markSelector.val(), colorSelector.val());
+ });
+ });
+ });
+
+ // This function creates and displays a viz image.
+ function addVizImage (markType, palette) {
+ // Building the input specification object that is used to create the viz image.
+ // Data values used in the viz image are prefilled.
+ const vizInputSpec = {
+ description: 'A sample viz', // optional parameter.
+ size: {width: 400, height: 300},
+ data: {
+ values: [
+ {'Product': 'Paper', 'Sales': 28, 'Region': 'Central'},
+ {'Product': 'Pens', 'Sales': 45, 'Region': 'East'},
+ {'Product': 'Rulers', 'Sales': 35, 'Region': 'East'},
+ {'Product': 'Rulers', 'Sales': 43, 'Region': 'South'},
+ {'Product': 'Paper', 'Sales': 50, 'Region': 'West'},
+ {'Product': 'Pens', 'Sales': 56, 'Region': 'West'}
+ ]
+ },
+ mark: markType,
+ markcolor: '#FFED5F', // may not get used in viz if color is encoded in viz.
+ encoding: {
+ columns: {field: 'Region', type: tableau.VizImageEncodingType.Discrete},
+ rows: {field: 'Sales', type: tableau.VizImageEncodingType.Continuous},
+ color: {field: 'Product', type: tableau.VizImageEncodingType.Discrete, palette}
+ }
+ };
+
+ // defaulting values if null.
+ if (markType === null) {
+ vizInputSpec.mark = tableau.MarkType.Bar;
+ }
+ if (palette === null) {
+ vizInputSpec.encoding.color.palette = 'tableau20_10_0';
+ }
+
+ // making call to create viz image from the input specifications.
+ tableau.extensions.createVizImageAsync(vizInputSpec).then(function (svg) {
+ var blob = new Blob([svg], { type: 'image/svg+xml' });
+ var url = URL.createObjectURL(blob);
+ var image = document.createElement('img');
+ image.src = url;
+ image.style.maxWidth = '100%';
+ image.style.maxHeight = '100%';
+ image.className = 'center-block';
+ var vizApiElement = document.getElementById('viz-container');
+ // clearing UI and adding in new viz.
+ vizApiElement.innerHTML = '';
+ vizApiElement.appendChild(image);
+ image.addEventListener('load', function () { return URL.revokeObjectURL(url); }, { once: true });
+ }, function (err) {
+ console.log(err);
+ });
+ }
+})();
diff --git a/package-lock.json b/package-lock.json
index 57670803..2fe90cc1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -92,9 +92,9 @@
}
},
"@tableau/tabextsandbox": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@tableau/tabextsandbox/-/tabextsandbox-1.1.0.tgz",
- "integrity": "sha512-uWo+JsyCHhBg2bNBt6Y47Drv1AM7CuOZ0veTy88tu+dMYTI3SApL0J/eWajJmSz9EAs+ZLxYzQLO0auTb2nnGw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@tableau/tabextsandbox/-/tabextsandbox-1.2.1.tgz",
+ "integrity": "sha512-psZ8OVb1fcJvcQnSbZXW2LzDBivr5YYUTrt+6H8iiRepILmuC19HYvuPXTu2JFKliUD9fnVrsm/wRrMn6NhXrQ==",
"dev": true,
"requires": {
"ejs": "^2.6.1",
diff --git a/package.json b/package.json
index 5cb7edef..3692fdc4 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
},
"devDependencies": {
"@tableau/extensions-api-types": "1.6.0",
- "@tableau/tabextsandbox": "^1.1.0",
+ "@tableau/tabextsandbox": "^1.2.1",
"@types/jquery": "^3.3.29",
"concurrently": "^6.2.1",
"semistandard": "^11.0.0",
diff --git a/webpack.config.js b/webpack.config.js
index ec4bb526..86e46f9b 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -7,6 +7,7 @@ module.exports = {
datasources: './Samples-Typescript/DataSources/datasources.ts',
filtering: './Samples-Typescript/Filtering/filtering.ts',
parameters: './Samples-Typescript/Parameters/parameters.ts',
+ vizImage: './Samples-Typescript/VizImage/vizImage.ts',
},
mode: 'production',
output: {