The single-dropdown work well

This commit is contained in:
沐见南 2020-05-02 00:02:18 +08:00
parent c676bb727e
commit b2639bcebe
10 changed files with 153 additions and 162 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
/dist /dist
/.tmp /.tmp
/.vscode /.vscode
webpack.statistics.*

View File

@ -18,10 +18,6 @@
"icon": "assets/icon.png" "icon": "assets/icon.png"
}, },
"externalJS": [ "externalJS": [
"node_modules/jquery/dist/jquery.min.js",
"src/coverJquery.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/bootstrap-multiselect/dist/js/bootstrap-multiselect.min.js"
], ],
"style": "style/visual.less", "style": "style/visual.less",
"capabilities": "capabilities.json", "capabilities": "capabilities.json",

View File

@ -14,6 +14,15 @@ export class FilterManager implements IFilterManager{
constructor(host:IVisualHost){ constructor(host:IVisualHost){
this.host=host; this.host=host;
} }
public dispose():void{
console.debug('filterManager disposing');
if(this.target.table&&this.target.column){
this.clear();
}
console.debug('filterManager disposed');
}
public clear():void{ public clear():void{
console.debug("clear start:"); console.debug("clear start:");
this.host.applyJsonFilter(null,"general","filter",powerbi.FilterAction.remove); this.host.applyJsonFilter(null,"general","filter",powerbi.FilterAction.remove);

View File

@ -11,13 +11,22 @@ export class LayoutManager implements ILayoutManager{
// constructor(layout:Selection<HTMLElement>){ // constructor(layout:Selection<HTMLElement>){
// this.layout=layout; // this.layout=layout;
// } // }
header:Selection<HTMLDivElement> headerContainer:Selection<HTMLDivElement>
constructor(layout:Selection<HTMLElement>,filterManager:IFilterManager){ constructor(layout:Selection<HTMLElement>,filterManager:IFilterManager){
this.layout=layout; this.layout=layout;
this.header=this.layout.append('div').attr('header',true); this.headerContainer=layout.append("div").classed("header-container",true);
this.header.append('button').attr('clear',true).text('clear').on('click',function(){ this.headerContainer.append('button').attr('clear',true).text('clear').on('click',function(){
filterManager.clear(); filterManager.clear();
}); });
this.headerContainer.style('display','none');
}
public dispose():void{
console.debug('layoutManager disposing');
this.headerContainer.remove();
this.layout.remove();
console.debug('layoutManager disposed');
} }
update(dataView:DataView,width:number,height:number):void{ update(dataView:DataView,width:number,height:number):void{
//this.layout.style("width",width+"px").style("height",height+"px"); //this.layout.style("width",width+"px").style("height",height+"px");

View File

@ -21,6 +21,10 @@ export class SelectorManager implements ISelectorManager{
this.selectorContainer=selectorContainer; this.selectorContainer=selectorContainer;
this.filterManager=filterManager; this.filterManager=filterManager;
} }
public dispose():void{
this.selector.dispose();
this.selectorContainer.remove();
}
public switchSelector<T extends ISelector>(classSelector:new ()=>T){ public switchSelector<T extends ISelector>(classSelector:new ()=>T){
let newSelector=new classSelector(); let newSelector=new classSelector();
this.selector?.dispose(); this.selector?.dispose();
@ -56,6 +60,30 @@ interface ISelector{
} }
abstract class Selector implements ISelector{ abstract class Selector implements ISelector{
protected field: powerbi.DataViewCategoryColumn;
protected defaultSelect: powerbi.DataViewValueColumn;
protected defaultStart: powerbi.DataViewValueColumn;
protected defaultEnd: powerbi.DataViewValueColumn;
protected checkFieldChange(field: powerbi.DataViewCategoryColumn):boolean{
//Field is not null, so first check the old field
if(!this.field){
return true;
}
if(field.source.queryName==this.field.source.queryName){
console.debug('checkFieldChange: false');
return false;
}else{
console.debug('checkFieldChange: true');
return true;
}
}
protected abstract checkDefaultSelectionChange(defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn):boolean;
protected checkFieldAndDefaultSelectionChange(field: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn){
console.debug('checkFieldAndDefaultSelectionChange start');
let flag:boolean=this.checkFieldChange(field)||this.checkDefaultSelectionChange(defaultSelect,defaultStart,defaultEnd)
console.debug('checkFieldAndDefaultSelectionChange end, result:',flag);
return flag;
}
constructor(manager: ISelectorManager){ constructor(manager: ISelectorManager){
console.debug("Abstract selector:","constructor start"); console.debug("Abstract selector:","constructor start");
this.manager=manager; this.manager=manager;
@ -67,59 +95,105 @@ abstract class Selector implements ISelector{
public abstract update(field: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn):void; public abstract update(field: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn):void;
} }
class DropDownSelector extends Selector{ class DropDownSelector extends Selector{
protected checkDefaultSelectionChange(defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn): boolean {
//The defaultSelect is nullable, so first check the new defaultSelect
console.debug('checkDefaultSelectionChange start');
let flag:boolean;
if(!defaultSelect||!defaultSelect.values||!defaultSelect.values[0]){
console.debug('new defaultSelect is null, set flag=false')
flag=flag||false;
}else{
if(!this.defaultSelect||!this.defaultSelect.values||!defaultSelect.values[0]){
console.debug('previous defaultSelect is null, set flag=true');
flag=flag||true;
}else{
if(defaultSelect.values[0].toString()!=this.defaultSelect.values[0].toString()){
console.debug('new defaultSelect not equal to the previous, set flag=true');
flag=flag||true;
}else{
console.debug('new defaultSelect equal to the previous, set flag=false');
flag=flag||false;
}
}
}
console.debug('checkDefaultSelectionChange end, result:',flag);
return flag;
}
private dropDown:Selection<HTMLSelectElement>; private dropDown:Selection<HTMLSelectElement>;
protected createView() { protected createView() {
console.debug('dropDownViewManager','createView start'); console.debug('dropDownViewManager','createView start');
this.dropDown=this.manager.selectorContainer.append("select").classed("dropDown-selector",true).classed("selector",true).attr("multiple",true); this.dropDown=this.manager.selectorContainer.append("select").classed("dropDown-selector",true).classed("selector",true);//.attr("multiple",false);
let filterManager:IFilterManager=this.manager.filterManager;
this.dropDown.on("input change",function(){
console.debug('DropDownSelector:',"input change");
console.debug('this',this);
console.debug('filterManager:',filterManager);
let selectedValues: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);
selectedValues.push(option.text);
}
}
if(selectedValues.length==0){
}else{
console.debug("selection.length",selectedValues.length);
filterManager.filterStringField(selectedValues);
}
console.debug("this",this.selectedOptions);
});
console.debug('dropDownViewManager','createView end'); console.debug('dropDownViewManager','createView end');
} }
public dispose(){ public dispose(){
console.debug('dropDown-selector disposing');
this.dropDown.remove(); this.dropDown.remove();
console.debug('dropDown-selector disposed');
} }
public update(field: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn) { public update(field: powerbi.DataViewCategoryColumn, defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn) {
console.debug('dropDownViewManager','update start'); console.debug('dropDownViewManager','update start');
let options=this.dropDown.selectAll("option").data(field.values,function(d){return d.toString();});//map data //Check field, defaultSelect are changed or not
options.enter().append("option").text(function(d){return d.toString();}).attr('dropDown-option');//add let needUpdateDefaultSelection:boolean=this.checkFieldAndDefaultSelectionChange(field,defaultSelect,defaultStart,defaultEnd);
let newDefaultSelect:string;
if(needUpdateDefaultSelection&&defaultSelect&&defaultSelect.values&&defaultSelect.values[0]){
newDefaultSelect=defaultSelect.values[0].toString();
console.debug('newDefaultSelect:',newDefaultSelect);
}
let options:d3.Selection<HTMLOptionElement, powerbi.PrimitiveValue, HTMLSelectElement, any>=<d3.Selection<HTMLOptionElement, powerbi.PrimitiveValue, HTMLSelectElement, any>>this.dropDown.selectAll("option").data(field.values,function(d){return d.toString();});//map data
options.exit().remove();//delete options.exit().remove();//delete
console.debug("dropDown:",this.dropDown);
let filterManager:IFilterManager=this.manager.filterManager;
// this.dropDown.on("input change",function(){
// console.debug('DropDownSelector:',"input change");
// console.debug('this',this);
// console.debug('filterManager:',filterManager);
// let selectedValues: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);
// selectedValues.push(option.text);
// }
// }
// if(selectedValues.length==0){
// }else{
// console.debug("selection.length",selectedValues.length);
// filterManager.filterStringField(selectedValues);
// }
// console.debug("this",this.selectedOptions);
// });
$('.dropDown-selector').multiselect({ if(needUpdateDefaultSelection&&newDefaultSelect){
onChange:function(){ console.debug('reset defaultSelection start');
let selectedValues:string[]=[]; options=options.enter().append("option")
$('option:selected').map(function(a,item){ .text(function(d){return d.toString();})
selectedValues.push(item.textContent); .attr('label',function(d){return d.toString();})
console.debug('item:',item.textContent); .classed('dropDown-option',true)
filterManager.filterStringField(selectedValues); .merge(options)
}); .property("selected",function(d){
}, console.debug('d.toString():',d.toString());
maxHeight:100, console.debug('newDefaultSelect:',newDefaultSelect);
includeSelectAllOption:true return (d.toString()==newDefaultSelect)?'selected':null;
}); });
this.dropDown.dispatch('change');
console.debug('reset defaultSelection end');
}else{
console.debug('defaultSelection not reset, start update options');
options.enter().append("option").text(function(d){return d.toString();}).attr('label',function(d){return d.toString();}).classed('dropDown-option',true);//add
console.debug('defaultSelection not reset, end update options');
}
console.debug("dropDown:",this.dropDown);
this.field=field;
this.defaultSelect=defaultSelect;
console.debug('dropDownViewManager','update end'); console.debug('dropDownViewManager','update end');
} }
} }
class ListSelector extends Selector{ class ListSelector extends Selector{
protected checkDefaultSelectionChange(defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn): boolean {
throw new Error("Method not implemented.");
}
public dispose() { public dispose() {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
@ -132,6 +206,9 @@ class ListSelector extends Selector{
} }
} }
class CalendarSelector extends Selector{ class CalendarSelector extends Selector{
protected checkDefaultSelectionChange(defaultSelect: powerbi.DataViewValueColumn, defaultStart: powerbi.DataViewValueColumn, defaultEnd: powerbi.DataViewValueColumn): boolean {
throw new Error("Method not implemented.");
}
public dispose() { public dispose() {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }

View File

@ -54,7 +54,6 @@ export class Visual implements IVisual {
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 filterManager:visualInterfaces.IFilterManager; private filterManager:visualInterfaces.IFilterManager;
private selectionManager:powerbi.extensibility.ISelectionManager; private selectionManager:powerbi.extensibility.ISelectionManager;
constructor(options: VisualConstructorOptions) { constructor(options: VisualConstructorOptions) {
@ -63,6 +62,8 @@ export class Visual implements IVisual {
if (document) { if (document) {
this.selectionManager =options.host.createSelectionManager(); 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);
//overload context menu
// d3.select(options.element).on('contextmenu', () => { // d3.select(options.element).on('contextmenu', () => {
// const mouseEvent: MouseEvent = <MouseEvent>d3.event; // const mouseEvent: MouseEvent = <MouseEvent>d3.event;
// //const eventTarget: EventTarget = mouseEvent.target; // //const eventTarget: EventTarget = mouseEvent.target;
@ -73,12 +74,14 @@ export class Visual implements IVisual {
// }); // });
// //mouseEvent.preventDefault(); // //mouseEvent.preventDefault();
// }); // });
let headerContainer=container.append("div").classed("header-container",true);
let selectorContainer=container.append("div").classed("selector-container",true);
//First, create the filterManager //First, create the filterManager
this.filterManager=ManagerFactory.CreateFilterManager(FilterManager,options.host); this.filterManager=ManagerFactory.CreateFilterManager(FilterManager,options.host);
//Then, layoutManager and selectorManager //Then, layoutManager and selectorManager, both use the filterManager
//Lagyoutmanager manage the whole div and the slicer-header
this.layoutManager=ManagerFactory.CreateLayoutManager(LayoutManager,container,this.filterManager); this.layoutManager=ManagerFactory.CreateLayoutManager(LayoutManager,container,this.filterManager);
//SelectorManager manage selectors
let selectorContainer=container.append("div").classed("selector-container",true);
this.selectorManager=ManagerFactory.CreateSelectorManager(SelectorManager,selectorContainer,this.filterManager); this.selectorManager=ManagerFactory.CreateSelectorManager(SelectorManager,selectorContainer,this.filterManager);
} }
console.debug('end constructor'); console.debug('end constructor');
@ -112,12 +115,14 @@ export class Visual implements IVisual {
console.debug("start layoutManager updateView"); console.debug("start layoutManager updateView");
this.layoutManager.update(dataView,width-10,height-10); 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"); console.debug("start filterManager updateView");
this.filterManager.update(field); this.filterManager.update(field);
this.events.renderingFinished(options); this.events.renderingFinished(options);
console.debug("start selectorManager updateView");
this.selectorManager.updateData(field,defaultSelect,defaultStart,defaultEnd);
} }
private static parseSettings(dataView: DataView): VisualSettings { private static parseSettings(dataView: DataView): VisualSettings {

View File

@ -14,6 +14,7 @@ Main interfaces
export interface ILayoutManager{ export interface ILayoutManager{
layout:Selection<HTMLElement>; layout:Selection<HTMLElement>;
update(dataView:DataView,width:number,height:number):void; update(dataView:DataView,width:number,height:number):void;
dispose():void;
} }
export interface ILayoutManagerConstructor{ export interface ILayoutManagerConstructor{
new(container:Selection<HTMLElement>,filterManager:IFilterManager):ILayoutManager; new(container:Selection<HTMLElement>,filterManager:IFilterManager):ILayoutManager;
@ -23,19 +24,20 @@ export interface ILayoutManagerConstructor{
export interface ISelectorManager{ export interface ISelectorManager{
selectorContainer:Selection<HTMLElement>; selectorContainer:Selection<HTMLElement>;
filterManager:IFilterManager; filterManager:IFilterManager;
updateData(field:powerbi.DataViewCategoryColumn,defaultSelect:powerbi.DataViewValueColumn,defaultStart:powerbi.DataViewValueColumn,defaultEnd:powerbi.DataViewValueColumn); dispose():void;
updateData(field:powerbi.DataViewCategoryColumn,defaultSelect:powerbi.DataViewValueColumn,defaultStart:powerbi.DataViewValueColumn,defaultEnd:powerbi.DataViewValueColumn):void;
} }
export interface ISelectorManagerConstructor{ export interface ISelectorManagerConstructor{
new(selectorContainer:Selection<HTMLElement>,filterManager:IFilterManager):ISelectorManager; new(selectorContainer:Selection<HTMLElement>,filterManager:IFilterManager):ISelectorManager;
} }
//IFilterManager //IFilterManager
export interface IFilterManager{ export interface IFilterManager{
update(field:powerbi.DataViewCategoryColumn):void; update(field:powerbi.DataViewCategoryColumn):void;
filterStringField(selection:string[]):void; filterStringField(selection:string[]):void;
clear():void; clear():void;
dispose():void;
} }
export interface IFilterManagerConstructor{ export interface IFilterManagerConstructor{
new(host:IVisualHost):IFilterManager; new(host:IVisualHost):IFilterManager;

View File

@ -1,5 +1,3 @@
@import "/node_modules/bootstrap/dist/css/bootstrap.min.css";
@import "/node_modules/bootstrap-multiselect/dist/css/bootstrap-multiselect.css";
p { p {
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long