Filter testing now, update the dropDown with d3

This commit is contained in:
沐见南 2020-04-27 23:44:05 +08:00
parent 6d67695096
commit ab2af8e102
11 changed files with 184 additions and 69 deletions

View File

@ -44,6 +44,24 @@
} }
], ],
"objects": { "objects": {
"general": {
"displayName": "General",
"displayNameKey": "formattingGeneral",
"properties": {
"filter": {
"type": {
"filter": true
}
},
"selfFilter": {
"type": {
"filter": {
"selfFilter": false
}
}
}
}
},
"dataPoint": { "dataPoint": {
"displayName": "Data colors", "displayName": "Data colors",
"properties": { "properties": {

5
package-lock.json generated
View File

@ -881,6 +881,11 @@
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true "dev": true
}, },
"powerbi-models": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/powerbi-models/-/powerbi-models-1.3.3.tgz",
"integrity": "sha512-F4O92yCpJ6thAlEOoG77cTSrQHlMrS70XxGbaCrlShNpVzVU5gyUdua1LUURZmERpoRjKPFMvQtAknkz4B7lAA=="
},
"powerbi-visuals-api": { "powerbi-visuals-api": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-2.6.2.tgz", "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-2.6.2.tgz",

View File

@ -10,10 +10,11 @@
"@babel/runtime": "7.6.0", "@babel/runtime": "7.6.0",
"@babel/runtime-corejs2": "7.6.0", "@babel/runtime-corejs2": "7.6.0",
"@types/d3": "5.7.2", "@types/d3": "5.7.2",
"core-js": "3.2.1",
"d3": "5.12.0", "d3": "5.12.0",
"powerbi-visuals-utils-dataviewutils": "2.2.1", "powerbi-models": "^1.3.3",
"powerbi-visuals-api": "~2.6.1", "powerbi-visuals-api": "~2.6.1",
"core-js": "3.2.1" "powerbi-visuals-utils-dataviewutils": "2.2.1"
}, },
"devDependencies": { "devDependencies": {
"ts-loader": "6.1.0", "ts-loader": "6.1.0",

View File

@ -1,23 +1,39 @@
"Use strict"; "Use strict";
import powerbi from "powerbi-visuals-api"; import powerbi from "powerbi-visuals-api";
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import DataView = powerbi.DataView; import DataView = powerbi.DataView;
import * as visualInterfaces from "../visual/visualInterfaces"; import * as visualInterfaces from "../visual/visualInterfaces";
import * as d3 from "d3"; import * as d3 from "d3";
import { IFilterManager } from "../visual/visualInterfaces"; import { IFilterManager } from "../visual/visualInterfaces";
export default class FilterManager implements IFilterManager{ import * as models from 'powerbi-models';
applyFilter(): void { import { select, json } from "d3";
throw new Error("Method not implemented.");
}
setJsonFilter(field: number | Text, select: number | Text): void;
setJsonFilter(field: number, start: number, end: number): void;
setJsonFilter(field: any, start: any, end?: any) {
throw new Error("Method not implemented.");
}
setJsonFitler(filter: Date, select: Date): void {
throw new Error("Method not implemented.");
}
applyJsonFilter(filter: powerbi.IFilter | powerbi.IFilter[], objectName: string, propertyName: string, action: powerbi.FilterAction): void {
export class FilterManager implements IFilterManager{
private target: models.IFilterColumnTarget={table:'',column:''};
private host:IVisualHost;
constructor(host:IVisualHost){
this.host=host;
}
public update(field:powerbi.DataViewCategoryColumn):void{
let queryName:string=field.source.queryName;
let splitPosition:number=queryName.indexOf('.');
this.target.table=queryName.substring(0,splitPosition); // table
this.target.column=queryName.substring(splitPosition+1,queryName.length); // column
console.debug("queryName:",queryName);
console.debug("queryName.length:",queryName.length);
console.debug("filterManager update end, now filter:",this.target);
}
public filterStringField(selection:string[]):void{
console.debug("filterStringField start");
let jsonFilter:models.IBasicFilter={
"$schema": "http://powerbi.com/product/schema#basic",
"target": this.target,
"filterType": models.FilterType.Basic,
"operator":"In",
"values": selection
}
console.debug("jsonFilter:",jsonFilter);
this.host.applyJsonFilter(jsonFilter?jsonFilter:null,"general","filter",powerbi.FilterAction.merge);
console.debug("filterStringField end");
} }
} }

View File

@ -1,4 +1,4 @@
export {default as filterManager} from "./filterManager"; export {FilterManager} from "./filterManager";
export {default as layoutManager} from "./layoutManager"; export {LayoutManager} from "./layoutManager";
export {default as selectorManager} from "./selectorManager"; export {SelectorManager} from "./selectorManager";
export {default as managerFactory} from "./managerFactory"; export {ManagerFactory} from "./managerFactory";

View File

@ -5,12 +5,12 @@ import * as visualInterfaces from "../visual/visualInterfaces";
import * as d3 from "d3"; import * as d3 from "d3";
import { ILayoutManager } from "../visual/visualInterfaces"; import { ILayoutManager } from "../visual/visualInterfaces";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>; type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
export default class LayoutManager implements ILayoutManager{ export class LayoutManager implements ILayoutManager{
layout:Selection<HTMLElement>; layout:Selection<HTMLElement>;
constructor(layout:Selection<HTMLElement>){ // constructor(layout:Selection<HTMLElement>){
this.layout=layout; // this.layout=layout;
} // }
update(dataView:DataView):void{ update(dataView:DataView,width:number,height:number):void{
//this.layout.style("width",width+"px").style("height",height+"px");
} }
} }

View File

@ -3,14 +3,14 @@ import * as visualInterfaces from "../visual/visualInterfaces";
import * as d3 from "d3"; import * as d3 from "d3";
import powerbi from "powerbi-visuals-api"; import powerbi from "powerbi-visuals-api";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>; type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
export default class ManagerFactory{ export class ManagerFactory{
public static CreateLayoutManager(classLayoutManager:visualInterfaces.ILayoutManagerConstructor,container:Selection<HTMLElement>):visualInterfaces.ILayoutManager{ public static CreateLayoutManager(classLayoutManager:visualInterfaces.ILayoutManagerConstructor,container:Selection<HTMLElement>):visualInterfaces.ILayoutManager{
return new classLayoutManager(container); return new classLayoutManager(container);
} }
public static CreateSelectorManager(classSelectorManager:visualInterfaces.ISelectorManagerConstructor,container:Selection<HTMLElement>):visualInterfaces.ISelectorManager{ public static CreateSelectorManager(classSelectorManager:visualInterfaces.ISelectorManagerConstructor,container:Selection<HTMLElement>,filterManager:visualInterfaces.IFilterManager):visualInterfaces.ISelectorManager{
return new classSelectorManager(container); return new classSelectorManager(container,filterManager);
} }
public static CreateFilterManager(classSelectorManager:visualInterfaces.IFilterManagerConstructor,host:powerbi.extensibility.IVisualHost):visualInterfaces.IFilterManager{ public static CreateFilterManager(classSelectorManager:visualInterfaces.IFilterManagerConstructor,host:powerbi.extensibility.visual.IVisualHost):visualInterfaces.IFilterManager{
return new classSelectorManager(host); return new classSelectorManager(host);
} }
} }

View File

@ -1,35 +1,57 @@
"Use strict"; "Use strict";
import powerbi from "powerbi-visuals-api"; import powerbi from "powerbi-visuals-api";
import {ISelectorManager} from "../visual/visualInterfaces"; import {ISelectorManager,ISelectorManagerConstructor, IFilterManager} from "../visual/visualInterfaces";
import * as d3 from "d3"; import * as d3 from "d3";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>; type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
/*
export default class SelectorManager implements ISelectorManager{
*/
export class SelectorManager implements ISelectorManager{
public selectorContainer : Selection<HTMLElement>; public selectorContainer : Selection<HTMLElement>;
private selector; private selector:ISelector;
public filterManager:IFilterManager;
constructor(selectorContainer:Selection<HTMLElement>){ private categories: powerbi.DataViewCategoryColumn;
private defaultSelect: powerbi.DataViewValueColumn;
private defaultStart: powerbi.DataViewValueColumn;
private defaultEnd: powerbi.DataViewValueColumn;
constructor(selectorContainer:Selection<HTMLElement>,filterManager:IFilterManager){
console.debug("selectorManager constructor start");
this.selectorContainer=selectorContainer; this.selectorContainer=selectorContainer;
this.filterManager=filterManager;
} }
public switchSelector<T extends ISelector>(c:new ()=>T){ public switchSelector<T extends ISelector>(classSelector:new ()=>T){
if(typeof(this.selector)!=typeof(c)){ let newSelector=new classSelector();
console.debug(typeof(this.selector));
console.debug(typeof(c));
}
let newSelector=new c();
this.selector?.dispose(); this.selector?.dispose();
this.selector=newSelector; this.selector=newSelector;
} }
updateView(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn){ updateData(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn){
if(!this.selector){ if(!this.selector){
let fieldType=categories.source.type;
if(fieldType.text){
this.selector=new DropDownSelector(this); this.selector=new DropDownSelector(this);
}else if(fieldType.numeric){
this.selector=new DropDownSelector(this);
}else if(fieldType.dateTime){
this.selector=new CalendarSelector(this);
}else{
throw "only receive text/num/datetime field";
} }
}
this.selector.update(categories, defaultSelect, defaultStart, defaultEnd); this.selector.update(categories, defaultSelect, defaultStart, defaultEnd);
}; };
public filterStringField(selection:string[]){
};
} }
interface ISelector{ interface ISelector{
update(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn); update(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn);
dispose():void;
} }
abstract class Selector implements ISelector{ abstract class Selector implements ISelector{
@ -54,8 +76,32 @@ class DropDownSelector extends Selector{
} }
public update(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn) { public update(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn) {
console.debug('dropDownViewManager','update start'); console.debug('dropDownViewManager','update start');
this.view.selectAll("option").remove(); let appending=this.view.selectAll("option").data(categories.values);
this.view.selectAll("option").data(categories.values).enter().append("option").text(function(d){return d.toString();}); appending.enter().append("option").text(function(d){return d.toString();});
appending.exit().remove();
console.debug("appending:",appending);
let filterManager:IFilterManager=this.manager.filterManager;
(<Selection<HTMLSelectElement>>this.view).on("input change",function(){
console.debug('DropDownSelector:',"input change");
console.debug('this',this);
console.debug('filterManager:',filterManager);
let selection:string[]=[];
for(let i=0;i<this.selectedOptions.length;i++){
let option=this.selectedOptions.item(i);
if(option.selected){
console.debug("option selected",option);
console.debug('option.text:',option.text);
selection.push(option.text);
}
}
if(selection.length==0){
}else{
console.debug("selection.length",selection.length);
filterManager.filterStringField(selection);
}
console.debug("this",this.selectedOptions);
});
console.debug('dropDownViewManager','update end'); console.debug('dropDownViewManager','update end');
} }
} }

View File

@ -37,31 +37,47 @@ import DataView = powerbi.DataView;
import VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject; import VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject;
import IVisualEventService = powerbi.extensibility.IVisualEventService; import IVisualEventService = powerbi.extensibility.IVisualEventService;
import * as visualInterfaces from "./visualInterfaces"; import * as visualInterfaces from "./visualInterfaces";
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import { VisualSettings } from "../settings/visualSettings"; import { VisualSettings } from "../settings/visualSettings";
import {filterManager,managerFactory,selectorManager,layoutManager} from "../managers"; import {FilterManager,ManagerFactory,SelectorManager,LayoutManager} from "../managers";
import * as d3 from "d3"; import * as d3 from "d3";
import { getObject } from "powerbi-visuals-utils-dataviewutils/lib/dataViewObjects"; import { getObject } from "powerbi-visuals-utils-dataviewutils/lib/dataViewObjects";
import { getMeasureIndexOfRole } from "powerbi-visuals-utils-dataviewutils/lib/dataRoleHelper"; import { getMeasureIndexOfRole } from "powerbi-visuals-utils-dataviewutils/lib/dataRoleHelper";
import { selector } from "d3"; import { selector } from "d3";
export class Visual implements IVisual { export class Visual implements IVisual {
/*
SelectorManager: a custom manager, used to manage dropDownSelector, listSelector, calendarSelector, and so on
SelectionManager: powerbi.extensibility
*/
private events: IVisualEventService; private events: IVisualEventService;
private settings: VisualSettings; private settings: VisualSettings;
private layoutManager: visualInterfaces.ILayoutManager; private layoutManager: visualInterfaces.ILayoutManager;
private selectorManager: visualInterfaces.ISelectorManager; private selectorManager: visualInterfaces.ISelectorManager;
private view:SVGElement; private view:SVGElement;
private filterManager:visualInterfaces.IFilterManager; private filterManager:visualInterfaces.IFilterManager;
private selectionManager:powerbi.extensibility.ISelectionManager;
constructor(options: VisualConstructorOptions) { constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options); console.debug('Visual constructor', options);
this.events = options.host.eventService; this.events = options.host.eventService;
if (document) { if (document) {
this.selectionManager =options.host.createSelectionManager();
let container=d3.select(options.element).append("div").classed("container",true); let container=d3.select(options.element).append("div").classed("container",true);
d3.select(options.element).on('contextmenu', () => {
const mouseEvent: MouseEvent = <MouseEvent>d3.event;
//const eventTarget: EventTarget = mouseEvent.target;
//let dataPoint = d3.select(eventTarget).datum();
this.selectionManager.showContextMenu({}, {
x: mouseEvent.clientX,
y: mouseEvent.clientY
});
mouseEvent.preventDefault();
});
let headerContainer=container.append("div").classed("header-container",true); let headerContainer=container.append("div").classed("header-container",true);
let selectorContainer=container.append("div").classed("selector-container",true); let selectorContainer=container.append("div").classed("selector-container",true);
this.layoutManager=managerFactory.CreateLayoutManager(layoutManager,container); this.layoutManager=ManagerFactory.CreateLayoutManager(LayoutManager,container);
this.selectorManager=managerFactory.CreateSelectorManager(selectorManager,selectorContainer); this.filterManager=ManagerFactory.CreateFilterManager(FilterManager,options.host);
this.filterManager=managerFactory.CreateFilterManager(filterManager,options.host); this.selectorManager=ManagerFactory.CreateSelectorManager(SelectorManager,selectorContainer,this.filterManager);
} }
console.debug('end constructor'); console.debug('end constructor');
} }
@ -69,15 +85,16 @@ export class Visual implements IVisual {
public update(options: VisualUpdateOptions) { public update(options: VisualUpdateOptions) {
console.debug('visual update start'); console.debug('visual update start');
this.events.renderingStarted(options); this.events.renderingStarted(options);
this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]); this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]);
let dataView=options.dataViews[0]; let dataView=options.dataViews[0];
let field=dataView.categorical.categories[0]; let field=dataView.categorical.categories[0];
let values=dataView.categorical.values; let messures=dataView.categorical.values;
let defaultSelect:powerbi.DataViewValueColumn; let defaultSelect:powerbi.DataViewValueColumn;
let defaultStart:powerbi.DataViewValueColumn; let defaultStart:powerbi.DataViewValueColumn;
let defaultEnd:powerbi.DataViewValueColumn; let defaultEnd:powerbi.DataViewValueColumn;
values.map((messure)=>{ console.debug('Start map messures');
messures?.map((messure)=>{
console.debug("map");
var role=messure.source.roles; var role=messure.source.roles;
if(role['defaultSelect']){ if(role['defaultSelect']){
defaultSelect=messure; defaultSelect=messure;
@ -87,8 +104,17 @@ export class Visual implements IVisual {
defaultEnd=messure; defaultEnd=messure;
}; };
}); });
this.layoutManager.update(dataView); let width:number=options.viewport.width;
this.selectorManager.updateView(field,defaultSelect,defaultStart,defaultEnd); let height:number=options.viewport.height;
console.debug("start layoutManager updateView");
this.layoutManager.update(dataView,width-10,height-10);
console.debug("start selectorManager updateView");
this.selectorManager.updateData(field,defaultSelect,defaultStart,defaultEnd);
console.debug("start filterManager updateView");
this.filterManager.update(field);
this.events.renderingFinished(options); this.events.renderingFinished(options);
} }

View File

@ -1,8 +1,10 @@
"Use strict"; "Use strict";
import powerbi from "powerbi-visuals-api"; import powerbi from "powerbi-visuals-api";
import DataView = powerbi.DataView; import DataView = powerbi.DataView;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import {VisualSettings} from "../settings/visualSettings"; import {VisualSettings} from "../settings/visualSettings";
import * as d3 from "d3"; import * as d3 from "d3";
import { IFilter } from "powerbi-models";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>; type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
/* /*
Main interfaces Main interfaces
@ -11,28 +13,29 @@ Main interfaces
//ISelectorManager //ISelectorManager
export interface ILayoutManager{ export interface ILayoutManager{
layout:Selection<HTMLElement>; layout:Selection<HTMLElement>;
update(dataView:DataView):void; update(dataView:DataView,width:number,height:number):void;
} }
export interface ILayoutManagerConstructor{ export interface ILayoutManagerConstructor{
new(layout:Selection<HTMLElement>):ILayoutManager; new(container:Selection<HTMLElement>):ILayoutManager;
}; };
//ISelectorManager //ISelectorManager
export interface ISelectorManager{ export interface ISelectorManager{
selectorContainer:Selection<HTMLElement>; selectorContainer:Selection<HTMLElement>;
updateView(categories:powerbi.DataViewCategoryColumn,defaultSelect:powerbi.DataViewValueColumn,defaultStart:powerbi.DataViewValueColumn,defaultEnd:powerbi.DataViewValueColumn); filterManager:IFilterManager;
updateData(field:powerbi.DataViewCategoryColumn,defaultSelect:powerbi.DataViewValueColumn,defaultStart:powerbi.DataViewValueColumn,defaultEnd:powerbi.DataViewValueColumn);
} }
export interface ISelectorManagerConstructor{ export interface ISelectorManagerConstructor{
new(selectorContainer:Selection<HTMLElement>):ISelectorManager; new(selectorContainer:Selection<HTMLElement>,filterManager:IFilterManager):ISelectorManager;
} }
//IFilterManager //IFilterManager
export interface IFilterManager{ export interface IFilterManager{
applyFilter():void; update(field:powerbi.DataViewCategoryColumn):void;
setJsonFilter(field:Text|number,select: Text|number):void; filterStringField(selection:string[]):void;
setJsonFilter(field:number,start:number,end:number):void;
setJsonFitler(filter:Date,select:Date):void;
} }
export interface IFilterManagerConstructor{ export interface IFilterManagerConstructor{
new(host:powerbi.extensibility.IVisualHost); new(host:IVisualHost):IFilterManager;
} }

File diff suppressed because one or more lines are too long