devexpress-reporting
Version:
DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.
199 lines (198 loc) • 10.1 kB
JavaScript
/**
* DevExpress HTML/JS Reporting (chart\_control.js)
* Version: 25.1.3
* Build date: Jun 26, 2025
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* License: https://www.devexpress.com/Support/EULAs/universal.xml
*/
import { DxDeferred, getFullPath } from '@devexpress/analytics-core/analytics-internal';
import { Disposable, ModelSerializer, PathRequest } from '@devexpress/analytics-core/analytics-utils';
import * as ko from 'knockout';
import { chart, ChartViewModel } from './components/models/_chart';
import { legend } from './components/models/_legend';
import { ScaleType, ScaleTypeMap, seriesTemplate } from './components/series/_template';
import { diagram } from './components/_diagram';
import { backImage, emptyChartText, legends, paletteName, seriesSerializable, smallChartText, titles } from './internal/meta/_chart';
import { chartDataSource, editorTemplates } from './internal/_editorTemplates';
import { _isDateTypeSpecific, _isNumericTypeSpecific } from './internal/_utils';
import { controlsFactory } from './_controlsFactory';
export class ChartControlViewModel extends Disposable {
getInfo() {
return chartControlSerializationsInfo;
}
getControlFactory() {
return controlsFactory;
}
isSeriesPropertyDisabled(name) {
if (!this.dataSource()) {
return name === 'argumentDataMember' || name === 'valueDataMembers' || name === 'colorDataMember' || name === 'filterString';
}
}
isSeriesTemplatePropertyDisabled(name) {
if (!this.dataSource()) {
return name === 'argumentDataMember' || name === 'valueDataMembers' || name === 'valueScaleType' || name === 'filterString';
}
}
_getSeriesActualArgumentScaleType(argumentDataMember) {
const deffered = new DxDeferred();
if (this.fieldListProvider() && argumentDataMember) {
let seriesDataMember = this.getPath('seriesDataMember');
let argumentFieldName = argumentDataMember;
const argumentDataMemberPathComponents = argumentDataMember.split('.');
if (argumentDataMemberPathComponents.length > 1) {
argumentFieldName = argumentDataMemberPathComponents.pop();
argumentDataMemberPathComponents.splice(0, 0, seriesDataMember);
seriesDataMember = argumentDataMemberPathComponents.join('.');
}
this.fieldListProvider().getItems(new PathRequest(seriesDataMember))
.done((items) => {
const result = items.filter(item => item.name === argumentFieldName)[0];
let _scaleType = ScaleType.Numerical;
if (result && result.specifics) {
if (_isNumericTypeSpecific(result.specifics))
_scaleType = ScaleType.Numerical;
else if (_isDateTypeSpecific(result.specifics))
_scaleType = ScaleType.DateTime;
else
_scaleType = ScaleType.Qualitative;
}
deffered.resolve(_scaleType);
})
.fail(() => {
deffered.resolve(ScaleType.Numerical);
});
}
else {
deffered.resolve(ScaleType.Numerical);
}
return deffered.promise();
}
_initSeries(series) {
const seriesGetPath = series['getPath'].bind(series);
series['getPath'] = (propertyName) => {
if (propertyName === 'argumentDataMember' || propertyName === 'colorDataMember' || propertyName === 'summaryFunction') {
return seriesGetPath('seriesDataMember') || this.getPath('seriesDataMember');
}
};
series['isPropertyDisabled'] = (name) => {
if (series._isPropertyDisabled(name))
return true;
if (series._isDataMemberPropertyDisabled(name)) {
return this.isSeriesPropertyDisabled(name);
}
};
series._disposables.push(series.filterString.helper.parameters = ko.computed(() => {
return this.parameters && this.parameters();
}));
series.valueDataMembers()['getPath'] = (propertyName) => {
return seriesGetPath('seriesDataMember') || this.getPath('seriesDataMember');
};
series._disposables.push(series.valueDataMembers.subscribe((newVal) => {
newVal['getPath'] = (propertyName) => {
return seriesGetPath('seriesDataMember') || this.getPath('seriesDataMember');
};
}));
const updateSeriesActualArgumentScaleType = () => {
if (this.chart.dataContainer.seriesTemplate.argumentScaleType() !== 'Auto')
return;
this._getSeriesActualArgumentScaleType(series.argumentDataMember()).done((scaleType) => {
series._actualArgumentScaleType(scaleType);
});
};
updateSeriesActualArgumentScaleType();
series._disposables.push(series.argumentDataMember.subscribe(updateSeriesActualArgumentScaleType), this.fieldListProvider.subscribe(updateSeriesActualArgumentScaleType));
series._disposables.push(series.argumentScaleType.subscribe((newVal) => {
if (newVal !== 'Auto' && newVal !== 'Qualitative')
this._getSeriesActualArgumentScaleType(series.argumentDataMember()).done((scaleType) => {
if (scaleType !== ScaleTypeMap[newVal])
series.argumentDataMember('');
});
series._actualArgumentScaleType(newVal == 'Auto' ? ScaleType.Numerical : ScaleTypeMap[newVal]);
}));
}
_initChartElementFunctions() {
const seriesTemplate = this.chart.dataContainer.seriesTemplate;
const seriesTemplateGetPath = seriesTemplate['getPath'].bind(seriesTemplate);
this._initSeries(seriesTemplate);
this.chart.dataContainer.series().forEach(series => this._initSeries(series));
this._disposables.push(this.chart.dataContainer.series.subscribe((args) => {
if (args[0].status === 'added') {
this._initSeries(args[0].value);
}
}, null, 'arrayChange'));
seriesTemplate['getPath'] = (propertyName) => {
return seriesTemplateGetPath('seriesDataMember') || this.getPath('seriesDataMember');
};
seriesTemplate['isPropertyDisabled'] = (name) => {
if (seriesTemplate._isPropertyDisabled(name))
return true;
if (seriesTemplate._isDataMemberPropertyDisabled(name)) {
return this.isSeriesTemplatePropertyDisabled(name);
}
};
this._disposables.push(seriesTemplate.filterString.helper.parameters = ko.computed(() => {
return this.parameters && this.parameters();
}));
seriesTemplate.valueDataMembers()['getPath'] = (propertyName) => {
return seriesTemplateGetPath('seriesDataMember') || this.getPath('seriesDataMember');
};
this._disposables.push(seriesTemplate.valueDataMembers.subscribe((newValue) => {
newValue['getPath'] = (propertyName) => {
return seriesTemplateGetPath('seriesDataMember') || this.getPath('seriesDataMember');
};
}));
this._disposables.push(seriesTemplate.argumentDataMember.subscribe((newValue) => {
if (seriesTemplate.argumentScaleType() !== 'Auto')
return;
this._getSeriesActualArgumentScaleType(newValue).done((scaleType) => {
seriesTemplate._actualArgumentScaleType(scaleType);
});
}));
}
constructor(options) {
super();
this.fieldListProvider = ko.observable(null);
this.chart = options.chart ? options.chart : new ChartViewModel(options.chartSource, new ModelSerializer());
this.dataSource = options.dataSource;
this.parameters = options.parameters;
this._initChartElementFunctions();
['seriesDataMember', 'dataMember'].forEach((val) => {
this[val] = ko.computed({
read: () => {
return this.chart.dataContainer[val]();
}, write: (newVal) => {
this.chart.dataContainer[val](newVal);
}
});
});
}
getPath(propertyName) {
const dataSourceInfo = this.dataSource();
const dataSourceName = (dataSourceInfo && dataSourceInfo.data && (dataSourceInfo.id || dataSourceInfo.ref)) || '';
if (propertyName === 'seriesDataMember' || propertyName === 'valueDataMembers' || propertyName === 'colorDataMember') {
return getFullPath(dataSourceName, this.chart.dataContainer.dataMember());
}
else if (propertyName === 'dataMember') {
return dataSourceName;
}
}
serialize() {
return (new ModelSerializer()).serialize(this);
}
save() {
const data = this.serialize();
if (this.onSave) {
this.onSave(data);
}
return data;
}
isPropertyDisabled(name) {
return !this.dataSource() && (name === 'seriesDataMember' || name === 'dataMember');
}
}
export const chartDataMember = { propertyName: 'dataMember', displayName: 'Data Member', defaultVal: '', editor: editorTemplates.getEditor('dataMemberChart'), localizationId: 'DevExpress.XtraReports.UI.XRSparkline.DataMember' };
export const chartSeriesDataMember = { propertyName: 'seriesDataMember', displayName: 'Series Data Member', defaultVal: '', editor: editorTemplates.getEditor('fieldChart'), localizationId: 'DevExpress.XtraReports.UI.XRChart.SeriesDataMember' };
export const fakeChartSerializationInfo = [
chartDataSource, chartDataMember, chartSeriesDataMember, paletteName, seriesTemplate, seriesSerializable, diagram, titles, legend, legends, emptyChartText, smallChartText, backImage
];
export const chartControlSerializationsInfo = [chart];