API de formato en objeto (versión preliminar)
formato on-object permite a los usuarios modificar rápidamente y fácilmente el formato de los objetos visuales seleccionando directamente los elementos que desean modificar. Cuando se selecciona un elemento, el panel de formato navega automáticamente y expande la configuración de formato específica del elemento seleccionado. Para obtener más información sobre el formato en el objeto, consulte Formato en objetos en Power BI Desktop.
Para agregar estas funcionalidades al objeto visual, cada objeto visual debe proporcionar una opción de estilo de subselección y acceso directo para cada región subselectable.
Nota
- Los objetos visuales que admiten el formato en objetos deben implementar el API getFormattingModel que está disponible en la versión 5.1 de la API.
- Si usa powerbi-visuals-utils-formatmodel, use la versión 6.0.0 al menos.
Creación de una experiencia en el objeto
Use el servicio de subselección cuando el usuario seleccione un elemento subselectable para enviar Power BI a la subselección. Proporcione los estilos y métodos abreviados de subselección mediante la API subselección. El asistente de subselección se puede usar para simplificar el proceso.
Modo de formato
El modo de formato es un nuevo modo en el que el usuario puede activar y desactivar onObject
formato cuando se encuentra en modo de creación. El objeto visual se actualiza con el estado del modo de formato en las opciones de actualización. Las opciones de actualización también incluyen la subselección subselección seleccionada actualmente como CustomVisualSubSelection
.
Implementación de la API de formato en objetos
Archivo de funcionalidades
En el archivo capabilites.json, agregue las siguientes propiedades para declarar que el objeto visual admite el formato en el objeto:
{
"supportsOnObjectFormatting": true,
"enablePointerEventsFormatMode": true,
}
Interfaz IVisual
El objeto visual debe implementar la interfaz VisualOnObjectFormatting
como parte de la interfaz IVisual.
VisualOnObjectFormatting contiene tres métodos:
- getSubSelectionStyles
- getSubSelectionShortcuts
- getSubSelectables
getSubSelectionStyles
Cada objeto visual es necesario para implementar un método getSubSelectionStyles
, al que se llama cuando se subselectable elemento es subselectable. El método getSubSelectionStyles
se proporciona con los elementos subselecciondos actuales como una matriz de CustomVisualSubSelection
y se espera que devuelva un objeto SubSelectionStyles
o undefined
.
Hay tres categorías de estilos de subselección que abarcan la mayoría de los escenarios:
- Mensaje de texto
- Texto numérico
- Forma
Cada objeto SubSelectionStyles
proporciona una experiencia diferente para el usuario para modificar el estilo de un elemento.
getSubSelectionShortcuts
Para proporcionar más opciones para el usuario, el objeto visual debe implementar el método getSubSelectionShortcuts
. Este método devuelve VisualSubSelectionShortcuts
o undefined
. Además, si se proporcionan SubSelectionShortcuts
, también se debe proporcionar un VisualNavigateSubSelectionShortcut
para que cuando un usuario subseleccione un elemento y el panel de formato esté abierto, el panel se desplaza automáticamente a la tarjeta adecuada.
Hay varios métodos abreviados de subselección para modificar el estado visual. Cada uno define un elemento de menú en el menú contextual con la etiqueta adecuada.
Sub-Selection Menú de desambiguación: El menú Desambiguación de objetos proporciona un método para que los usuarios seleccionen su subselección deseada cuando no esté claro qué elemento visual se está subseleccionando. Esto suele ocurrir cuando el usuario subselecciona el fondo del objeto visual. Para que el menú desambiguado presente más subselecciones, el objeto visual debe proporcionar todas las subselecciones a través del método getSubSelectables
.
getSubSelectables
Para proporcionar subselecciones al menú de desambiguación, el objeto visual debe implementar el método getSubSelectables
. Este método se proporciona un argumento opcional filterType
, de tipo SubSelectionStylesType
y devuelve una matriz de CustomVisualSubSelection
o undefined
.
Si se utiliza el HTMLSubSelectionHelper
para crear una subselección, el método HTMLSubSelectionHelper.getSubSelectables() se puede usar para recopilar elementos subselectables del DOM.
Sub-Selection Edición directa de texto: Con formato on-Object, puede hacer doble clic en el texto de un elemento subselecible para editarlo directamente.
Para proporcionar la funcionalidad de edición directa, debe proporcionar un RectangleSubSelectionOutline
con la propiedad cVDirectEdit adecuada rellenada con un objeto SubSelectableDirectEdit. El esquema se puede proporcionar como un esquema personalizado o, si usa el HTMLSubSelectionHelper
puede usar el atributo SubSelectableDirectEdit
. (Consulte los atributos proporcionados por HTMLSubSelectionHelper)
Todavía no se admite la adición de una edición directa para un punto de datos específico (mediante selectores).
Interfaz FormatId
La siguiente interfaz se usa para hacer referencia a los métodos abreviados y estilos de subSelection
.
interface FormattingId {
objectName: string;
propertyName: string;
selector?: powerbi.data.Selector;
}
- objectName: el nombre del objeto tal como se declara en el capabilities.json.
- propertyName: el nombre de propiedad de un objeto como se declara en el capabilities.json.
- selector: si el punto de datos tiene un selectionId, use selectionId.getSelector(), este selector debe ser el mismo que se proporciona para el segmento de modelo de formato.
Ejemplos
En este ejemplo, creamos un objeto visual personalizado que tiene dos objetos, colorSelector
y directEdit
. Usamos el HTMLSubSelectionHelper
de las utilidades de onobjectFormatting
, para controlar la mayoría del trabajo de subselección.
Para obtener más información, vea utilidades en objetos.
En primer lugar, creamos tarjetas para el panel de formato y proporcionamos subSelectionShortcuts y estilos para cada subselectable.
Definición de los objetos
Defina los objetos y declare que el objeto visual admite el formato OnObject en el capabilities.json:
"objects": {
"directEdit": {
"properties": {
"show": {
"displayName": "Show",
"type": {
"bool": true
}
},
"textProperty": {
"displayName": "Text",
"type": {
"text": true
}
},
"fontFamily": {
"type": {
"formatting": {
"fontFamily": true
}
}
},
"fontSize": {
"type": {
"formatting": {
"fontSize": true
}
}
},
"bold": {
"type": {
"bool": true
}
},
"italic": {
"type": {
"bool": true
}
},
"underline": {
"type": {
"bool": true
}
},
"fontColor": {
"displayName": "Font Color",
"type": {
"fill": {
"solid": {
"color": true
}
}
}
},
"background": {
"displayName": "Background",
"type": {
"fill": {
"solid": {
"color": true
}
}
}
},
"position": {
"displayName": "Position",
"type": {
"enumeration": [
{ "displayName": "Left", "value": "Left" }, { "displayName": "Right", "value": "Right" }
]
}
}
}
},
"colorSelector": {
"displayName": "Data Colors",
"properties": {
"fill": {
"displayName": "Color",
"type": {
"fill": {
"solid": {
"color": true
}
}
}
}
}
},
},
"supportsOnObjectFormatting": true,
"enablePointerEventsFormatMode": true,
Compilación de las tarjetas de formato
Compile sus tarjetas de formato mediante las utilidades FormatModel.
Configuración de la tarjeta del selector de colores
class ColorSelectorCardSettings extends Card {
name: string = "colorSelector";
displayName: string = "Data Colors";
slices = [];
}
Agregue un método al formatoSetting para que podamos rellenar los segmentos dinámicamente para el objeto colorSelector (nuestros puntos de datos).
populateColorSelector(dataPoints: BarChartDataPoint[]) {
let slices: formattingSettings.ColorPicker[] = this.colorSelector.slices;
if (dataPoints) {
dataPoints.forEach(dataPoint => {
slices.push(new formattingSettings.ColorPicker({
name: "fill",
displayName: dataPoint.category,
value: { value: dataPoint.color },
selector: dataPoint.selectionId.getSelector(),
}));
});
}
}
Pasamos el selector del punto de datos específico en el campo selector. Este selector es el que se usa al implementar las API get de OnObject.
Configuración de tarjeta de edición directa
class DirectEditSettings extends Card {
displayName = 'Direct Edit';
name = 'directEdit';
private minFontSize: number = 8;
private defaultFontSize: number = 11;
show = new formattingSettings.ToggleSwitch({
name: "show",
displayName: undefined,
value: true,
});
topLevelSlice = this.show;
textProperty = new formattingSettings.TextInput({
displayName: "Text Property",
name: "textProperty",
value: "What is your quest?",
placeholder: ""
});
position = new formattingSettings.ItemDropdown({
name: 'position',
items: [{ displayName: 'Left', value: 'Left' }, { displayName: 'Right', value: 'Right' }],
value: { displayName: 'Right', value: 'Right' }
});
font = new formattingSettings.FontControl({
name: "font",
displayName: 'Font',
fontFamily: new formattingSettings.FontPicker({
name: "fontFamily",
displayName: "Font Family",
value: "Segoe UI, wf_segoe-ui_normal, helvetica, arial, sans-serif"
}),
fontSize: new formattingSettings.NumUpDown({
name: "fontSize",
displayName: "Font Size",
value: this.defaultFontSize,
options: {
minValue: {
type: powerbi.visuals.ValidatorType.Min,
value: this.minFontSize,
}
}
}),
bold: new formattingSettings.ToggleSwitch({
name: 'bold',
displayName: "Font Size",
value: true
}),
italic: new formattingSettings.ToggleSwitch({
name: 'italic',
displayName: "Font Size",
value: true
}),
underline: new formattingSettings.ToggleSwitch({
name: 'underline',
displayName: "Font Size",
value: true
})
});
fontColor = new formattingSettings.ColorPicker({
name: "fontColor",
displayName: "Color",
value: { value: "#000000" }
});
background = new formattingSettings.ColorPicker({
name: "background",
displayName: "Color",
value: { value: "#FFFFFF" }
});
slices = [this.show, this.textProperty, this.font, this.fontColor, this.background, this.position];
}
Uso de atributos auxiliares de subselección
Agregue los atributos HTMLSubSelectionHelper
a nuestros objetos. Para ver qué atributos proporciona HTMLSubSelectionHelper, compruebe en documentación de utilidades del objeto.
Para el atributo directEdit:
import { HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr, SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute } from 'powerbi-visuals-utils-onobjectutils'; const DirectEdit: powerbi.visuals.SubSelectableDirectEdit = { reference: { objectName: 'directEdit', propertyName: 'textProperty' }, style: SubSelectableDirectEditStyle.Outline, }; private visualDirectEditSubSelection = JSON.stringify(DirectEdit); this.directEditElement .classed('direct-edit', true) .classed('hidden', !this.formattingSettings.directEditSettings.show.value) .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.directEditSettings.show.value) .attr(SubSelectableObjectNameAttribute, 'directEdit') .attr(SubSelectableDisplayNameAttribute, 'Direct Edit') .attr(SubSelectableDirectEditAttr, this.visualDirectEditSubSelection)
El
HTMLSubSelectionHelper
usa el atributoSubSelectableDirectEditAttr
para proporcionar la referencia directEdit del esquema directEdit, por lo que se inicia una edición directa cuando un usuario hace doble clic en el elemento.Para colorSelector:
barSelectionMerged .attr(SubSelectableObjectNameAttribute, 'colorSelector') .attr(SubSelectableDisplayNameAttribute, (dataPoint: BarChartDataPoint) => this.formattingSettings.colorSelector.slices[dataPoint.index].displayName) .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape) .classed(HtmlSubSelectableClass, options.formatMode)
Definición de referencias
Defina la siguiente interfaz para simplificar los ejemplos:
Nota
El cardUid
que proporcione debe ser el mismo que el proporcionado para la API getFormattingModel. Por ejemplo, si usa powerbi-visuals-utils-formatmodel, proporcione el cardUid
como visual-cardName-card, donde cardName es el nombre que asignó a esta tarjeta en la configuración del modelo de formato. De lo contrario, es necesario proporcionarlo como el visual-cardUid asignó a esta tarjeta.
interface References {
cardUid?: string;
groupUid?: string;
fill?: FormattingId;
font?: FormattingId;
fontColor?: FormattingId;
show?: FormattingId;
fontFamily?: FormattingId;
bold?: FormattingId;
italic?: FormattingId;
underline?: FormattingId;
fontSize?: FormattingId;
position?: FormattingId;
textProperty?: FormattingId;
}
Para este ejemplo, cree una enumeración para los nombres de objetos:
const enum BarChartObjectNames {
ColorSelector = 'colorSelector',
DirectEdit = 'directEdit'
}
- Referencias para el objeto
directEdit
:
const directEditReferences: References = {
cardUid: 'Visual-directEdit-card',
groupUid: 'directEdit-group',
fontFamily: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'fontFamily'
},
bold: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'bold'
},
italic: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'italic'
},
underline: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'underline'
},
fontSize: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'fontSize'
},
fontColor: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'fontColor'
},
show: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'show'
},
position: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'position'
},
textProperty: {
objectName: BarChartObjectNames.DirectEdit,
propertyName: 'textProperty'
}
};
- Para
colorSelector
:
const colorSelectorReferences: References = {
cardUid: 'Visual-colorSelector-card',
groupUid: 'colorSelector-group',
fill: {
objectName: BarChartObjectNames.ColorSelector,
propertyName: 'fill'
}
};
Implementación de API
Ahora vamos a implementar las API get para el formato onObject y proporcionarlas en visualOnObjectFormatting:
En el código del constructor, proporcione los métodos get en visualOnObjectFormatting:
public visualOnObjectFormatting: powerbi.extensibility.visual.VisualOnObjectFormatting; constructor(options: VisualConstructorOptions) { this.subSelectionHelper = HtmlSubSelectionHelper.createHtmlSubselectionHelper({ hostElement: options.element, subSelectionService: options.host.subSelectionService, selectionIdCallback: (e) => this.selectionIdCallback(e), }); this.visualOnObjectFormatting = { getSubSelectionStyles: (subSelections) => this.getSubSelectionStyles(subSelections), getSubSelectionShortcuts: (subSelections, filter) => this.getSubSelectionShortcuts(subSelections, filter), getSubSelectables: (filter) => this. getSubSelectables(filter) } } private getSubSelectionStyles(subSelections: CustomVisualSubSelection[]): powerbi.visuals.SubSelectionStyles | undefined { const visualObject = subSelections[0]?.customVisualObjects[0]; if (visualObject) { switch (visualObject.objectName) { case BarChartObjectNames.ColorSelector: return this.getColorSelectorStyles(subSelections); case BarChartObjectNames.DirectEdit: return this.getDirectEditStyles(); } } } private getSubSelectionShortcuts(subSelections: CustomVisualSubSelection[], filter: SubSelectionShortcutsKey | undefined): VisualSubSelectionShortcuts | undefined { const visualObject = subSelections[0]?. customVisualObjects[0]; if (visualObject) { switch (visualObject.objectName) { case BarChartObjectNames.ColorSelector: return this.getColorSelectorShortcuts(subSelections); case BarChartObjectNames.DirectEdit: return this.getDirectEditShortcuts(); } } }
Implemente los métodos abreviados y el estilo getSubSelection para colorSelector:
private getColorSelectorShortcuts(subSelections: CustomVisualSubSelection[]): VisualSubSelectionShortcuts { const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); return [ { type: VisualShortcutType.Reset, relatedResetFormattingIds: [{ ...colorSelectorReferences.fill, selector }], }, { type: VisualShortcutType.Navigate, destinationInfo: { cardUid: colorSelectorReferences.cardUid }, label: 'Color' } ]; }
El acceso directo anterior devuelve el elemento de menú pertinente en el menú contextual y agrega las siguientes funcionalidades:
- VisualShortcutType.Navigate: cuando un usuario selecciona en una de las barras (punto de datos) y el panel de formato está abierto, el panel de formato se desplaza a la tarjeta del selector de colores y lo abre.
- VisualShortcutType.Reset: agrega un acceso directo de restablecimiento al menú contextual. Está habilitado si se cambió el color de relleno.
private getColorSelectorStyles(subSelections: CustomVisualSubSelection[]): SubSelectionStyles { const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); return { type: SubSelectionStylesType.Shape, fill: { label: 'Fill', reference: { ...colorSelectorReferences.fill, selector }, }, }; }
Cuando un usuario hace clic con el botón derecho en una barra, aparece lo siguiente:
Al cambiar el color:
Accesos directos de subsección
Para implementar los accesos directos y estilos de subSelección para directEdit:
private getDirectEditShortcuts(): VisualSubSelectionShortcuts {
return [
{
type: VisualShortcutType.Reset,
relatedResetFormattingIds: [
directEditReferences.bold,
directEditReferences.fontFamily,
directEditReferences.fontSize,
directEditReferences.italic,
directEditReferences.underline,
directEditReferences.fontColor,
directEditReferences.textProperty
]
},
{
type: VisualShortcutType.Toggle,
relatedToggledFormattingIds: [{
...directEditReferences.show,
}],
...directEditReferences.show,
disabledLabel: 'Delete',
},
{
type: VisualShortcutType.Picker,
...directEditReferences.position,
label: 'Position'
},
{
type: VisualShortcutType.Navigate,
destinationInfo: { cardUid: directEditReferences.cardUid },
label: 'Direct edit'
}
];
}
Este acceso directo agrega un elemento de menú relevante en el menú contextual y agrega las siguientes funcionalidades:
- VisualShortcutType.Reset: agrega un restablecimiento al elemento predeterminado al menú contextual, cuando una de las propiedades proporcionadas en la matriz relatedResetFormattingIds cambia.
- VisualShortcutType.Toggle: agrega una opción Eliminar al menú contextual. Al hacer clic en este, se desactiva el modificador de alternancia de la tarjeta directEdit
. - VisualShortcutType.Picker: agrega una opción en el menú contextual para elegir entre Derecha e Izquierda, ya que hemos agregado el segmento de posición en la tarjeta de formato de la directEdit.
- VisualShortcutType.Navigate: cuando el panel de formato está abierto y el usuario selecciona el elemento directEdit, el panel de formato se desplaza y abre el tarjeta directEdit.
private getDirectEditStyles(): SubSelectionStyles {
return {
type: powerbi.visuals.SubSelectionStylesType.Text,
fontFamily: {
reference: {
...directEditReferences.fontFamily
},
label: 'font family'
},
bold: {
reference: {
...directEditReferences.bold
},
label: 'bold'
},
italic: {
reference: {
...directEditReferences.italic
},
label: 'italic'
},
underline: {
reference: {
...directEditReferences.underline
},
label: 'underline'
},
fontSize: {
reference: {
...directEditReferences.fontSize
},
label: 'font size'
},
fontColor: {
reference: {
...directEditReferences.fontColor
},
label: 'font color'
},
background: {
reference: {
objectName: 'directEdit',
propertyName: 'background'
},
label: 'background'
}
}
}
Proporcionamos las propiedades pertinentes a medida que las agregamos en formatSettings.
En la imagen siguiente se muestra el aspecto de la interfaz de usuario al hacer clic con el botón derecho en el elemento directEdit:
Localización
El objeto visual debe controlar la localización y proporcionar cadenas localizadas.
Recursos de GitHub
- Todas las interfaces de formato de objeto se pueden encontrar en (vínculo que se proporcionará una vez que se publique la API) en on-object-formatting-api.d.ts
- Se recomienda usar [on object utils], que incluyen [HTMLSubSelectionHelper](link to be provided once the API is released)
- Puede encontrar un ejemplo de un objeto visual personalizado SampleBarChart que usa la versión de API 5.8.0 e implementa la compatibilidad con el formato de objeto mediante las utilidades del objeto en (vínculo que se proporcionará una vez que se libere la API).