MicroStrategy ONE
Modify the Plugin Structure for the React Format Panel
This feature is available starting in MicroStrategy 2021 Update 3.
Before moving to the new Format panel structure, you must modify the plugin structure. This section details what changes need to be made.
-
Modify Files and Functions that Initialize and Render the Plugin
-
Modify the Main File that Initializes and Renders the Plugin
Modify Logic for Managing Properties
Create a properties
folder to contain the files that handle the logic responsible for managing property definitions and values. Download the entire folder, with the same properties used in the sample plugin, in properties.zip
. The properties
folder contains the following files:
This file contains definitions for all used properties. All definitions are stored inside the PROPERTIES_INFO
variable. The variable is also used inside Format panel logic.
Each property is defined according to the template below.
SHOW_METRIC: { // SHOW_METRIC - enum that is binded to the property
name: "showMetric", // name - name that represents the enum
defaultValue: true, // defaultValue - initial value for the property
},
This file contains the logic responsible for modifying property values before they are passed to render functions, if necessary.
This file contains the logic responsible for dynamically setting the default values for properties, if necessary.
Modify Files and Functions that Initialize and Render the Plugin
Create a src/utils
folder to contain all of the files and functions used during various stages of rendering and initializing the plugin. This folder contains enhanceHost.js
, which adds new methods to the main visualization object (host) to enable the management of properties using one unified property.
Add Format Panel Icons
Add example icons for the Format panel components using src/images/format_panel_icons.svg
.
Update the CSS
Update src/vis.less
to add styles for rendered components, components inside the Format panel, and all necessary icons. This CSS file is used in the sample visualization.
Modify the Main File that Initializes and Renders the Plugin
This section details the src/SampleViz.js
file, which is the main file used to initialize the plugin, as well as render the visualization. A few modifications need to be made to this file. All of these modifications are included in the sample plugin.
Imports
Import all necessary functions at the top of the file.
import { adjustProperties } from "./properties/adjustProperties";
import { getDefaultProperties } from "./properties/getDefaultProperties";
import { enhanceHost } from "./utils/enhanceHost";
init function
In the init
function, add new methods that enhance the host.
init(props) {
this._super(props);
enhanceHost(this);
const defaultPropertyValues = getDefaultProperties();
this.setDefaultPropertyValues(defaultPropertyValues);
},
clearDomNode function
Add the clearDomNode
function before the plot
function to clear the DOM node.
clearDomNode() {
const host = this;
const { domNode } = host;
domNode.innerHTML = "";
},
appliedProperties argument
Add this argument to the plot
function and set the default value to null
.
plot(appliedProperties = null) {
clearDomNode in the plot function
At the beginning of the plot
function, add new lines to clear the DOM node before each render.
const host = this;
host.clearDomNode();
Add functions to incorporate property management
Add functions to enable better management of property values.
let properties;
if (appliedProperties) {
properties = adjustProperties(appliedProperties, host);
} else {
const savedProperties = JSON.parse(host.getProperty("unifiedProperty"));
properties = adjustProperties(savedProperties, host);
}
Modify code for rendering the plugin
Adjust the code responsible for rendering the content of the plugin according to your needs. For the sample plugin, make the changes shown below.
-
Remove unused imports from the top of the file:
Copyimport * as d3 from 'd3';
import cloud from 'd3-cloud'; -
Remove the section formerly responsible for rendering the content in the
plot
function.Copyconst minFont = this.getProperty('minFont');
const maxFont = this.getProperty('maxFont');
const numOfWords = this.getProperty('numOfWords');
const spiral = this.getProperty('spiral');
const textFont = this.getProperty('textFont');
let data = graphicModels
.sort((a, b) => b.value - a.value)
.slice(0, Math.max(graphicModels.length, numOfWords));
const scaleFont = d3.scaleLinear()
.domain([data[0].value, data[data.length - 1].value])
.range([maxFont, minFont]);
const width = parseInt(this.width, 10);
const height = parseInt(this.height, 10);
const container = d3.select(this.domNode);
data = data.map(d => ({ ...d, size: scaleFont(d.value) }));
cloud()
.size([width, height])
.timeInterval(1000)
.words(data)
.padding(1)
.font(textFont.fontFamily)
.fontSize(d => d.size)
.spiral(spiral.ellipse === 'true' ? 'archimedean' : 'rectangular')
.on('end', words => {
const hashStr2Color = str => {
let num = 0;
for (let i = 0; i < str.length; i++) {
num += str.charCodeAt(i);
}
return d3.schemePaired[num % d3.schemePaired.length];
};
container
.html(null)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`)
.selectAll('text')
.data(words)
.enter()
.append('text')
.style('font-size', d => `${d.size}px`)
.style('font-family', textFont.fontFamily)
.style('fill', d => hashStr2Color(d.text))
.attr('text-anchor', 'middle')
.attr('transform', d => `translate(${[d.x, d.y]})rotate(${d.rotate})`)
.text(d => d.text);
})
.start(); -
Add the new code for rendering the content in the
plot
function.Copyconst {
showAttribute,
showMetric,
attributeBackgroundColor,
metricBackgroundColor,
attributeFontFamily,
attributeFontStyle,
attributeFontColor,
attributeFontSize,
metricFontFamily,
metricFontStyle,
metricFontColor,
metricFontSize,
} = properties;
const addStyle = (
element,
fontFamily,
fontColor,
fontSize,
fontStyle
) => {
element.style.fontFamily = fontFamily;
element.style.color = fontColor;
element.style.fontSize = `${fontSize}px`;
const [isBold, isItalic, isUnderlined, isCrossedOut] = fontStyle;
element.style.fontWeight = isBold ? "bold" : "normal";
element.style.fontStyle = isItalic ? "italic" : "normal";
const textDecorationOptions = [];
if (isUnderlined) textDecorationOptions.push("underline");
if (isCrossedOut) textDecorationOptions.push("line-through");
const textDecoration = textDecorationOptions.join(" ");
element.style.textDecoration = textDecoration;
};
graphicModels.forEach((graphicModel) => {
const container = document.createElement("div");
container.classList.add("container");
const attributeContainer = document.createElement("div");
attributeContainer.classList.add("attributeContainer");
attributeContainer.style.backgroundColor = attributeBackgroundColor;
const attributeContainerText = document.createTextNode(
showAttribute ? graphicModel.text : ""
);
addStyle(
attributeContainer,
attributeFontFamily,
attributeFontColor,
attributeFontSize,
attributeFontStyle
);
attributeContainer.appendChild(attributeContainerText);
const metricContainer = document.createElement("div");
metricContainer.classList.add("metricContainer");
metricContainer.style.backgroundColor = metricBackgroundColor;
const metricContainerText = document.createTextNode(
showMetric ? graphicModel.value : ""
);
addStyle(
metricContainer,
metricFontFamily,
metricFontColor,
metricFontSize,
metricFontStyle
);
metricContainer.appendChild(metricContainerText);
container.appendChild(attributeContainer);
container.appendChild(metricContainer);
host.domNode.appendChild(container);
});
Internationalization (i18n)
-
To internationalize plugin text, you must populate the appropriate files with the translated strings. See Add New Custom Translations for more information.
-
Once you have added the translated strings, see step 6 in Add New Custom Translations to add the strings to the code.
-
Add the function responsible for loading translated strings. In the sample plugin, add the following line just after the imports at the top of the file.
Copymstrmojo.requiresDescsWPrefix("SampleViz.", 10, 11, 12, 13);
In the sample plugin, translations have already been added to the Format panel. However, you can also internationalize error messages, labels included in the drop zone area, or visualization text.