API de formato en el objeto (versión preliminar)
El formato en el objeto permite a los usuarios modificar rápida y fácilmente el formato de los objetos visuales seleccionando directamente los elementos que quieren 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 el objeto 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 subseleccionable.
Nota:
- Los objetos visuales que admiten el formato en el objeto deben implementar la API getFormattingModel que está disponible en la versión 5.1 de la API.
- Si usa powerbi-visuals-utils-formattingmodel, use la versión 6.0.0 como mínimo.
Creación de una experiencia en el objeto
Use el servicio de subselección cuando el usuario seleccione un elemento subseleccionable para enviar a Power BI la subselección. Proporcione los estilos y accesos directos de subselección mediante la API de 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 el formato onObject
cuando está 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 el elemento subSelection subseleccionado actualmente como CustomVisualSubSelection
.
Implementación de la API de formato en el objeto
Archivo de funcionalidades
En el archivo capabilities.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
Cada objeto visual es necesario para implementar un método getSubSelectionStyles
, al que se llama cuando se subselecciona un elemento subseleccionable. El método getSubSelectionStyles
se proporciona con los elementos subseleccionados actuales como una matriz CustomVisualSubSelection
y se espera que devuelva un objeto SubSelectionStyles
o undefined
.
Hay tres categorías de estilos de subselección que cubren la mayoría de los escenarios:
- Texto
- Texto numérico
- Forma
Cada objeto SubSelectionStyles
proporciona una experiencia diferente al usuario para modificar el estilo de un elemento.
getSubSelectionShortcuts
Para proporcionar más opciones al usuario, el objeto visual debe implementar el método getSubSelectionShortcuts
. Este método devuelve VisualSubSelectionShortcuts
o undefined
. Además, si se proporcionan elementos SubSelectionShortcuts
, también se debe proporcionar VisualNavigateSubSelectionShortcut
para que cuando un usuario subseleccione un elemento y el panel de formato se abra, el panel se desplace automáticamente a la tarjeta adecuada.
Hay varios accesos directos de subselección para modificar el estado del objeto visual. Cada uno define un elemento de menú en el menú contextual con la etiqueta adecuada.
Menú de desambiguación de la subselección: el menú de desambiguación En el objeto 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ú de desambiguación presente más subselecciones, el objeto visual debe proporcionar todas las subselecciones mediante el método getSubSelectables
.
getSubSelectables
Para proporcionar las subselecciones al menú de desambiguación, el objeto visual debe implementar el método getSubSelectables
. Este método proporciona un argumento filterType
opcional de tipo SubSelectionStylesType
y devuelve una matriz de CustomVisualSubSelection
o undefined
.
Si se usa HTMLSubSelectionHelper
para crear una subselección, el método HTMLSubSelectionHelper.getSubSelectables() se puede usar para recopilar elementos subseleccionables del DOM.
Edición directa de texto en la subselección: con el formato en el objeto, puede hacer doble clic en el texto de un elemento subseleccionable para editarlo directamente.
Para proporcionar la funcionalidad de edición directa, debe proporcionar un elemento RectangleSubSelectionOutline
con la propiedad cVDirectEdit adecuada rellenada con un objeto SubSelectableDirectEdit. El contorno se puede proporcionar como un contorno personalizado, o bien si usa HTMLSubSelectionHelper
, puede usar el atributo SubSelectableDirectEdit
. (Consulte los atributos proporcionados por HTMLSubSelectionHelper)
Todavía no se admite la edición directa para un punto de datos específico (mediante selectores).
Interfaz FormattingId
La siguiente interfaz se usa para hacer referencia a los accesos directos 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 archivo capabilities.json.
- propertyName: el nombre de la propiedad de un objeto tal como se declara en el archivo capabilities.json.
- selector: si el punto de datos tiene un valor selectionId, use selectionId.getSelector(), este selector debe ser el mismo que se proporciona para el sector de modelo de formato.
Ejemplos
En este ejemplo, creamos un objeto visual personalizado que tiene dos objetos: colorSelector
y directEdit
. Usamos HTMLSubSelectionHelper
desde las utilidades de onobjectFormatting
para controlar la mayor parte del trabajo de subSelection.
Para más información, consulte las utilidades en el objeto.
En primer lugar, creamos tarjetas para el panel de formato y proporcionamos accesos directos (subSelectionShortcuts) y estilos para cada elemento subseleccionable.
Definición de los objetos
Defina los objetos y declare que el objeto visual admite el formato OnObject en el archivo 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,
Creación de las tarjetas de formato
Cree sus tarjetas de formato mediante las utilidades formattingModel.
Configuración de la tarjeta del selector de color
class ColorSelectorCardSettings extends Card {
name: string = "colorSelector";
displayName: string = "Data Colors";
slices = [];
}
Agregue un método a formattingSetting para que podamos rellenar los sectores 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 del 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 del asistente de subselección
Agregue los atributos HTMLSubSelectionHelper
a nuestros objetos. Para ver qué atributos proporciona HTMLSubSelectionHelper, compruebe la documentación sobre las utilidades en el 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)
HTMLSubSelectionHelper
usa el atributoSubSelectableDirectEditAttr
para proporcionar la referencia directEdit del contorno 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 elemento cardUid
que proporcione debe ser el mismo que el proporcionado para la API getFormattingModel. Por ejemplo, si usa powerbi-visuals-utils-formattingmodel, proporcione 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, proporciónelo como el elemento Visual-cardUid que 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 de los nombres de los 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'
}
};
Implementar API
Ahora vamos a implementar las API get para el formato onObject y a 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 accesos directos de getSubSelection y el estilo 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 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 color y la 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 subselección
Para implementar los accesos directos y los estilos de subSelection 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ú pertinente en el menú contextual y agrega las siguientes funcionalidades:
- VisualShortcutType.Reset: agrega un restablecimiento al elemento predeterminado en el menú contextual cuando cambia una de las propiedades proporcionadas en la matriz relatedResetFormattingIds.
- VisualShortcutType.Toggle: agrega una opción Eliminar en el menú contextual. Cuando se hace clic, el modificador de alternancia de la tarjeta directEdit se desactiva.
- VisualShortcutType.Picker: agrega una opción en el menú contextual para elegir entre Derecha e Izquierda, ya que hemos agregado el sector de posición en la tarjeta de formato para 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 la 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 se agregan en formattingSettings.
En la siguiente imagen 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 (el vínculo se proporcionará una vez que se publique la API) en on-object-formatting-api.d.ts.
- Se recomienda usar las [utilidades en el objecto], que incluyen [HTMLSubSelectionHelper](el vínculo se proporcionará una vez que se publique la API).
- Puede encontrar un ejemplo de un objeto visual personalizado SampleBarChart que usa la versión 5.8.0 de la API e implementa la compatibilidad con el formato en el objeto mediante las utilidades en el objeto en (el vínculo se proporcionará una vez que se publique la API).