Repository: microsoft/SandDance (language: python)

Issue:
Add setup parameter to load message
- In order to fully configure the SandDance embed control, you need to add a setup parameter to the data object sent using the "load" postMessage()
- Document the setup object
- Add another event to return the setup object, similar to the insight event.


Discussion / hints:

Fix patch:
diff --git a/packages/sanddance-embed/README.md b/packages/sanddance-embed/README.md
index 504b4ae0..2f5dc59b 100644
--- a/packages/sanddance-embed/README.md
+++ b/packages/sanddance-embed/README.md
@@ -67,23 +67,50 @@ This promise provides you `embedIframe` when it is available:
 ## Send commands to SandDance Embed
 Use `postMessage` to communicate with `embedIframe.contentWindow`. For all command requests, see https://github.com/microsoft/SandDance/blob/master/packages/sanddance-embed/src/types/message-request.d.ts
 
-* Load data and display initial chart:
+* Use the [load command](https://microsoft.github.io/SandDance/docs/sanddance-embed/v4/interfaces/types_message_request.MessageRequest_Load.html) to load data and display initial chart:
     ```js
     const data = [
         { x: 0, y: 0, z: 0 },
         { x: 1, y: 1, z: 1 },
         { x: 2, y: 2, z: 2 },
     ];
-    embedIframe.contentWindow.postMessage({ action: 'load', data, props: { theme: 'dark-theme' } }, '*');
+    embedIframe.contentWindow.postMessage({ action: 'load', data }, '*');
     ```
-    The `data` variable can be an array, or a [DataFile object](https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/DataFile.html). The `props` member is optional [Explorer Props](https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/Props.html), here is shown used to specify the dark color theme.  
+    
+    The `data` variable can be an array, or a [DataFile object](https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/DataFile.html). 
+    
+    Notable optional parameters:
 
-* Get insight:
+    * The `props` member, of type [Explorer Props](https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/Props.html), here is shown used to specify the dark color theme, initially close the sidebar, and use the advanced renderer: 
+    ```js
+    const props = { theme: 'dark-theme', initialSidebarClosed: true, initialRenderer: { advanced: true } };
+    embedIframe.contentWindow.postMessage({ action: 'load', data, props }, '*');
+    ```
+
+    *Note that the `props` member is for initializing the instance of SandDance Explorer. A new dataset can be loaded with a subsequent load command, but `props` will be not be used.*
+
+
+    * The `insight` member, of type [Insight](https://microsoft.github.io/SandDance/docs/sanddance-specs/v1/interfaces/Insight.html), to specify a chart view: 
+    ```js
+    const insight = {
+        chart: 'barchartH',
+        columns: {
+            y: 'Age',
+            z: 'TicketCost',
+            color: 'Class'
+        },
+        scheme: 'category10',
+        view: '3d',
+    };
+    embedIframe.contentWindow.postMessage({ action: 'load', data, insight }, '*');
+    ```
+
+* The [getInsight command](https://microsoft.github.io/SandDance/docs/sanddance-embed/v4/interfaces/types_message_request.MessageRequest_GetInsight.html) will request the current insight:
     ```js
     embedIframe.contentWindow.postMessage({ action: 'getInsight' }, '*');
     ```
 
-* Get or set theme:
+* The [theme command](https://microsoft.github.io/SandDance/docs/sanddance-embed/v4/interfaces/types_message_request.MessageRequest_Theme.html) will get or set the theme:
     ```js
     embedIframe.contentWindow.postMessage({ action: 'theme', dark: true }, '*');
     ```
diff --git a/packages/sanddance-embed/package-lock.json b/packages/sanddance-embed/package-lock.json
index bfa9158d..d52fc4fa 100644
--- a/packages/sanddance-embed/package-lock.json
+++ b/packages/sanddance-embed/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "@msrvida/sanddance-embed",
-  "version": "4.4.2",
+  "version": "4.4.3",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@msrvida/sanddance-embed",
-      "version": "4.4.2",
+      "version": "4.4.3",
       "license": "MIT",
       "devDependencies": {
         "@fluentui/react": "^8",
diff --git a/packages/sanddance-embed/package.json b/packages/sanddance-embed/package.json
index 024e3b9f..ed3528b3 100644
--- a/packages/sanddance-embed/package.json
+++ b/packages/sanddance-embed/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@msrvida/sanddance-embed",
-  "version": "4.4.2",
+  "version": "4.4.3",
   "description": "Embeddable SandDance Explorer.",
   "browser": "dist/umd/sanddance-embed.js",
   "repository": {
diff --git a/packages/sanddance-embed/src/sanddance-embed.ts b/packages/sanddance-embed/src/sanddance-embed.ts
index 261b16cb..03749938 100644
--- a/packages/sanddance-embed/src/sanddance-embed.ts
+++ b/packages/sanddance-embed/src/sanddance-embed.ts
@@ -18,7 +18,12 @@ namespace SandDanceEmbed {
     let creating = false;
     let innerLoad: () => void;
 
-    export function load(data: DataToLoad, insight?: Partial<SandDanceExplorer.SandDance.specs.Insight>, props?: SandDanceExplorer.Props) {
+    export function load(
+        data: DataToLoad,
+        insight?: Partial<SandDanceExplorer.SandDance.specs.Insight>,
+        props?: SandDanceExplorer.Props,
+        options?: SandDanceExplorer.Options,
+    ) {
         return new Promise((resolve) => {
 
             innerLoad = () => {
@@ -27,7 +32,7 @@ namespace SandDanceEmbed {
                     //TODO make sure that insight columns exist in dataset
                     getPartialInsight = columns => insight;
                 }
-                sandDanceExplorer.load(data, getPartialInsight).then(resolve);
+                sandDanceExplorer.load(data, getPartialInsight, options).then(resolve);
             };
 
             const create = () => {
@@ -145,7 +150,12 @@ namespace SandDanceEmbed {
             }
             case 'load': {
                 const request_load = request as MessageRequest_Load;
-                load(request_load.data, request_load.insight, request_load.props).then(() => {
+                load(
+                    request_load.data,
+                    request_load.insight,
+                    request_load.props,
+                    request_load.options,
+                ).then(() => {
                     response = {
                         request,
                     };
@@ -165,10 +175,19 @@ namespace SandDanceEmbed {
             case 'getInsight': {
                 response = <MessageResponse_GetInsight>{
                     request,
-                    insight: sandDanceExplorer.viewer.getInsight(),
+                    insight: sandDanceExplorer.getInsight(),
                 };
                 break;
             }
+            case 'getSetup': {
+                const setup: SandDanceExplorer.SandDance.types.Setup = sandDanceExplorer.getSetup();
+                setup.camera = sandDanceExplorer.viewer.getCamera();
+                response = <MessageResponse_GetSetup>{
+                    request,
+                    setup,
+                };
+                break;
+            };
             case 'theme': {
                 const request_theme = request as MessageRequest_Theme;
                 if (request_theme.dark !== undefined) {
diff --git a/packages/sanddance-embed/src/types/message-request.d.ts b/packages/sanddance-embed/src/types/message-request.d.ts
index 3e6a9eb9..9c343f09 100644
--- a/packages/sanddance-embed/src/types/message-request.d.ts
+++ b/packages/sanddance-embed/src/types/message-request.d.ts
@@ -28,6 +28,11 @@ interface MessageRequest_Load extends MessageRequestBase {
      * See https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/Props.html
      */
     props?: SandDanceExplorer.Props;
+
+    /**
+     * See https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/Options.html
+     */
+    options?: SandDanceExplorer.Options;
 }
 
 interface MessageRequest_GetData extends MessageRequestBase {
@@ -38,6 +43,10 @@ interface MessageRequest_GetInsight extends MessageRequestBase {
     action: 'getInsight';
 }
 
+interface MessageRequest_GetSetup extends MessageRequestBase {
+    action: 'getSetup';
+}
+
 interface MessageRequest_Theme extends MessageRequestBase {
     action: 'theme';
     dark?: boolean;
@@ -56,6 +65,7 @@ type MessageRequest =
     | MessageRequest_Load
     | MessageRequest_GetData
     | MessageRequest_GetInsight
+    | MessageRequest_GetSetup
     | MessageRequest_Theme
     | MessageRequest_EventCanvasClick
     | MessageRequest_EventCubeClick
diff --git a/packages/sanddance-embed/src/types/message-response.d.ts b/packages/sanddance-embed/src/types/message-response.d.ts
index 44c430da..a968536f 100644
--- a/packages/sanddance-embed/src/types/message-response.d.ts
+++ b/packages/sanddance-embed/src/types/message-response.d.ts
@@ -16,6 +16,14 @@ interface MessageResponse_GetInsight extends MessageResponseBase {
     insight: SandDanceExplorer.SandDance.types.Insight;
 }
 
+interface MessageResponse_GetSetup extends MessageResponseBase {
+
+    /**
+     * See https://microsoft.github.io/SandDance/docs/sanddance-explorer/v4/interfaces/SandDance.types.Setup.html
+     */
+    setup: SandDanceExplorer.SandDance.types.Setup;
+}
+
 interface MessageResponse_EventError extends MessageResponseBase {
     errors: string[];
 }
@@ -36,6 +44,7 @@ type MessageResponse =
     | MessageResponse_Init
     | MessageResponse_GetData
     | MessageResponse_GetInsight
+    | MessageResponse_GetSetup
     | MessageResponse_Theme
     | MessageResponse_EventCanvasClick
     | MessageResponse_EventCubeClick
diff --git a/packages/sanddance-explorer/package-lock.json b/packages/sanddance-explorer/package-lock.json
index 5cec531d..84dd02e2 100644
--- a/packages/sanddance-explorer/package-lock.json
+++ b/packages/sanddance-explorer/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "@msrvida/sanddance-explorer",
-  "version": "4.0.7",
+  "version": "4.0.8",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@msrvida/sanddance-explorer",
-      "version": "4.0.7",
+      "version": "4.0.8",
       "license": "MIT",
       "dependencies": {
         "d3-format": "^1.3.2"
diff --git a/packages/sanddance-explorer/package.json b/packages/sanddance-explorer/package.json
index 90521bc9..933eb6db 100644
--- a/packages/sanddance-explorer/package.json
+++ b/packages/sanddance-explorer/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@msrvida/sanddance-explorer",
-  "version": "4.0.7",
+  "version": "4.0.8",
   "description": "SandDance data exploration React component.",
   "main": "dist/es6/index.js",
   "repository": {
diff --git a/packages/sanddance-explorer/src/defaults.ts b/packages/sanddance-explorer/src/defaults.ts
index 17bf8618..414e983c 100644
--- a/packages/sanddance-explorer/src/defaults.ts
+++ b/packages/sanddance-explorer/src/defaults.ts
@@ -35,6 +35,13 @@ export const defaultRenderer: SandDance.VegaMorphCharts.types.MorphChartsRendere
 };
 
 export function initialExplorerState(props: Props) {
+    const renderer = (props.initialRenderer as SandDance.VegaMorphCharts.types.MorphChartsRendererOptions) || defaultRenderer;
+    if (!renderer.advancedOptions) {
+        renderer.advancedOptions = defaultRenderer.advancedOptions;
+    }
+    if (!renderer.basicOptions) {
+        renderer.basicOptions = defaultRenderer.basicOptions;
+    }
     const state: State = {
         calculating: null,
         errors: null,
@@ -62,8 +69,8 @@ export function initialExplorerState(props: Props) {
         sideTabId: SideTabId.ChartType,
         dataScopeId: DataScopeId.AllData,
         selectedItemIndex: {},
-        sidebarClosed: false,
-        sidebarPinned: true,
+        sidebarClosed: props.initialSidebarClosed === undefined ? false : props.initialSidebarClosed,
+        sidebarPinned: props.initialSidebarPinned === undefined ? true : props.initialSidebarPinned,
         view: props.initialView || '2d',
         snapshots: [],
         selectedSnapshotIndex: -1,
@@ -72,7 +79,7 @@ export function initialExplorerState(props: Props) {
         note: null,
         historyIndex: -1,
         historyItems: [],
-        renderer: props.initialRenderer || defaultRenderer,
+        renderer,
         transitionType: 'ordinal',
         transitionDimension: 'x',
         transitionDurations: SandDance.VegaMorphCharts.util.clone(SandDance.VegaMorphCharts.defaults.defaultPresenterConfig.transitionDurations),
diff --git a/packages/sanddance-explorer/src/explorer.tsx b/packages/sanddance-explorer/src/explorer.tsx
index e36e4441..7af3e59d 100644
--- a/packages/sanddance-explorer/src/explorer.tsx
+++ b/packages/sanddance-explorer/src/explorer.tsx
@@ -93,7 +93,9 @@ export interface Props {
     onSetupOptionsChanged?: (setup: SandDance.types.Setup) => void;
     additionalSettings?: SettingsGroup[];
     systemInfoChildren?: React.ReactNode;
-    initialRenderer?: SandDance.VegaMorphCharts.types.MorphChartsRendererOptions;
+    initialRenderer?: Partial<SandDance.VegaMorphCharts.types.MorphChartsRendererOptions>;
+    initialSidebarClosed?: boolean;
+    initialSidebarPinned?: boolean;
     renderOptions?: SandDance.types.RenderOptions;
 }
 


Test patch:
diff --git a/docs/embed/v4/dynamic/test.html b/docs/embed/v4/dynamic/test.html
index a042545f..d9c78570 100644
--- a/docs/embed/v4/dynamic/test.html
+++ b/docs/embed/v4/dynamic/test.html
@@ -13,10 +13,12 @@
         <h1>sanddance embed test</h1>
     </header>
 
-    <iframe id="embed" title="embed" style="width: 90%; height: 600px" src="target.html"></iframe>
+    <iframe id="embed" title="embed" style="width: 90%; height: 700px" src="target.html"></iframe>
 
     <div>
         <button id="button_theme">toggle dark theme</button>
+        <button id="button_insight">get insight</button>
+        <button id="button_setup">get setup</button>
     </div>
 
     <script>
@@ -25,12 +27,32 @@ <h1>sanddance embed test</h1>
         };
         const embedIframe = document.getElementById('embed');
         embedIframe.onload = () => {
-            const embedWindow = embedIframe.contentWindow;
             fetch('../../../sample-data/titanicmaster.tsv')
                 .then(response => response.text())
                 .then(rawText => {
                     const data = { rawText, type: 'tsv' };
-                    embedWindow.postMessage({ action: 'load', data, props: { theme: 'dark-theme' } }, '*');
+                    embedIframe.contentWindow.postMessage({
+                        action: 'load',
+                        data,
+                        insight: {
+                            chart: 'barchartH',
+                            columns: {
+                                y: 'Age',
+                                z: 'TicketCost',
+                                color: 'Class'
+                            },
+                            scheme: 'category10',
+                            view: '3d',
+                        },
+                        props: {
+                            theme: 'dark-theme',
+                            initialSidebarClosed: true,
+                            initialSidebarPinned: false,
+                            initialRenderer: {
+                                advanced: true,
+                            },
+                        }
+                    }, '*');
                 });
         };
 
@@ -40,6 +62,16 @@ <h1>sanddance embed test</h1>
             dark = !dark;
             embedIframe.contentWindow.postMessage({ action: 'theme', dark }, '*');
         };
+
+        const button_insight = document.getElementById('button_insight');
+        button_insight.onclick = () => {
+            embedIframe.contentWindow.postMessage({ action: 'getInsight' }, '*');
+        };
+
+        const button_setup = document.getElementById('button_setup');
+        button_setup.onclick = () => {
+            embedIframe.contentWindow.postMessage({ action: 'getSetup' }, '*');
+        };
     </script>
 
 </body>
diff --git a/packages/sanddance-embed/test/dynamic-deps/test.html b/packages/sanddance-embed/test/dynamic-deps/test.html
index 1e86083a..8a4cace5 100644
--- a/packages/sanddance-embed/test/dynamic-deps/test.html
+++ b/packages/sanddance-embed/test/dynamic-deps/test.html
@@ -17,6 +17,8 @@ <h1>sanddance embed test</h1>
 
     <div>
         <button id="button_theme">toggle dark theme</button>
+        <button id="button_insight">get insight</button>
+        <button id="button_setup">get setup</button>
         <a href="?">localDev</a>
         <a href="?prod">prod</a>
     </div>
@@ -31,7 +33,28 @@ <h1>sanddance embed test</h1>
                 .then(response => response.text())
                 .then(rawText => {
                     const data = { rawText, type: 'tsv' };
-                    embedIframe.contentWindow.postMessage({ action: 'load', data, props: { theme: 'dark-theme' } }, '*');
+                    embedIframe.contentWindow.postMessage({
+                        action: 'load',
+                        data,
+                        insight: {
+                            chart: 'barchartH',
+                            columns: {
+                                y: 'Age',
+                                z: 'TicketCost',
+                                color: 'Class'
+                            },
+                            scheme: 'category10',
+                            view: '3d',
+                        },
+                        props: {
+                            theme: 'dark-theme',
+                            initialSidebarClosed: true,
+                            initialSidebarPinned: false,
+                            initialRenderer: {
+                                advanced: true,
+                            },
+                        }
+                    }, '*');
                 });
         };
         embedIframe.src = `target.html${location.search}`;
@@ -43,6 +66,15 @@ <h1>sanddance embed test</h1>
             embedIframe.contentWindow.postMessage({ action: 'theme', dark }, '*');
         };
 
+        const button_insight = document.getElementById('button_insight');
+        button_insight.onclick = () => {
+            embedIframe.contentWindow.postMessage({ action: 'getInsight' }, '*');
+        };
+
+        const button_setup = document.getElementById('button_setup');
+        button_setup.onclick = () => {
+            embedIframe.contentWindow.postMessage({ action: 'getSetup' }, '*');
+        };
     </script>
 
 </body>