Визуальный элемент Power BI не будет отображать или отображать мои добавленные параметры форматирования

Я пытаюсь работать над этим визуальным элементом для Power BI, но сталкиваюсь со странной проблемой. Предполагается, что это столбчатая диаграмма (будет преобразована в линию), которая поддерживает меру по осям X и Y. Когда я пытаюсь построить график с моими данными, я получаю пустой визуал без ошибок. Мои параметры форматирования, которые я добавил (например, всплывающие подсказки или параметры переключения), даже не отображаются на панели параметров визуального форматирования. Я напортачил, и я не могу заставить это работать или действительно изменить, независимо от того, что я делаю, за исключением того, что я захожу и бросаю случайные символы в свой код, чтобы нарушить синтаксис. Я даже пробовал переходить к более старым визуальным файлам, с которыми возился в прошлом, и удостоверился, что не делаю ничего плохого, например, неправильно использую модули или неправильно размещаю их. Я даже повторно импортировал все свои модули, проверил свои переменные, проверил опечатки и т. Д.Кажется, я не могу заставить эту штуку работать. Я даже попытался удалить часть своих возможностей, которая позволяет наносить меры на ось, чтобы увидеть, будет ли она построена со столбцами нормальных значений. К сожалению, безрезультатно. Может быть, у меня застой в глазах и я упустил что-то очевидное, или это что-то более сложное.

Буду очень признателен за любую помощь. Даже если это что-то не связано с проблемой.


"use strict";
import "@babel/polyfill";
import "./../style/visual.less";
import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions;
import VisualObjectInstance = powerbi.VisualObjectInstance;
import DataView = powerbi.DataView;
import VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject;
import * as d3 from "d3";
import { VisualSettings } from "./settings";
import ISelectionManager = powerbi.extensibility.ISelectionManager;
import { ChartDataPoint, ChartViewModel } from "./viewmodels/model";
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import * as DataViewObject from 'powerbi-visuals-utils-dataviewutils';

interface DataPoints {
    duration: number;
    value: number;
    details: number;
    wells: string;
    colour: string;
    identity: powerbi.visuals.ISelectionId;
    highlighted: boolean;
};
interface ViewModel {
    dataPoints: DataPoints[];
    maxValue: number;
    highlights: boolean;
};

export class Visual implements IVisual {

    private host: IVisualHost;
    private svg: d3.Selection<SVGElement>;
    private barGroup: d3.Selection<SVGElement>;
    private viewModel: ViewModel;
    private locale: string;
    private selectionManager: ISelectionManager;
    private xAxisGroup: d3.Selection<SVGElement>;
    private yAxisGroup: d3.Selection<SVGElement>;
    private settings = {
        axis: {
            x: {
                padding: {
                    default: 50,
                    value: 50
                },
                show: {
                    default: true,
                    value: true
                }
            },
            y: {
                padding: {
                    default: 50,
                    value: 50
                }
            },
            border: {
                top: {
                    default: 10,
                    value: 10
                }
            }
        }
    }

    constructor(options: VisualConstructorOptions) {
        this.host = options.host;
        this.svg = d3.select(options.element)
            .append(".svg")
            .classed("Visual", true);
        this.barGroup = this.svg.append("g")
            .classed("bar-group", true);         //this was chart
        this.xAxisGroup = this.svg.append("g")
            .classed("x-axis", true);
        this.selectionManager = this.host.createSelectionManager();
        this.yAxisGroup = this.svg.append("g")
            .classed("y-axis", true);



    }

    //This contains the 'canvas', its scaling, and how it can or cannot interact
    public update(options: VisualUpdateOptions) {
        //this.updateSettings(options);
        let viewModel = this.getViewModel(options);
        let width = options.viewport.width;
        let height = options.viewport.height;
        let xAxisPadding = this.settings.axis.x.show.value ? this.settings.axis.x.padding.value : 0;
        // let yAxisPadding = this.settings.axis.y.show.value ? this.settings.axis.y.padding.value : 0;
        this.svg.attr({
            width: width,
            height: height
        });

        let yScale = d3.scale.linear()
            .domain([0, this.viewModel.maxValue])
            .range([height - xAxisPadding, 0 + this.settings.axis.border.top.value]);


        let xScale = d3.scale.linear()
            .domain(viewModel.dataPoints.map(d => d.duration))
           // .rangeRoundBands([yAxisPadding, width], this.xPadding);
        let xAxis = d3.svg.axis()  //come back to this later if it causes issues. https://www.youtube.com/watch?v=zLNfXxDsa-s&list=PL6z9i4iVbl8C2mtjFlH3ECb3q00eFDLAG&index=14 3:40 in
            .scale(xScale)
            .orient("bottom")
            .tickSize(.5);
        let yAxis = d3.svg.axis()
            .scale(yScale)
            .orient("left")
            .tickSize(.5);

        this.xAxisGroup
            .call(xAxis)
            .attr({
                transform: "translate(0 " + (height - xAxisPadding) + ")"
            })
            .style({
                fill: "#777777"
            })
            .selectAll("text")
            .attr({
                "text-anchor": "end",
                "font-size": "x-small"

            });
        this.yAxisGroup
            .call(yAxis)
            .attr({
                transform: "translate(" + this.settings.axis.y.padding + ",0)"
            })
            .style({
                fill: "#777777"
            })
            .selectAll("text")
            .style({
                "text-anchor": "end",
                "font-size": "x-small"
            });


        let bars = this.barGroup
            .selectAll(".bar")            //keep an eye on this. was '.lines'
            .data(viewModel.dataPoints);
        bars.enter()
            .append("svg")
            .classed("bar", true);    //this was chart
        bars
            .attr({
                //width: xScale.range(),
                height: d => height = yScale(d.value) - xAxisPadding,
                x: d => xScale(d.duration),

            })
            .style({
                fill: d => d.colour,
                "fill-opacity": d => viewModel.highlights ? d.highlighted ? 1.0 : 0.5 : 1.0
            })
            .on("click", (d) => {
                this.selectionManager
                    .select(d.identity, true)
                    .then(ids => {
                        bars.style({
                            "fill-opacity": ids.length > 0 ?
                                d => ids.indexOf(d.identity) >= 0 ? 1.0 : 0.5
                                : 1.0


                        });

                    })

            });
        bars.exit()
            .remove();




    }
    /* private updateSettings(options: VisualUpdateOptions) {
         this.settings.axis.x.show.value = DataViewObjects.getValue
             (options.dataViews[0].metadata.objects, {
                 objectName: "xAxis",
                 propertyName: "show"
         })
     }*/

    private getViewModel(options: VisualUpdateOptions): ViewModel {
        let dv = options.dataViews;
        let viewModel: ViewModel = {
            dataPoints: [],
            maxValue: 0,
            highlights: false

        };

        /* if (!dv
             || !dv[0]
             || !dv[0].categorical
             || !dv[0].categorical.categories
             || !dv[0].categorical.categories[0].source
             || !dv[0].categorical.values)
             return viewModel;*/

        let view = dv[0].categorical;

        let categories = view.categories[0];
        let values = view.values[0];
        let highlights = values.highlights;
        for (let i = 0, len = Math.max(categories.values.length, values.values.length); i < len; i++) {
            viewModel.dataPoints.push({
                duration: <number>values.values[i],
                value: <number>values.values[i],
                details: <number>categories.values[i],
                wells: <string>categories.values[i],
                colour: this.host.colorPalette.getColor(<string>categories.values[i]).value,
                identity: this.host.createSelectionIdBuilder()
                    .withCategory(categories, i)
                    .createSelectionId(),
                highlighted: highlights ? highlights[i] ? true : false : false

            });
        }

        viewModel.maxValue = d3.max(viewModel.dataPoints, d => d.value);
        viewModel.highlights = viewModel.dataPoints.filter(d => d.highlighted).length > 0;
        return viewModel;

    }



    public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
        let propertyGroupName = options.objectName;
        let properties: VisualObjectInstance[] = [];
        switch (propertyGroupName) {
            case "xAxisGroup":
                properties.push({
                    objectName: propertyGroupName,
                    properties: {
                        show: this.settings.axis.x.show.value
                    },
                    selector: null
                });
                break;

        };
        return properties
    }



}

Для всех, кому интересно, моя конечная цель (в конечном итоге) - получить линейный график, который может поддерживать меру (вычисляемый столбец) по любой оси. Например, даты для оси X очень распространены. Я также хотел бы иметь возможность использовать меру, которая может принимать диапазон дат, например 9/5/2019–9/10/2019, и преобразовывать его в продолжительность. Ожидаемый результат - 1-5.

Измерение оси Y может делать что-то вроде... например, отображать все значения, которые соответствуют определенным параметрам.

{

  "supportsHighlight": true,
  "dataRoles": [
    {
      "displayName": "Y Axis",
      "name": "values",
      "kind": "Grouping"
    },
    {
      "displayName": "Details",
      "name": "details",
      "kind": "Grouping"
    },
    {
      "displayName": "Duration",
      "name": "duration",
      "kind": "Measure"
    }

  ],
  "objects": {

    "xAxis": {
      "displayName": "X Axis",
      "properties": {
        "show": {
          "displayName": "Show X Axis",
          "type": {
            "bool": true
          }

        }
      }
    },
    "dataPoint": {
      "displayName": "Data colors",
      "properties": {
        "defaultColor": {
          "displayName": "Default color",
          "type": {
            "fill": {
              "solid": {
                "color": true
              }
            }
          }
        },
        "showAllDataPoints": {
          "displayName": "Show all",
          "type": {
            "bool": true
          }
        },
        "fill": {
          "displayName": "Fill",
          "type": {
            "fill": {
              "solid": {
                "color": true
              }
            }
          }
        },
        "fillRule": {
          "displayName": "Color saturation",
          "type": {
            "fill": {}
          }
        },
        "fontSize": {
          "displayName": "Text Size",
          "type": {
            "formatting": {
              "fontSize": true
            }
          }
        }
      }
    }
  },
  "dataViewMappings": [
    {
      "categorical": {
        "categories": {
          "for": {
            "in": "duration"
          },
          "dataReductionAlgorithm": {
            "top": {
              "count": 450
            }
          }
        },
        "values": {
          "group": {
            "by": "values",
            "select": [
              {
                "bind": {
                  "to": "details"
                }
              }
            ]
          },
          "dataReductionAlgorithm": {
            "top": {
              "count": 450
            }
          }
        }
      }
    }

  ]
}

1 ответ

Судя по комментариям, часть задачи состоит в том, чтобы получить ось Y, на которой наименьшее число отображается вверху, а наибольшее число - внизу. Это можно сделать с помощью настраиваемой строки формата для меры. Вот быстрый и грязный мокап с использованием стандартной линейной диаграммы.

Если вы установите для формата меры значение "Пользовательский" и используете строку формата без символа "-" для отрицательного значения, например "0;0;0", визуальный элемент не будет отображать "-" на оси y. Это приводит к желаемому эффекту.

Обратите внимание, что эта мера -1 * SUM ( 'Table'[Column1] ). Этот столбец содержит только положительные значения.

Другие вопросы по тегам