diff --git a/ReadMe.md b/ReadMe.md new file mode 100644 index 0000000..1372c2f --- /dev/null +++ b/ReadMe.md @@ -0,0 +1,22 @@ +# A utility slicer for Power Bi +Assign default selection to this slicer by messures, just use DAX! +## Functionalities +* Implemented +1. Dropdown-slicer for text field +1. Use DAX to assign **single** default selected items to the dropdown-slicer +1. Support async slicers +* Planned +1. List-slicer for text field +1. Use DAX to assign **one** default selected items to the list-slicer +1. Use DAX to assign **multiple** default selected items to the dropdown-slicer and list-slicer +1. Range-slicer for number field +1. Use DAX to assign default selected range to the range-slicer +1. Single-date-slicer for datetime field +1. Use DAX to assign default selected date to the single-date-slicer +1. Period-slicer for datetime field +1. Use DAX to assign default selected period to the period-slicer +## Known issures +1. Slicer components for number field and datetime field are in developing, just slicer for text field is usable now +1. The outline setting has no effectivity on dropdown items +1. I can't change background-color of dropdown items +1. This slicer wouldn't support bookmarks \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0385818..1eeb21e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -905,6 +905,11 @@ "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-dataviewutils/-/powerbi-visuals-utils-dataviewutils-2.2.1.tgz", "integrity": "sha512-Ai+TM1gj6DpAsNbn0IhOwUCAPfcaH4Z7y6Ow2OwAfbxNpELwQSF0S8D+vlJN2AoqV/ruQhnEngUC88mMFNyvJQ==" }, + "powerbi-visuals-utils-typeutils": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-typeutils/-/powerbi-visuals-utils-typeutils-2.2.1.tgz", + "integrity": "sha512-xm5xNBVudCiU9ZZggsLlpHr+a4bnHtgw6Cy1UtNM/zILtOE2HUamjw+yZovLe6YNov4N2EaCmPO8XPhcXkuz+A==" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index cb8d328..da9b9f9 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "d3": "5.12.0", "powerbi-models": "^1.3.3", "powerbi-visuals-api": "~2.6.1", - "powerbi-visuals-utils-dataviewutils": "2.2.1" + "powerbi-visuals-utils-dataviewutils": "2.2.1", + "powerbi-visuals-utils-typeutils": "^2.2.1" }, "devDependencies": { "@types/node": "^13.13.4", diff --git a/src/managers/filterManager.ts b/src/managers/filterManager.ts index 0d7131e..94c54b8 100644 --- a/src/managers/filterManager.ts +++ b/src/managers/filterManager.ts @@ -11,12 +11,17 @@ import { select, json } from "d3"; export class FilterManager implements IFilterManager{ private target: models.IFilterColumnTarget={table:'',column:''}; private host:IVisualHost; - private jsonFilter:powerbi.IFilter; + private _jsonFilter:powerbi.IFilter; + + public get jsonFilter() : powerbi.IFilter { + return this._jsonFilter; + } + constructor(host:IVisualHost){ this.host=host; } setFilter(jsonFilter: powerbi.IFilter,applyNow:boolean): void { - this.jsonFilter=jsonFilter; + this._jsonFilter=jsonFilter; if(applyNow){ this.applyJsonFilter(); } @@ -24,7 +29,7 @@ export class FilterManager implements IFilterManager{ public applyJsonFilter():void{ console.debug('filter manager applyJsonFilter start'); - this.host.applyJsonFilter(this.jsonFilter,'general','filter',powerbi.FilterAction.merge); + this.host.applyJsonFilter(this._jsonFilter,'general','filter',powerbi.FilterAction.merge); console.debug('filter manager applyJsonFilter end'); } @@ -61,7 +66,7 @@ export class FilterManager implements IFilterManager{ "values": selection } console.debug("jsonFilter:",jsonFilter); - this.jsonFilter=jsonFilter; + this._jsonFilter=jsonFilter; if(applyNow){ this.applyJsonFilter(); } diff --git a/src/managers/selectors/dropDownSelector.ts b/src/managers/selectors/dropDownSelector.ts index 8fa31ce..16624f5 100644 --- a/src/managers/selectors/dropDownSelector.ts +++ b/src/managers/selectors/dropDownSelector.ts @@ -4,6 +4,7 @@ import powerbi from "powerbi-visuals-api"; import * as d3 from "d3"; import { selection } from "d3"; type Selection = d3.Selection; +import {pixelConverter} from "powerbi-visuals-utils-typeutils"; export class DropDownSelector extends Selector { public select(items: string[]): void { @@ -25,7 +26,7 @@ export class DropDownSelector extends Selector { this.dropDown.style('background-color', itemsSetting.backgroundColor) .attr('postion','absolute') .style('color', itemsSetting.fontColor) - .style('font-size', itemsSetting.textSize + 'px') + .style('font-size',pixelConverter.fromPointToPixel(itemsSetting.textSize) + 'px') .style('width', (width - 10) + 'px') .style('border-style', settings.Enums.getOutlineStyle(itemsSetting.outline)) .style('border-width', '2px') @@ -37,8 +38,7 @@ export class DropDownSelector extends Selector { .style('width', (width - 10) + 'px') .style('border-style', settings.Enums.getOutlineStyle(itemsSetting.outline)) .style('border-width', '2px') - .style('border-color', 'black') - .style('maxHeight','200px'); + .style('border-color', 'black'); } console.debug('dropDownSelector updateFormat end'); } @@ -73,7 +73,7 @@ export class DropDownSelector extends Selector { protected createView(container: Selection) { console.debug('dropDownViewManager', 'createView start'); this.container = container; - this.dropDown = this.container.append("select").classed("dropDown-selector", true).classed("selector", true);//.attr("multiple",false); + this.dropDown = this.container.append("select").classed("dropDown-selector", true).classed("selector", true);//.attr('multiple',true); let dropDownSelector=this; //on change, filter this.dropDown.on("input change", function () { @@ -95,6 +95,7 @@ export class DropDownSelector extends Selector { } console.debug("this", this.selectedOptions); }); + console.debug('dropDownViewManager', 'createView end'); } @@ -116,6 +117,7 @@ export class DropDownSelector extends Selector { newDefaultSelect = defaultSelect.values[0].toString(); console.debug('newDefaultSelect:', newDefaultSelect); } + //let values=field.values let options: d3.Selection = >this.dropDown.selectAll("option").data(field.values, function (d) { return d.toString(); });//map data options.exit().remove();//delete @@ -125,6 +127,7 @@ export class DropDownSelector extends Selector { .text(function (d) { return d.toString(); }) .attr('label', function (d) { return d.toString(); }) .classed('dropDown-option', true) + .attr('title',function (d) { return d.toString(); }) .merge(options) .attr("selected", function (d) { console.debug('d.toString():', d.toString()); @@ -134,10 +137,14 @@ export class DropDownSelector extends Selector { console.debug('Set defaultSelection end'); } else { console.debug('defaultSelection not reset, start update options'); - options=options.enter().append("option").text(function (d) { return d.toString(); }).attr('label', function (d) { return d.toString(); }).classed('dropDown-option', true).merge(options);//add + options=options.enter().append("option") + .text(function (d) { return d.toString(); }) + .attr('label', function (d) { return d.toString(); }) + .attr('title',function (d) { return d.toString(); }) + .attr('label', function (d) { return d.toString(); }).classed('dropDown-option', true).merge(options);//add console.debug('defaultSelection not reset, end update options'); } - + let selectedValues: string[] = []; this.dropDown.selectAll('option').each(function(d,i){ let option=d3.select(this); diff --git a/src/visual/visual.ts b/src/visual/visual.ts index a844e1e..8f635af 100644 --- a/src/visual/visual.ts +++ b/src/visual/visual.ts @@ -84,7 +84,6 @@ export class Visual implements IVisual { }); } - //First, create the filterManager this.filterManager=ManagerFactory.CreateFilterManager(FilterManager,options.host); //Then, layoutManager and selectorManager, both use the filterManager @@ -142,18 +141,35 @@ export class Visual implements IVisual { this.selectorManager.updateData(field,defaultSelect,defaultStart,defaultEnd); this.selectorManager.updateFormat(this.settings,width,height); console.debug("previous filter",JSON.stringify(options.jsonFilters)); - if(this.isFirstUpdate&&options.jsonFilters&&options.jsonFilters[0]){ - //Sync slicers - console.debug('Sync slicers init end'); - this.filterManager.setFilter(options.jsonFilters[0],false); - this.selectorManager.select(options.jsonFilters[0]['values']) - console.debug('Sync slicers init end'); + /* + Compare two jsonFilters(filterManager.jsonFilter and options.jsonFilters[0]). + Use method JSON.stringify. + 1. filterManager.jsonFilter is null, options.jsonFilter[0] is null + Don't restore + 2. filterManager.jsonFilter is Null, options.jsonFilter[0] is not null + Restore + 3. filterManager.jsonFilter is not null, options.jsonFilter[0] is null + Don't restore + 4. filterManager.jsonFilter != options.jsonFilter[0] + Restore + 5. filterManager.jsonFilter == options.jsonFilter[0] + Don't restore + */ + if(options.jsonFilters&&options.jsonFilters[0]&&this.isFirstUpdate){ + console.debug('options.jsonFilters[0] is not null'); + if((!this.filterManager.jsonFilter)|| + (JSON.stringify(this.filterManager.jsonFilter)!=JSON.stringify(options.jsonFilters[0]))){ + //Sync slicers + console.debug('Sync slicers init or restore a bookmark start'); + this.filterManager.setFilter(options.jsonFilters[0],false); + this.selectorManager.select(options.jsonFilters[0]['values']) + console.debug('Sync slicers init or restore a bookmark end'); + }//end if }else{ - console.debug('Neednt init a sync slicer'); + console.debug('Neednt init a sync slicer or restore a bookmark'); } - console.debug("isFirstUpdate:",this.isFirstUpdate); - this.isFirstUpdate=false; console.debug('visual update end'); + this.isFirstUpdate=false; this.filterManager.applyJsonFilter(); this.events.renderingFinished(options); } diff --git a/src/visual/visualInterfaces.ts b/src/visual/visualInterfaces.ts index f9b9bf9..f467413 100644 --- a/src/visual/visualInterfaces.ts +++ b/src/visual/visualInterfaces.ts @@ -43,6 +43,7 @@ export interface ISelectorManagerConstructor{ //IFilterManager export interface IFilterManager{ + jsonFilter:powerbi.IFilter; update(field:powerbi.DataViewCategoryColumn):void; setFilter_String(selection:string[],applyNow:boolean):void; setFilter(jsonFilter:powerbi.IFilter,applyNow:boolean):void;