From ab2af8e1026fd57215b81951b4b6f77e335f3d90 Mon Sep 17 00:00:00 2001 From: MuJianNan Date: Mon, 27 Apr 2020 23:44:05 +0800 Subject: [PATCH] Filter testing now, update the dropDown with d3 --- capabilities.json | 18 ++++++++ package-lock.json | 5 +++ package.json | 5 ++- src/managers/filterManager.ts | 46 ++++++++++++------- src/managers/index.ts | 8 ++-- src/managers/layoutManager.ts | 12 ++--- src/managers/managerFactory.ts | 8 ++-- src/managers/selectorManager.ts | 78 ++++++++++++++++++++++++++------- src/visual/visual.ts | 48 +++++++++++++++----- src/visual/visualInterfaces.ts | 21 +++++---- webpack.statistics.dev.html | 4 +- 11 files changed, 184 insertions(+), 69 deletions(-) diff --git a/capabilities.json b/capabilities.json index 73a3eb0..e21e535 100644 --- a/capabilities.json +++ b/capabilities.json @@ -44,6 +44,24 @@ } ], "objects": { + "general": { + "displayName": "General", + "displayNameKey": "formattingGeneral", + "properties": { + "filter": { + "type": { + "filter": true + } + }, + "selfFilter": { + "type": { + "filter": { + "selfFilter": false + } + } + } + } + }, "dataPoint": { "displayName": "Data colors", "properties": { diff --git a/package-lock.json b/package-lock.json index c38ff45..5f06da3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -881,6 +881,11 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "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": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-2.6.2.tgz", diff --git a/package.json b/package.json index cab1605..3e1d041 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,11 @@ "@babel/runtime": "7.6.0", "@babel/runtime-corejs2": "7.6.0", "@types/d3": "5.7.2", + "core-js": "3.2.1", "d3": "5.12.0", - "powerbi-visuals-utils-dataviewutils": "2.2.1", + "powerbi-models": "^1.3.3", "powerbi-visuals-api": "~2.6.1", - "core-js": "3.2.1" + "powerbi-visuals-utils-dataviewutils": "2.2.1" }, "devDependencies": { "ts-loader": "6.1.0", diff --git a/src/managers/filterManager.ts b/src/managers/filterManager.ts index c76fa2b..19a57f4 100644 --- a/src/managers/filterManager.ts +++ b/src/managers/filterManager.ts @@ -1,23 +1,39 @@ "Use strict"; import powerbi from "powerbi-visuals-api"; +import IVisualHost = powerbi.extensibility.visual.IVisualHost; import DataView = powerbi.DataView; import * as visualInterfaces from "../visual/visualInterfaces"; import * as d3 from "d3"; import { IFilterManager } from "../visual/visualInterfaces"; -export default class FilterManager implements IFilterManager{ - applyFilter(): void { - 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 { - - } +import * as models from 'powerbi-models'; +import { select, json } from "d3"; +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"); + } } \ No newline at end of file diff --git a/src/managers/index.ts b/src/managers/index.ts index 207b51a..c584cd1 100644 --- a/src/managers/index.ts +++ b/src/managers/index.ts @@ -1,4 +1,4 @@ -export {default as filterManager} from "./filterManager"; -export {default as layoutManager} from "./layoutManager"; -export {default as selectorManager} from "./selectorManager"; -export {default as managerFactory} from "./managerFactory"; \ No newline at end of file +export {FilterManager} from "./filterManager"; +export {LayoutManager} from "./layoutManager"; +export {SelectorManager} from "./selectorManager"; +export {ManagerFactory} from "./managerFactory"; \ No newline at end of file diff --git a/src/managers/layoutManager.ts b/src/managers/layoutManager.ts index 8642c39..702ef51 100644 --- a/src/managers/layoutManager.ts +++ b/src/managers/layoutManager.ts @@ -5,12 +5,12 @@ import * as visualInterfaces from "../visual/visualInterfaces"; import * as d3 from "d3"; import { ILayoutManager } from "../visual/visualInterfaces"; type Selection = d3.Selection; -export default class LayoutManager implements ILayoutManager{ +export class LayoutManager implements ILayoutManager{ layout:Selection; - constructor(layout:Selection){ - this.layout=layout; - } - update(dataView:DataView):void{ - + // constructor(layout:Selection){ + // this.layout=layout; + // } + update(dataView:DataView,width:number,height:number):void{ + //this.layout.style("width",width+"px").style("height",height+"px"); } } diff --git a/src/managers/managerFactory.ts b/src/managers/managerFactory.ts index d5e1098..8df9000 100644 --- a/src/managers/managerFactory.ts +++ b/src/managers/managerFactory.ts @@ -3,14 +3,14 @@ import * as visualInterfaces from "../visual/visualInterfaces"; import * as d3 from "d3"; import powerbi from "powerbi-visuals-api"; type Selection = d3.Selection; -export default class ManagerFactory{ +export class ManagerFactory{ public static CreateLayoutManager(classLayoutManager:visualInterfaces.ILayoutManagerConstructor,container:Selection):visualInterfaces.ILayoutManager{ return new classLayoutManager(container); } - public static CreateSelectorManager(classSelectorManager:visualInterfaces.ISelectorManagerConstructor,container:Selection):visualInterfaces.ISelectorManager{ - return new classSelectorManager(container); + public static CreateSelectorManager(classSelectorManager:visualInterfaces.ISelectorManagerConstructor,container:Selection,filterManager:visualInterfaces.IFilterManager):visualInterfaces.ISelectorManager{ + 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); } } diff --git a/src/managers/selectorManager.ts b/src/managers/selectorManager.ts index 63a375b..7e5e950 100644 --- a/src/managers/selectorManager.ts +++ b/src/managers/selectorManager.ts @@ -1,35 +1,57 @@ "Use strict"; import powerbi from "powerbi-visuals-api"; -import {ISelectorManager} from "../visual/visualInterfaces"; +import {ISelectorManager,ISelectorManagerConstructor, IFilterManager} from "../visual/visualInterfaces"; import * as d3 from "d3"; -type Selection = d3.Selection; -export default class SelectorManager implements ISelectorManager{ +type Selection = d3.Selection; +/* +负责页面上选择器的展示 +*/ +export class SelectorManager implements ISelectorManager{ public selectorContainer : Selection; - private selector; - - constructor(selectorContainer:Selection){ + private selector:ISelector; + public filterManager:IFilterManager; + private categories: powerbi.DataViewCategoryColumn; + private defaultSelect: powerbi.DataViewValueColumn; + private defaultStart: powerbi.DataViewValueColumn; + private defaultEnd: powerbi.DataViewValueColumn; + constructor(selectorContainer:Selection,filterManager:IFilterManager){ + console.debug("selectorManager constructor start"); this.selectorContainer=selectorContainer; + this.filterManager=filterManager; } - public switchSelector(c:new ()=>T){ - if(typeof(this.selector)!=typeof(c)){ - console.debug(typeof(this.selector)); - console.debug(typeof(c)); - } - let newSelector=new c(); + public switchSelector(classSelector:new ()=>T){ + let newSelector=new classSelector(); this.selector?.dispose(); 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){ - this.selector=new DropDownSelector(this); + let fieldType=categories.source.type; + if(fieldType.text){ + 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); }; + public filterStringField(selection:string[]){ + + }; } interface ISelector{ update(categories: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn); + dispose():void; } 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) { console.debug('dropDownViewManager','update start'); - this.view.selectAll("option").remove(); - this.view.selectAll("option").data(categories.values).enter().append("option").text(function(d){return d.toString();}); + let appending=this.view.selectAll("option").data(categories.values); + appending.enter().append("option").text(function(d){return d.toString();}); + appending.exit().remove(); + console.debug("appending:",appending); + let filterManager:IFilterManager=this.manager.filterManager; + (>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 { + const 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 selectorContainer=container.append("div").classed("selector-container",true); - this.layoutManager=managerFactory.CreateLayoutManager(layoutManager,container); - this.selectorManager=managerFactory.CreateSelectorManager(selectorManager,selectorContainer); - this.filterManager=managerFactory.CreateFilterManager(filterManager,options.host); + this.layoutManager=ManagerFactory.CreateLayoutManager(LayoutManager,container); + this.filterManager=ManagerFactory.CreateFilterManager(FilterManager,options.host); + this.selectorManager=ManagerFactory.CreateSelectorManager(SelectorManager,selectorContainer,this.filterManager); } console.debug('end constructor'); } @@ -69,15 +85,16 @@ export class Visual implements IVisual { public update(options: VisualUpdateOptions) { console.debug('visual update start'); this.events.renderingStarted(options); - this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]); let dataView=options.dataViews[0]; let field=dataView.categorical.categories[0]; - let values=dataView.categorical.values; + let messures=dataView.categorical.values; let defaultSelect:powerbi.DataViewValueColumn; let defaultStart: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; if(role['defaultSelect']){ defaultSelect=messure; @@ -87,8 +104,17 @@ export class Visual implements IVisual { defaultEnd=messure; }; }); - this.layoutManager.update(dataView); - this.selectorManager.updateView(field,defaultSelect,defaultStart,defaultEnd); + let width:number=options.viewport.width; + 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); } diff --git a/src/visual/visualInterfaces.ts b/src/visual/visualInterfaces.ts index 59a50f3..3218c1a 100644 --- a/src/visual/visualInterfaces.ts +++ b/src/visual/visualInterfaces.ts @@ -1,8 +1,10 @@ "Use strict"; import powerbi from "powerbi-visuals-api"; import DataView = powerbi.DataView; +import IVisualHost = powerbi.extensibility.visual.IVisualHost; import {VisualSettings} from "../settings/visualSettings"; import * as d3 from "d3"; +import { IFilter } from "powerbi-models"; type Selection = d3.Selection; /* Main interfaces @@ -11,28 +13,29 @@ Main interfaces //ISelectorManager export interface ILayoutManager{ layout:Selection; - update(dataView:DataView):void; + update(dataView:DataView,width:number,height:number):void; } export interface ILayoutManagerConstructor{ - new(layout:Selection):ILayoutManager; + new(container:Selection):ILayoutManager; }; //ISelectorManager export interface ISelectorManager{ selectorContainer:Selection; - 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{ - new(selectorContainer:Selection):ISelectorManager; + new(selectorContainer:Selection,filterManager:IFilterManager):ISelectorManager; } + + //IFilterManager export interface IFilterManager{ - applyFilter():void; - setJsonFilter(field:Text|number,select: Text|number):void; - setJsonFilter(field:number,start:number,end:number):void; - setJsonFitler(filter:Date,select:Date):void; + update(field:powerbi.DataViewCategoryColumn):void; + filterStringField(selection:string[]):void; } export interface IFilterManagerConstructor{ - new(host:powerbi.extensibility.IVisualHost); + new(host:IVisualHost):IFilterManager; } diff --git a/webpack.statistics.dev.html b/webpack.statistics.dev.html index f5fb753..62e6e0e 100644 --- a/webpack.statistics.dev.html +++ b/webpack.statistics.dev.html @@ -3,7 +3,7 @@ - Webpack Bundle Analyzer [25 Apr 2020 at 21:45] + Webpack Bundle Analyzer [27 Apr 2020 at 23:07]