Complete main work, next to do the last-test

This commit is contained in:
沐见南 2020-02-07 00:04:15 +08:00
parent 7fa42e0df2
commit e7528900d1
19 changed files with 4098 additions and 330 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 659 B

View File

@ -6,36 +6,139 @@
"kind": "Grouping",
"displayNameKey": "Role_Dates_DisplayName",
"description": "Column date",
"descriptionKey": "Role_Dates_Discription"
"descriptionKey": "Role_Dates_Description"
},
{
"displayNameKey": "Role_StartDate_DisplayName",
"displayName": "DefaultStartDate",
"name": "StartDate",
"kind": "Measure",
"descriptionKey": "Role_StartDate_Discription",
"description": "You can use Messure to assign Default date to the date-picker"
"descriptionKey": "Role_StartDate_Description",
"description": "You can use measure to assign Default date to the date-picker"
},
{
"displayNameKey": "Role_DefaultEndDate_DisplayName",
"displayName": "DefaultEndDate",
"name": "EndDate",
"kind": "Measure",
"descriptionKey": "Role_DefaultEndDate_Discription",
"description": "You can use Messure to assign Default date to the date-picker"
"descriptionKey": "Role_DefaultEndDate_Description",
"description": "You can use measure to assign Default date to the date-picker"
}
],
"objects": {
"period": {
"datePickers": {
"displayNameKey": "Obj_DatePickers_DisplayName",
"displayName": "Date pickers",
"descriptionKey": "Obj_DatePickers_Description",
"description": "Settings for period-pickers",
"properties": {
"orientationType":{
"displayNameKey": "DatePickers_Orientation_DisplayName",
"displayName": "Orientation",
"descriptionKey": "DatePickers_Orientation_Description",
"description": "Set orientation for datePickers",
"type": {
"enumeration": [
{
"displayNameKey": "Horizontal",
"displayName": "Horizontal",
"value": "0"
},
{
"displayNameKey": "Vertical",
"displayName": "Vertical",
"value": "1"
}
]
}
},
"fontSize":{
"displayNameKey": "DatePickers_FontSize_DisplayName",
"displayName": "Font size",
"descriptionKey": "DatePickers_FontSize_Description",
"description": "Set font-size for datePickers",
"type": {
"numeric": true
}
},
"fontColor":{
"displayNameKey": "DatePickers_FontColor_DisplayName",
"displayName": "Font color",
"descriptionKey": "DatePickers_FontColor_Description",
"description": "Set font-color for datePickers",
"type": {
"fill": {"solid": {"color":true}}
}
},
"backgroundColor":{
"displayNameKey": "DatePickers_BackgroundColor_DisplayName",
"displayName": "Background color",
"descriptionKey": "DatePickers_BackgroundColor_Description",
"description": "Set background-color for datePickers",
"type": {
"fill": {
"solid": {
"color":true
}
}
}
},
"backgroundTransparency":{
"displayNameKey": "DatePickers_BackgroundTransparency_DisplayName",
"displayName":"Background transparency",
"descriptionKey": "DatePickers_BackgroundTransparency_Description",
"description": "Set background-transparency for datePickers",
"type": {
"numeric": true
}
},
"borderWidth":{
"displayNameKey": "DatePickers_BorderWidth_DisplayName",
"displayName":"Border width",
"descriptionKey": "DatePickers_BorderWidth_Description",
"description": "Set border-width for datePickers",
"type": {
"numeric": true
}
},
"borderColor":{
"displayNameKey": "DatePickers_BorderColor_DisplayName",
"displayName": "Border color",
"descriptionKey": "DatePickers_BorderColor_Description",
"description": "Set border-color for datePickers",
"type": {
"fill": {
"solid": {
"color":true
}
}
}
},
"outlineColor":{
"displayNameKey": "DatePickers_OutlineColor_DisplayName",
"displayName": "Outline color",
"descriptionKey": "DatePickers_OutlineColor_Description",
"description": "Set outline-color for datePickers",
"type": {
"fill": {
"solid": {
"color":true
}
}
}
}
}
},
"period":{
"displayNameKey": "Obj_Period_DisplayName",
"displayName": "Period",
"descriptionKey": "Obj_Period_Discription",
"description": "Settings for period-picker",
"descriptionKey": "Obj_Period_Description",
"description": "Settings for period",
"properties": {
"defaultPeriodType": {
"displayNameKey": "Period_DefaultPeriodType_DisplayName",
"displayName": "Default period",
"descriptionKey":"Period_DefaultPeriodType_Discription",
"descriptionKey":"Period_DefaultPeriodType_Description",
"description": "Choose how to assign default period to the period-picker",
"type": {
"enumeration": [
@ -62,7 +165,7 @@
{
"value": "4",
"displayNameKey": "Custom",
"displayName": "Custom(use messures)"
"displayName": "Custom(use measures)"
}
]
},
@ -74,8 +177,8 @@
},
"displayNameKey": "Period_RelativeToday_DisplayName",
"displayName": "Contain today",
"descriptionKey": "Period_RelativeToday_Discription",
"description": "Effictive when and only when Custom(use messures) not selected"
"descriptionKey": "Period_RelativeToday_Description",
"description": "Effictive when and only when Custom(use measures) not selected"
},
"firstDayOfWeek": {
"descriptionKey": "Period_FirstDayOfWeek_DisplayName",

3736
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,13 +4,15 @@
"pbiviz": "pbiviz",
"start": "pbiviz start",
"package": "pbiviz package",
"lint": "tslint -c tslint.json -p tsconfig.json"
"lint": "tslint -c tslint.json -p tsconfig.json",
"cert": "pbiviz --install-cert"
},
"dependencies": {
"@babel/runtime": "7.6.0",
"@babel/runtime": "^7.6.0",
"@babel/runtime-corejs2": "7.6.0",
"@babel/runtime-corejs3": "^7.8.4",
"@types/d3": "5.7.2",
"core-js": "3.2.1",
"core-js": "^3.2.1",
"d3": "5.12.0",
"moment": "^2.24.0",
"powerbi-models": "^1.3.1",
@ -19,19 +21,24 @@
"powerbi-visuals-utils-interactivityutils": "^5.6.0"
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/polyfill": "^7.2.5",
"@types/d3": "5.7.2",
"@babel/preset-env": "^7.8.4",
"@types/jasmine": "2.5.37",
"@types/jasmine-jquery": "1.5.28",
"@types/jquery": "2.0.41",
"@types/karma": "3.0.0",
"@types/lodash-es": "4.17.1",
"babel-loader": "^8.0.6",
"base64-inline-loader": "^1.1.1",
"coveralls": "3.0.2",
"css-loader": "^3.4.2",
"extra-watch-webpack-plugin": "^1.0.3",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine": "2.5.2",
"jasmine-core": "2.5.2",
"jasmine-jquery": "2.1.1",
"jquery": "^3.4.1",
"json-loader": "^0.5.7",
"karma": "^4.4.1",
"karma-chrome-launcher": "2.2.0",
"karma-coverage": "1.1.2",
@ -42,13 +49,19 @@
"karma-typescript": "^4.1.1",
"karma-typescript-preprocessor": "0.4.0",
"karma-webpack": "3.0.5",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"puppeteer": "1.17.0",
"style-loader": "0.23.1",
"ts-loader": "6.1.0",
"ts-loader": "^6.2.1",
"ts-node": "7.0.1",
"tslint": "^5.18.0",
"tslint": "^5.20.1",
"tslint-microsoft-contrib": "^6.2.0",
"typescript": "3.6.3",
"webpack": "4.26.0"
"webpack": "^4.41.5",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.3"
}
}

View File

@ -1,13 +1,13 @@
{
"visual": {
"name": "DatePeriodSlice",
"displayName": "DatePeriodSlice",
"guid": "DatePeriodSlice9771124744984CE8959D0304EEAB35E8",
"name": "Period Slice - Syinpo",
"displayName": "Period Slicer - Syinpo",
"guid": "SyinpoPeriodSlice9771124744984CE8959D0304EEAB35E8",
"visualClassName": "Visual",
"version": "1.0.0",
"description": "可设置默认值的日期段切片器",
"supportUrl": "https://github.com/mujiannan/PbiViz",
"gitHubUrl": "https://github.com/mujiannan/PbiViz"
"description": "A period slicer, which can be initialized by messures.",
"supportUrl": "https://github.com/mujiannan/PeriodSlicer-Syinpo",
"gitHubUrl": "https://github.com/mujiannan/PeriodSlicer-Syinpo"
},
"apiVersion": "2.6.0",
"author": {

View File

@ -15,5 +15,7 @@ export class Period implements IPeriod {
export enum DefaultPeriodType {
LastMonth, LastEntireMonth, LastWeek, LastEntireWeek, Custom
}
export enum OrientationType{
Horizontal,Vertical
}

View File

@ -0,0 +1,12 @@
"use strict";
import { OrientationType } from "./datePeriod";
export class DatePickerSetting {
public orientationType: OrientationType = OrientationType.Horizontal;
public fontSize: number = 12;
public fontColor: string = "black";
public backgroundColor: string = "white";
public backgroundTransparency: number = 0;
public borderWidth: number = 1;
public borderColor: string = "gray";
public outlineColor: string = "blue";
}

View File

@ -4,7 +4,6 @@ import {IPeriod,Period} from "./datePeriod";
import * as moment from "moment";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
export interface IPeriodSelectorManager{
dateSelector_Start:Selection<HTMLInputElement>;
dateSelector_End:Selection<HTMLInputElement>;
period:IPeriod;
@ -24,11 +23,10 @@ export class PeriodSelectorManager implements IPeriodSelectorManager{
return this._dateSelector_End;
}
get period():IPeriod{
console.debug(this._dateSelector_Start.property("value"));
let start:Date=this._dateSelector_Start.property("value")?moment(this._dateSelector_Start.property("value")).startOf("day").toDate():null;
let end:Date=this._dateSelector_End.property("value")?moment(this._dateSelector_End.property("value")).endOf("day").toDate():null;
if(start&&end&&start>end){
console.debug("dateStart>dateEnd, set dateEnd=dateStart");
this._dateSelector_End.property("value",this._dateSelector_Start.property("value"));
end=start;
}
@ -39,25 +37,24 @@ export class PeriodSelectorManager implements IPeriodSelectorManager{
return this._defaultPeriod;
}
set defaultPeriod(newDefaultPeriod:IPeriod){
console.debug("PeriodSelectorManager set defaultPeriod start");
console.debug((!this._defaultPeriod.dateStart)&&newDefaultPeriod.dateStart);
console.debug(this._defaultPeriod.dateStart&&newDefaultPeriod.dateStart&&(newDefaultPeriod.dateStart.getTime()-this._defaultPeriod.dateStart.getTime()!=0));
console.debug("test");
let defaultPeriodChanged:boolean=false;
if(((!this._defaultPeriod.dateStart)&&newDefaultPeriod.dateStart)||
(this._defaultPeriod.dateStart&&newDefaultPeriod.dateStart&&(newDefaultPeriod.dateStart.getTime()-this._defaultPeriod.dateStart.getTime()!=0))){
defaultPeriodChanged=true;
let newStartStr=moment(newDefaultPeriod.dateStart).format("YYYY-MM-DD");
console.debug("new start",newStartStr);
this._dateSelector_Start.property("value",newStartStr);
console.debug("Set dateStart value="+newStartStr);
}
if(((!this._defaultPeriod.dateEnd)&&newDefaultPeriod.dateEnd)||
(this._defaultPeriod.dateEnd&&newDefaultPeriod.dateEnd&&(newDefaultPeriod.dateEnd.getTime()-this._defaultPeriod.dateEnd.getTime()!=0))){
defaultPeriodChanged=true;
let newEndStr=moment(newDefaultPeriod.dateEnd).format("YYYY-MM-DD");
this._dateSelector_End.property("value",newEndStr);
console.debug("Set dateEnd value="+newEndStr);
}
this._defaultPeriod=newDefaultPeriod;
this._dateSelector_Start.dispatch("change");
console.debug("PeriodSelectorManager set defaultPeriod end");
if(defaultPeriodChanged){
this._dateSelector_Start.dispatch("change");
}
}
}

View File

@ -1,7 +1,7 @@
"use strict";
import * as DatePeriod from "./datePeriod";
export class PeriodSettings {
public defaultPeriodType:DatePeriod.DefaultPeriodType=DatePeriod.DefaultPeriodType.LastEntireMonth;
export class PeriodSetting {
public defaultPeriodType:DatePeriod.DefaultPeriodType=DatePeriod.DefaultPeriodType.Custom;
public relativeToday:boolean=true;
public firstDayOfWeek:number=1;
public firstDayOfWeek:number=1.00;
}

View File

@ -1,54 +1,41 @@
"use strict";
import {DefaultPeriodType,IPeriod,Period} from "./datePeriod";
import { DefaultPeriodType, IPeriod, Period } from "./datePeriod";
import * as moment from "moment";
class RelativePeriod {
export class RelativePeriod {
periodType: DefaultPeriodType;
private _period: IPeriod;
get period(): IPeriod {
return this._period;
}
public constructor(periodType: DefaultPeriodType, period: IPeriod) {
console.debug("RelativePeriod constructor start,preiodType:",periodType);
this.periodType = periodType;
this._period = period;
console.debug(period.dateStart+"~"+period.dateEnd);
}
}
export class RelativeReriodHelper {
export class RelativePeriodHelper {
private _relativePeriods: RelativePeriod[] = [];
private _baseMoment: moment.Moment;
get baseMoment(){
get baseMoment() {
return moment(this._baseMoment);
}
public getPeriod(periodType: DefaultPeriodType): IPeriod {
console.debug("RelativeReriodHelper getPeriod start");
let result: IPeriod;
console.log("input preiodType",periodType);
for (const key in this._relativePeriods) {
if (this._relativePeriods.hasOwnProperty(key)) {
console.debug("key",key);
let relativePeriod = this._relativePeriods[key];
console.debug(relativePeriod.periodType);
if (relativePeriod.periodType == periodType) {
result = relativePeriod.period;
console.debug("period found",result.dateStart+"~"+result.dateEnd);
}
for (const relativePeriod of this._relativePeriods) {
if (relativePeriod.periodType == periodType) {
result = relativePeriod.period;
}
}
return result;
}
public constructor(relativeToday: boolean,firstDayOfWeek:number) {
console.debug("RelativePeriod helper constructor start");
moment.locale("cn",{
week:{
dow:firstDayOfWeek,
doy:7
public constructor(relativeToday: boolean, firstDayOfWeek: number) {
moment.locale("cn", {
week: {
dow: firstDayOfWeek,
doy: 7
}
});
this._baseMoment = relativeToday ? moment() : moment().subtract(1, "day");
this._relativePeriods.push(this.getLastWeek(), this.getLastMonth(), this.getLastEntireWeek(), this.getLastEntireMonth());
console.debug("this._baseMoment:" + this.baseMoment.format());
console.debug("RelativePeriodHelper constuctor end");
}
private getLastWeek(): RelativePeriod {
const start: Date = this.baseMoment.subtract(6, "days").startOf("day").toDate();

View File

@ -28,10 +28,12 @@
import { dataViewObjectsParser } from "powerbi-visuals-utils-dataviewutils";
import DataViewObjectsParser = dataViewObjectsParser.DataViewObjectsParser;
import {PeriodSettings} from "./datePeriod/periodSetting";
import { DatePickerSetting } from "./datePeriod/datePickerSetting";
import { PeriodSetting } from "./datePeriod/periodSetting";
export class VisualSettings extends DataViewObjectsParser {
public period: PeriodSettings = new PeriodSettings();
}
public datePickers: DatePickerSetting = new DatePickerSetting();
public period: PeriodSetting = new PeriodSetting();
}

View File

@ -40,22 +40,25 @@ import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import ISelectionId = powerbi.extensibility.ISelectionId;
import * as d3 from "d3";
type Selection<T extends d3.BaseType> = d3.Selection<T, any, any, any>;
import { VisualSettings } from "./settings/settings";
import { stratify } from "d3";
import { VisualSettings } from "./settings/visualSettings";
import { stratify, rgb } from "d3";
import * as models from 'powerbi-models';
import { IAdvancedFilter } from "powerbi-models";
import IVisualEventService=powerbi.extensibility.IVisualEventService;
//custom
import { IPeriod, Period, DefaultPeriodType } from "./settings/datePeriod/datePeriod";
import { RelativeReriodHelper } from "./settings/datePeriod/relativePeriodHelper";
import { IPeriod, Period, DefaultPeriodType,OrientationType } from "./settings/datePeriod/datePeriod";
import { RelativePeriodHelper } from "./settings/datePeriod/relativePeriodHelper";
import { IPeriodSelectorManager, PeriodSelectorManager } from "./settings/datePeriod/periodSelectorManager";
//third party
import * as moment from "moment";
export class Visual implements IVisual {
//pbi
private host: IVisualHost;
private settings: VisualSettings;
private category: powerbi.DataViewCategoryColumn;
private selectionManager: powerbi.extensibility.ISelectionManager;
private events: IVisualEventService;
//others
private container: Selection<HTMLElement>;
@ -63,25 +66,24 @@ export class Visual implements IVisual {
constructor(options: VisualConstructorOptions) {
//pbi
//console.log('Visual constructor', options);
console.debug("visual constructor start");
this.host = options.host;
this.selectionManager=this.host.createSelectionManager();
this.selectionManager = this.host.createSelectionManager();
this.events = options.host.eventService;
//others
this.container = d3.select(options.element).classed("container", true);
this.container = d3.select(options.element).classed("container", true).append("div");
if (document) {
const dateSelector_Start = this.container.append("input")
.attr("type", "date")
.style("margin", "2px 10px 2px 2px");
.style("margin", "4px");
const dateSelector_End = this.container.append("input")
.attr("type", "date")
.style("margin", "2px 0px 0px 2px");
.style("margin", "4px");
dateSelector_Start.on("input change", () => { this.filterPeriod(); });
dateSelector_End.on("input change", () => { this.filterPeriod(); });
this.periodSelectorManager = new PeriodSelectorManager(dateSelector_Start, dateSelector_End);
//Select datePeriod when click this button
this.container.on('contextmenu', () => {
const mouseEvent: MouseEvent = d3.event as MouseEvent;
const mouseEvent: MouseEvent = <MouseEvent>d3.event;
//const eventTarget: EventTarget = mouseEvent.target;
//let dataPoint = d3.select(eventTarget).datum();
this.selectionManager.showContextMenu({}, {
@ -93,53 +95,66 @@ export class Visual implements IVisual {
}
}
public update(options: VisualUpdateOptions) {
console.debug("update start");
//pbi
this.events.renderingStarted(options);
this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]);
let width: number = options.viewport.width;
if(this.settings.datePickers.backgroundTransparency<0||this.settings.datePickers.backgroundTransparency>1){
this.settings.datePickers.backgroundTransparency=0;
}
let backgroundColor=d3.rgb(this.settings.datePickers.backgroundColor).rgb();
let backgroundColorWithTransparency=rgb(backgroundColor.r,backgroundColor.g,backgroundColor.b,1-this.settings.datePickers.backgroundTransparency).toString();
//Set style for these date-pickers one-by-one, but not group by class
let datePickerWidth:number=(this.settings.datePickers.orientationType==OrientationType.Horizontal)?width/2-8-4*this.settings.datePickers.borderWidth:width-8-2*this.settings.datePickers.borderWidth;
this.periodSelectorManager.dateSelector_Start
.style("width", datePickerWidth + "px")
.style("font-size",this.settings.datePickers.fontSize+"px")
.style("color",this.settings.datePickers.fontColor)
.style("background-color",backgroundColorWithTransparency)
.style("border-width",this.settings.datePickers.borderWidth+"px")
.style("border-color",this.settings.datePickers.borderColor)
.style("outline-color",this.settings.datePickers.outlineColor)
.style("display", (this.settings.datePickers.orientationType==OrientationType.Horizontal)?"inline":"block");
this.periodSelectorManager.dateSelector_End
.style("width", datePickerWidth+"px")
.style("font-size",this.settings.datePickers.fontSize+"px")
.style("color",this.settings.datePickers.fontColor)
.style("background-color",backgroundColorWithTransparency)
.style("border-width",this.settings.datePickers.borderWidth+"px")
.style("border-color",this.settings.datePickers.borderColor)
.style("display", (this.settings.datePickers.orientationType==OrientationType.Horizontal)?"inline":"block");
let dataView = options.dataViews[0];
console.debug("dataView", dataView);
//set date series
this.category = dataView.categorical.categories[0];
//set new default period
let newDefaultPeriod: IPeriod = new Period();
if (this.settings.period.defaultPeriodType == DefaultPeriodType.Custom) {
console.debug("user select custom defaultPeriod");
dataView.categorical.values.map((messure: powerbi.DataViewValueColumn, index: number) => {
console.debug("1");
console.debug(messure.values[0]);
console.debug("2");
let messureDate: Date = moment(messure.values[0].toString()).startOf("day").toDate();
console.debug("messureDate", messureDate);
if (messure.source.roles["StartDate"]) {
newDefaultPeriod.dateStart = messureDate;
dataView.categorical.values.map((measure: powerbi.DataViewValueColumn, index: number) => {
let measureDate: Date = moment(measure.values[0].toString()).startOf("day").toDate();
if (measure.source.roles["StartDate"]) {
newDefaultPeriod.dateStart = measureDate;
}
if (messure.source.roles["EndDate"]) {
newDefaultPeriod.dateEnd = messureDate;
if (measure.source.roles["EndDate"]) {
newDefaultPeriod.dateEnd = measureDate;
}
});
} else {
console.debug("user select " + this.settings.period.defaultPeriodType.toString() + "\ defaultPeriod");
console.debug("firstDayOfWeek", this.settings.period.firstDayOfWeek);
let relativePeriodHelper: RelativeReriodHelper = new RelativeReriodHelper(this.settings.period.relativeToday, this.settings.period.firstDayOfWeek);
let relativePeriodHelper: RelativePeriodHelper = new RelativePeriodHelper(this.settings.period.relativeToday, this.settings.period.firstDayOfWeek);
newDefaultPeriod = relativePeriodHelper.getPeriod(this.settings.period.defaultPeriodType);
}
this.periodSelectorManager.defaultPeriod = newDefaultPeriod;
console.debug("update end");
this.events.renderingFinished(options);
}
private filterPeriod() {
//determine period from dateSelectors
console.debug("filter start");
let period: IPeriod = this.periodSelectorManager.period;
let target: models.IFilterColumnTarget;
try {
target = {
table: this.category.source.queryName.substr(0, this.category.source.queryName.indexOf('.')), // table
column: this.category.source.displayName // col1
};
}
catch (e) {
console.log(e);
}
target = {
table: this.category.source.queryName.substr(0, this.category.source.queryName.indexOf('.')), // table
column: this.category.source.displayName // col1
};
//filter
let conditions: models.IAdvancedFilterCondition[] = [];
if (period.dateStart) {
@ -158,8 +173,8 @@ export class Visual implements IVisual {
}
);
}
let filter: IAdvancedFilter = {
// tslint:disable-next-line: no-http-string
"$schema": "http://powerbi.com/product/schema#advanced",
"target": target,
"filterType": models.FilterType.Advanced,
@ -167,7 +182,7 @@ export class Visual implements IVisual {
"conditions": conditions
};
this.host.applyJsonFilter((period.dateStart || period.dateEnd) ? filter : null, "general", "filter", powerbi.FilterAction.merge);
console.debug("applyFilter end");
}
private static parseSettings(dataView: DataView): VisualSettings {
return <VisualSettings>VisualSettings.parse(dataView);

View File

@ -1,21 +1,21 @@
{
"Role_Dates_DisplayName":"日期序列",
"Role_Dates_Discription":"请放置日期列",
"Role_Dates_Description":"请放置日期列",
"Role_StartDate_DisplayName":"默认开始日期",
"Role_StartDate_Discription":"可以使用度量值指定切片器的默认开始日期",
"Role_StartDate_Description":"可以使用度量值指定切片器的默认开始日期",
"Role_DefaultEndDate_DisplayName":"默认结束日期",
"Role_DefaultEndDate_Discription":"可以使用度量值指定切片器的默认结束日期",
"Role_DefaultEndDate_Description":"可以使用度量值指定切片器的默认结束日期",
"Obj_Period_DisplayName":"日期段",
"Obj_Period_Discription":"日期段选项",
"Obj_Period_Description":"日期段选项",
"Period_DefaultPeriodType_DisplayName":"默认日期段",
"Period_DefaultPeriodType_Discription":"选择如何确定切片器日期首尾默认值",
"Period_DefaultPeriodType_Description":"选择如何确定切片器日期首尾默认值",
"LastMonth":"最近一个月",
"LastEntireMonth":"最近一个完整月",
"LastWeek":"最近一周",
"LastEntireWeek":"最近一个完整周",
"Custom":"自定义(根据度量值)",
"Period_RelativeToday_DisplayName":"包含今天",
"Period_RelativeToday_Discription":"当默认日期项没有选择自定义时,此选项用于确定相对日期是否包含今日",
"Period_RelativeToday_Description":"当默认日期项没有选择自定义时,此选项用于确定相对日期是否包含今日",
"Period_FirstDayOfWeek_DisplayName":"一周的第一天",
"Sunday":"星期天",
"Monday":"星期一",
@ -23,5 +23,25 @@
"Wednesday":"星期三",
"Thursday":"星期四",
"Friday":"星期五",
"Saturday":"星期六"
"Saturday":"星期六",
"DatePickers_Orientation_DisplayName":"方向",
"DatePickers_Orientation_Description":"设置日期选择器的排列方向",
"Horizontal":"水平",
"Vertical":"垂直",
"Obj_DatePickers_DisplayName":"日期选择器外观",
"Obj_DatePickers_Description":"设置两个日期选择器的外观",
"DatePickers_FontSize_DisplayName":"字体",
"DatePickers_FontSize_Description":"设置字体大小单位px无大小限制但请注意保持合适",
"DatePickers_FontColor_DisplayName":"字体颜色",
"DatePickers_FontColor_Description":"设置字体颜色",
"DatePickers_BackgroundColor_DisplayName":"背景色",
"DatePickers_BackgroundColor_Description":"设置背景色",
"DatePickers_BackgroundTransparency_DisplayName":"背景透明度",
"DatePickers_BackgroundTransparency_Description":"设置背景透明度",
"DatePickers_BorderWidth_DisplayName":"边框宽度",
"DatePickers_BorderWidth_Description":"设置边框的宽度",
"DatePickers_BorderColor_DisplayName":"边框颜色",
"DatePickers_BorderColor_Description":"设置常规状态下边框的颜色",
"DatePickers_OutlineColor_DisplayName":"轮廓颜色",
"DatePickers_OutlineColor_Description":"设置选中状态下日期选择器的边缘颜色"
}

View File

@ -2,22 +2,22 @@
"locale":"zh-CN",
"values":{
"Role_Dates_DisplayName":"日期序列",
"Role_Dates_Discription":"请放置日期列",
"Role_Dates_Description":"请放置日期列",
"Role_StartDate_DisplayName":"默认开始日期",
"Role_StartDate_Discription":"可以使用度量值指定切片器的默认开始日期",
"Role_StartDate_Description":"可以使用度量值指定切片器的默认开始日期",
"Role_DefaultEndDate_DisplayName":"默认结束日期",
"Role_DefaultEndDate_Discription":"可以使用度量值指定切片器的默认结束日期",
"Role_DefaultEndDate_Description":"可以使用度量值指定切片器的默认结束日期",
"Obj_Period_DisplayName":"日期段",
"Obj_Period_Discription":"日期段选项",
"Obj_Period_Description":"日期段选项",
"Period_DefaultPeriodType_DisplayName":"默认日期段",
"Period_DefaultPeriodType_Discription":"选择如何确定切片器日期首尾默认值",
"Period_DefaultPeriodType_Description":"选择如何确定切片器日期首尾默认值",
"LastMonth":"最近一个月",
"LastEntireMonth":"最近一个完整月",
"LastWeek":"最近一周",
"LastEntireWeek":"最近一个完整周",
"Custom":"自定义(根据度量值)",
"Period_RelativeToday_DisplayName":"包含今天",
"Period_RelativeToday_Discription":"当默认日期项没有选择自定义时,此选项用于确定相对日期是否包含今日",
"Period_RelativeToday_Description":"当默认日期项没有选择自定义时,此选项用于确定相对日期是否包含今日",
"Period_FirstDayOfWeek_DisplayName":"一周的第一天",
"Sunday":"星期天",
"Monday":"星期一",

219
test.webpack.config.js Normal file
View File

@ -0,0 +1,219 @@
const path = require('path');
const fs = require("fs");
// werbpack plugin
const webpack = require("webpack");
const PowerBICustomVisualsWebpackPlugin = require('powerbi-visuals-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const Visualizer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
// api configuration
const powerbiApi = require("powerbi-visuals-api");
// visual configuration json path
const pbivizPath = "./pbiviz.json";
const pbivizFile = require(path.join(__dirname, pbivizPath));
// the visual capabilities content
const capabilitiesPath = "./capabilities.json";
const capabilitiesFile = require(path.join(__dirname, capabilitiesPath));
const pluginLocation = './.tmp/precompile/visualPlugin.ts'; // path to visual plugin file, the file generates by the plugin
// string resources
const resourcesFolder = path.join(".","stringResources");
const localizationFolders = fs.existsSync(resourcesFolder) && fs.readdirSync(resourcesFolder);
const statsLocation = "../../webpack.statistics.html";
// babel options to support IE11
let babelOptions = {
"presets": [
[
require.resolve('@babel/preset-env'),
{
"targets": {
"ie": "11"
},
useBuiltIns: "entry",
corejs: 3,
modules: false
}
]
],
sourceType: "unambiguous", // tell to babel that the project can contains different module types, not only es2015 modules
cacheDirectory: path.join(".tmp", "babelCache") // path for chace files
};
module.exports = {
entry: {
"visual.js": pluginLocation
},
optimization: {
concatenateModules: false,
minimize: true // enable minimization for create *.pbiviz file less than 2 Mb, can be disabled for dev mode
},
devtool: 'source-map',
mode: "development",
module: {
rules: [
{
parser: {
amd: false
}
},
{
test: /(\.ts)x|\.ts$/,
include: /powerbi-visuals-|src|precompile\\visualPlugin.ts/,
use: [
{
loader: require.resolve('babel-loader'),
options: babelOptions
},
{
loader: require.resolve('ts-loader'),
options: {
transpileOnly: false,
experimentalWatchApi: false
}
}
]
},
{
test: /(\.js)x|\.js$/,
use: [
{
loader: require.resolve('babel-loader'),
options: babelOptions
}
]
},
{
test: /\.json$/,
loader: require.resolve('json-loader'),
type: "javascript/auto"
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: require.resolve('css-loader')
},
{
loader: require.resolve('less-loader'),
options: {
paths: [path.resolve(__dirname, "..", 'node_modules')]
}
}
]
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: require.resolve('css-loader')
}
]
},
{
test: /\.(woff|ttf|ico|woff2|jpg|jpeg|png|webp)$/i,
use: [
{
loader: 'base64-inline-loader'
}
]
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '.css']
},
output: {
path: path.join(__dirname, "/.tmp","drop"),
publicPath: 'assets',
filename: "[name]",
},
devServer: {
disableHostCheck: true,
contentBase: path.join(__dirname, ".tmp", "drop"), // path with assets for dev server, they are generated by webpack plugin
compress: true,
port: 8080, // dev server port
hot: false,
inline: false,
// cert files for dev server
https: {
pfx: fs.readFileSync("C:\\Users\\littl\\AppData\\Roaming\\npm\\node_modules\\powerbi-visuals-tools\\certs\\PowerBICustomVisualTest_public.pfx"), // for windows
passphrase: "5573455193282877"
// keep it commented to use webpack generated certificate
// key: path.join(__dirname, "certs","PowerBICustomVisualTest_public.key"), // for darwin, linux
// cert: path.join(__dirname, "certs", "PowerBICustomVisualTest_public.cer"), // for darwin, linux
// pfx: fs.readFileSync(path.join(__dirname, "certs", "PowerBICustomVisualTest_public.pfx")), // for windows
// passphrase: "5031595470751755"
},
headers: {
"access-control-allow-origin": "*",
"cache-control": "public, max-age=0"
},
},
externals: {
"powerbi-visuals-api": 'null',
"fakeDefine": 'false',
"corePowerbiObject": "Function('return this.powerbi')()",
"realWindow": "Function('return this')()"
},
plugins: [
new MiniCssExtractPlugin({
filename: "visual.css",
chunkFilename: "[id].css"
}),
new Visualizer({
reportFilename: statsLocation,
openAnalyzer: false,
analyzerMode: `static`
}),
// visual plugin regenerates with the visual source, but it does not require relaunching dev server
new webpack.WatchIgnorePlugin([
path.join(__dirname, pluginLocation),
"./.tmp/**/*.*"
]),
// custom visuals plugin instance with options
new PowerBICustomVisualsWebpackPlugin({
...pbivizFile,
capabilities: capabilitiesFile,
stringResources: localizationFolders && localizationFolders.map(localization => path.join(
resourcesFolder,
localization,
"resources.resjson"
)),
apiVersion: powerbiApi.version,
capabilitiesSchema: powerbiApi.schemas.capabilities,
pbivizSchema: powerbiApi.schemas.pbiviz,
stringResourcesSchema: powerbiApi.schemas.stringResources,
dependenciesSchema: powerbiApi.schemas.dependencies,
devMode: false,
generatePbiviz: true,
generateResources: true,
modules: true,
visualSourceLocation: "../../src/visual",
pluginLocation: pluginLocation,
packageOutPath: path.join(__dirname, "dist")
}),
new ExtraWatchWebpackPlugin({
files: [
pbivizPath,
capabilitiesPath
]
}),
new webpack.ProvidePlugin({
//window: 'realWindow',//for global window.jquery
define: 'fakeDefine',
powerbi: 'corePowerbiObject'
}),
]
};

View File

@ -14,6 +14,7 @@
]
},
"files": [
"./src/visual.ts"
"./src/visual.ts",
"./src/settings/datePeriod/relativePeriodHelper.ts"
]
}

File diff suppressed because one or more lines are too long

67
webpack.statistics.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long