Re-wrote to work with latest Power BI visuals SDK; added latest Vega/… (#8)
* Re-wrote to work with latest Power BI visuals SDK; added latest Vega/Vega-Lite packages and fixed typings for Vega spec. Removed the logger, as this hasn't worked in the SDK for a while and the team have yet to document a suitable replacement. * Removed old .api and logger from source as no longer needed. * Updating .gitignore We shouldn't be keeping the generated webpack stats in our source code
This commit is contained in:
Родитель
f5cd4c6c9d
Коммит
80249e4f94
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"PBI_API_VERSION": "v1.10.0",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cranPackages": {
|
||||
"type": "array",
|
||||
"description": "An array of the Cran packages required for the custom R visual script to operate",
|
||||
"items": {
|
||||
"$ref": "#/definitions/cranPackage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"cranPackage": {
|
||||
"type": "object",
|
||||
"description": "cranPackage - Defines the name and displayName of a required Cran package",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name for this Cran package"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string",
|
||||
"description": "The name for this Cran package that is shown to the user"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A url for package documentation in Cran website"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"url"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
{
|
||||
"PBI_API_VERSION": "v1.10.0",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "Version of the IVisual API"
|
||||
},
|
||||
"author": {
|
||||
"type": "object",
|
||||
"description": "Information about the author of the visual",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the visual author. This is displayed to users."
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"description": "E-mail of the visual author. This is displayed to users for support."
|
||||
}
|
||||
}
|
||||
},
|
||||
"assets": {
|
||||
"type": "object",
|
||||
"description": "Assets used by the visual",
|
||||
"properties": {
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "A 20x20 png icon used to represent the visual"
|
||||
}
|
||||
}
|
||||
},
|
||||
"externalJS": {
|
||||
"type": "array",
|
||||
"description": "An array of relative paths to 3rd party javascript libraries to load",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"stringResources": {
|
||||
"type": "array",
|
||||
"description": "An array of relative paths to string resources to load",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"style" : {
|
||||
"type": "string",
|
||||
"description": "Relative path to the stylesheet (less) for the visual"
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "string",
|
||||
"description": "Relative path to the visual capabilities json file"
|
||||
},
|
||||
"visual": {
|
||||
"type": "object",
|
||||
"description": "Details about this visual",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "What does this visual do?"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Internal visual name"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string",
|
||||
"description": "A friendly name"
|
||||
},
|
||||
"externals": {
|
||||
"type": "array",
|
||||
"description": "External files (such as JavaScript) that you would like to include"
|
||||
},
|
||||
"guid": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for the visual"
|
||||
},
|
||||
"visualClassName": {
|
||||
"type": "string",
|
||||
"description": "Class of your IVisual"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "Icon path"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Visual version"
|
||||
},
|
||||
"gitHubUrl": {
|
||||
"type": "string",
|
||||
"description": "Url to the github repository for this visual"
|
||||
},
|
||||
"supportUrl": {
|
||||
"type": "string",
|
||||
"description": "Url to the support page for this visual"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
{
|
||||
"PBI_API_VERSION": "v1.10.0",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"locale": {
|
||||
"$ref": "#/definitions/localeOptions"
|
||||
},
|
||||
"values": {
|
||||
"type": "object",
|
||||
"description": "translations for the display name keys in the capabilities",
|
||||
"additionalProperties": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"required": [ "locale" ],
|
||||
"definitions": {
|
||||
"localeOptions": {
|
||||
"description": "Specifies the locale key from a list of supported locales",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ar-SA",
|
||||
"bg-BG",
|
||||
"ca-ES",
|
||||
"cs-CZ",
|
||||
"da-DK",
|
||||
"de-DE",
|
||||
"el-GR",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"et-EE",
|
||||
"eu-ES",
|
||||
"fi-FI",
|
||||
"fr-FR",
|
||||
"gl-ES",
|
||||
"he-IL",
|
||||
"hi-IN",
|
||||
"hr-HR",
|
||||
"hu-HU",
|
||||
"id-ID",
|
||||
"it-IT",
|
||||
"ja-JP",
|
||||
"kk-KZ",
|
||||
"ko-KR",
|
||||
"lt-LT",
|
||||
"lv-LV",
|
||||
"ms-MY",
|
||||
"nb-NO",
|
||||
"nl-NL",
|
||||
"pl-PL",
|
||||
"pt-BR",
|
||||
"pt-PT",
|
||||
"ro-RO",
|
||||
"ru-RU",
|
||||
"sk-SK",
|
||||
"sl-SI",
|
||||
"sr-Cyrl-RS",
|
||||
"sr-Latn-RS",
|
||||
"sv-SE",
|
||||
"th-TH",
|
||||
"tr-TR",
|
||||
"uk-UA",
|
||||
"vi-VN",
|
||||
"zh-CN",
|
||||
"zh-TW"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,3 +2,5 @@ node_modules
|
|||
.tmp
|
||||
.vscode
|
||||
dist
|
||||
|
||||
webpack.statistics*.html
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
20
package.json
20
package.json
|
@ -6,14 +6,22 @@
|
|||
"url": "https://github.com/Microsoft/vegalite-for-powerbi.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"powerbi-visuals-utils-dataviewutils": "1.4.1",
|
||||
"vega": "^3.0.8",
|
||||
"vega-lite": "^2.0.4"
|
||||
"@babel/runtime": "7.6.0",
|
||||
"@babel/runtime-corejs2": "7.6.0",
|
||||
"core-js": "3.2.1",
|
||||
"powerbi-visuals-api": "^2.6.2",
|
||||
"powerbi-visuals-utils-dataviewutils": "2.2.1",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"vega": "^5.9.1",
|
||||
"vega-lite": "^4.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"powerbi-visuals-tools": "^1.10.0",
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "^2.6.2"
|
||||
"@types/vega": "^3.2.0",
|
||||
"powerbi-visuals-tools": "^3.1.5",
|
||||
"ts-loader": "6.1.0",
|
||||
"tslint": "^5.18.0",
|
||||
"tslint-microsoft-contrib": "^6.2.0",
|
||||
"typescript": "3.6.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "pbiviz start",
|
||||
|
|
10
pbiviz.json
10
pbiviz.json
|
@ -9,7 +9,7 @@
|
|||
"supportUrl": "https://github.com/Microsoft/vegalite-for-powerbi/issues",
|
||||
"gitHubUrl": "https://github.com/Microsoft/vegalite-for-powerbi"
|
||||
},
|
||||
"apiVersion": "1.10.0",
|
||||
"apiVersion": "2.6.0",
|
||||
"author": {
|
||||
"name": "Dominik Moritz",
|
||||
"email": "t-romor@microsoft.com"
|
||||
|
@ -17,13 +17,9 @@
|
|||
"assets": {
|
||||
"icon": "assets/icon.png"
|
||||
},
|
||||
"externalJS": [
|
||||
"node_modules/powerbi-visuals-utils-dataviewutils/lib/index.js",
|
||||
"node_modules/vega-lite/build/vega-lite.js",
|
||||
"node_modules/vega/build/vega.js"
|
||||
],
|
||||
"externalJS": [],
|
||||
"style": "style/visual.less",
|
||||
"capabilities": "capabilities.json",
|
||||
"dependencies": "dependencies.json",
|
||||
"dependencies": null,
|
||||
"stringResources": []
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
module powerbi.extensibility.visual {
|
||||
export function logExceptions() {
|
||||
return function(target: any, propertyKey: string, descriptor) {
|
||||
return {
|
||||
value: function() {
|
||||
try {
|
||||
return descriptor.value.apply(this, arguments);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
module powerbi.extensibility.visual {
|
||||
import DataViewObjectsParser = powerbi.extensibility.utils.dataview.DataViewObjectsParser;
|
||||
import { dataViewObjectsParser } from 'powerbi-visuals-utils-dataviewutils';
|
||||
import DataViewObjectsParser = dataViewObjectsParser.DataViewObjectsParser;
|
||||
|
||||
export class VisualSettings extends DataViewObjectsParser {
|
||||
public rendering = new RenderSettings();
|
||||
}
|
||||
|
||||
export class RenderSettings {
|
||||
public svg = false;
|
||||
}
|
||||
export class VisualSettings extends DataViewObjectsParser {
|
||||
public rendering = new RenderSettings();
|
||||
}
|
||||
|
||||
export class RenderSettings {
|
||||
public svg = false;
|
||||
}
|
||||
|
|
205
src/visual.ts
205
src/visual.ts
|
@ -1,117 +1,128 @@
|
|||
module powerbi.extensibility.visual {
|
||||
interface BarChartDataPoint {
|
||||
value: PrimitiveValue;
|
||||
category: string;
|
||||
"use strict";
|
||||
|
||||
import "core-js/stable";
|
||||
import "regenerator-runtime/runtime";
|
||||
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 VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject;
|
||||
import VisualUpdateType = powerbi.VisualUpdateType;
|
||||
import PrimitiveValue = powerbi.PrimitiveValue;
|
||||
import DataView = powerbi.DataView;
|
||||
import * as vega from 'vega';
|
||||
import * as vl from 'vega-lite';
|
||||
import { VisualSettings } from "./settings";
|
||||
|
||||
interface BarChartDataPoint {
|
||||
value: PrimitiveValue;
|
||||
category: string;
|
||||
}
|
||||
|
||||
function visualTransform(options: VisualUpdateOptions) {
|
||||
let dataViews = options.dataViews;
|
||||
|
||||
let dataPoints: BarChartDataPoint[] = [];
|
||||
|
||||
if (!dataViews
|
||||
|| !dataViews[0]
|
||||
|| !dataViews[0].categorical
|
||||
|| !dataViews[0].categorical.categories
|
||||
|| !dataViews[0].categorical.categories[0].source
|
||||
|| !dataViews[0].categorical.values)
|
||||
return null;
|
||||
|
||||
let categorical = dataViews[0].categorical;
|
||||
let category = categorical.categories[0];
|
||||
let dataValue = categorical.values[0];
|
||||
|
||||
let objects = dataViews[0].metadata.objects;
|
||||
|
||||
let categoryTitle = category.source.displayName;
|
||||
let valueTitle = dataValue.source.displayName;
|
||||
|
||||
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
|
||||
dataPoints.push({
|
||||
category: category.values[i] + "",
|
||||
value: dataValue.values[i]
|
||||
});
|
||||
}
|
||||
|
||||
function visualTransform(options: VisualUpdateOptions) {
|
||||
let dataViews = options.dataViews;
|
||||
return {dataPoints, categoryTitle, valueTitle};
|
||||
}
|
||||
|
||||
let dataPoints: BarChartDataPoint[] = [];
|
||||
export class BarChart implements IVisual {
|
||||
private target: HTMLElement;
|
||||
private settings: VisualSettings;
|
||||
|
||||
if (!dataViews
|
||||
|| !dataViews[0]
|
||||
|| !dataViews[0].categorical
|
||||
|| !dataViews[0].categorical.categories
|
||||
|| !dataViews[0].categorical.categories[0].source
|
||||
|| !dataViews[0].categorical.values)
|
||||
return null;
|
||||
private view: any;
|
||||
|
||||
let categorical = dataViews[0].categorical;
|
||||
let category = categorical.categories[0];
|
||||
let dataValue = categorical.values[0];
|
||||
constructor(options: VisualConstructorOptions) {
|
||||
console.log("Visual constructor", options);
|
||||
|
||||
let objects = dataViews[0].metadata.objects;
|
||||
|
||||
let categoryTitle = category.source.displayName;
|
||||
let valueTitle = dataValue.source.displayName;
|
||||
|
||||
for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
|
||||
dataPoints.push({
|
||||
category: category.values[i] + '',
|
||||
value: dataValue.values[i]
|
||||
});
|
||||
}
|
||||
|
||||
return {dataPoints, categoryTitle, valueTitle};
|
||||
this.target = options.element;
|
||||
}
|
||||
|
||||
export class BarChart implements IVisual {
|
||||
private target: HTMLElement;
|
||||
private settings: VisualSettings;
|
||||
public update(options: VisualUpdateOptions) {
|
||||
this.settings = BarChart.parseSettings(options && options.dataViews && options.dataViews[0]);
|
||||
console.log("Visual update", options);
|
||||
|
||||
private view: any;
|
||||
|
||||
constructor(options: VisualConstructorOptions) {
|
||||
console.log('Visual constructor', options);
|
||||
|
||||
this.target = options.element;
|
||||
if (this.view && (options.type & VisualUpdateType.Resize || options.type & VisualUpdateType.ResizeEnd)) {
|
||||
this.view.width(options.viewport.width).height(options.viewport.height).run();
|
||||
return;
|
||||
}
|
||||
|
||||
@logExceptions()
|
||||
public update(options: VisualUpdateOptions) {
|
||||
this.settings = BarChart.parseSettings(options && options.dataViews && options.dataViews[0]);
|
||||
console.log('Visual update', options);
|
||||
const r = visualTransform(options);
|
||||
|
||||
if (this.view && (options.type & VisualUpdateType.Resize || options.type & VisualUpdateType.ResizeEnd)) {
|
||||
this.view.width(options.viewport.width).height(options.viewport.height).run();
|
||||
return;
|
||||
if (!r) {
|
||||
this.target.innerHTML = "Need category and measure";
|
||||
this.view = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const {dataPoints, categoryTitle, valueTitle} = r;
|
||||
const spec: vl.TopLevelSpec = {
|
||||
$schema: "https://vega.github.io/schema/vega-lite/v4.json",
|
||||
width: options.viewport.width,
|
||||
height: options.viewport.height,
|
||||
padding: 0,
|
||||
autosize: {
|
||||
type: "fit",
|
||||
contains: "content"
|
||||
},
|
||||
data: {
|
||||
values: dataPoints
|
||||
},
|
||||
mark: "bar",
|
||||
encoding: {
|
||||
x: {field: "category", type: "ordinal", axis: {title: categoryTitle}},
|
||||
y: {field: "value", type: "quantitative", axis: {title: valueTitle}}
|
||||
}
|
||||
};
|
||||
|
||||
const r = visualTransform(options);
|
||||
const vgSpec = vl.compile(spec).spec;
|
||||
|
||||
if (!r) {
|
||||
this.target.innerHTML = "Need category and measure";
|
||||
this.view = null;
|
||||
return;
|
||||
}
|
||||
const runtime = vega.parse(vgSpec);
|
||||
|
||||
const {dataPoints, categoryTitle, valueTitle} = r;
|
||||
this.view = new vega.View(runtime)
|
||||
.logLevel(vega.Warn)
|
||||
.initialize(this.target)
|
||||
.renderer(this.settings.rendering.svg ? "svg" : "canvas")
|
||||
.run();
|
||||
}
|
||||
|
||||
// this should be type TopLevelExtendedSpec
|
||||
const spec = {
|
||||
$schema: "https://vega.github.io/schema/vega-lite/v2.json",
|
||||
width: options.viewport.width,
|
||||
height: options.viewport.height,
|
||||
padding: 0,
|
||||
autosize: {
|
||||
type: "fit",
|
||||
contains: "content"
|
||||
},
|
||||
data: {
|
||||
values: dataPoints
|
||||
},
|
||||
mark: "bar",
|
||||
encoding: {
|
||||
x: {field: "category", type: "ordinal", axis: {title: categoryTitle}},
|
||||
y: {field: "value", type: "quantitative", axis: {title: valueTitle}}
|
||||
}
|
||||
};
|
||||
private static parseSettings(dataView: DataView): VisualSettings {
|
||||
return VisualSettings.parse(dataView) as VisualSettings;
|
||||
}
|
||||
|
||||
const vl = (window as any).vl;
|
||||
const vega = (window as any).vega;
|
||||
|
||||
const vgSpec = vl.compile(spec).spec;
|
||||
|
||||
const runtime = vega.parse(vgSpec);
|
||||
|
||||
this.view = new vega.View(runtime)
|
||||
.logLevel(vega.Warn)
|
||||
.initialize(this.target)
|
||||
.renderer(this.settings.rendering.svg ? "svg" : "canvas")
|
||||
.run();
|
||||
}
|
||||
|
||||
private static parseSettings(dataView: DataView): VisualSettings {
|
||||
return VisualSettings.parse(dataView) as VisualSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function gets called for each of the objects defined in the capabilities files and allows you to select which of the
|
||||
* objects and properties you want to expose to the users in the property pane.
|
||||
*/
|
||||
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
|
||||
return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
|
||||
}
|
||||
/**
|
||||
* This function gets called for each of the objects defined in the capabilities files and allows you to select which of the
|
||||
* objects and properties you want to expose to the users in the property pane.
|
||||
*/
|
||||
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
|
||||
return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
|
||||
}
|
||||
}
|
|
@ -1,17 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowJs": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES5",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"out": "./.tmp/build/visual.js"
|
||||
"outDir": "./.tmp/build/",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"lib": [
|
||||
"es2015",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
".api/v1.10.0/PowerBI-visuals.d.ts",
|
||||
"node_modules/powerbi-visuals-utils-dataviewutils/lib/index.d.ts",
|
||||
"src/settings.ts",
|
||||
"src/logger.ts",
|
||||
"src/visual.ts"
|
||||
"./src/visual.ts"
|
||||
]
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче