@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,727 lines (1,726 loc) • 71.2 kB
JavaScript
const require_kendo_licensing = require('./kendo.licensing-B1rACieL.js');
let _progress_kendo_charts = require("@progress/kendo-charts");
//#region ../src/kendo.chartwizard.js
const __meta__ = {
id: "chartwizard",
name: "ChartWizard",
category: "web",
description: "The ChartWizard allows configuration and visual representation of various charts",
depends: [
"core",
"icons",
"html.icon",
"grid",
"expansionpanel",
"window",
"form",
"tabstrip",
"dataviz.chart",
"splitter",
"dropdownbutton",
"colorpicker"
]
};
(function($) {
const kendo = window.kendo, Widget = kendo.ui.Widget, DataSource = kendo.data.DataSource, keys = kendo.keys, fontSizes = _progress_kendo_charts.ChartWizardCommon.fontSizes, fontNames = _progress_kendo_charts.ChartWizardCommon.fontNames, isCategorical = _progress_kendo_charts.ChartWizardCommon.isCategorical, updateState = _progress_kendo_charts.ChartWizardCommon.updateState, mergeStates = _progress_kendo_charts.ChartWizardCommon.mergeStates, actionTypes = _progress_kendo_charts.ChartWizardCommon.ActionTypes, getWizardDataFromDataRows = _progress_kendo_charts.ChartWizardCommon.getWizardDataFromDataRows, NS = ".kendoChartWizard", ui = kendo.ui, extend = $.extend, deepExtend = kendo.deepExtend, RESIZING = "resizing", RESIZE = "resize", MAXIMIZE = "maximize", RESTORE = "restore", CLICK = "click", KEYDOWN = "keydown", OPEN = "open", CLOSE = "close", ACTIVATE = "activate", CHANGE = "change", DATA_BINGING = "dataBinding", DATA_BOUND = "dataBound", EXPORT_PDF = "exportPDF", EXPORT_SVG = "exportSVG", EXPORT_IMAGE = "exportImage", ICON_SIZE = "xlarge", CHART = "chart", DATA = "data", FORMAT = "format", DOT = ".", REF = "ref", REF_SELECTOR = "ref*=", DATA_ACTION = "data-action", DATA_ACTION_SELECTOR = "[data-action]", DATA_ROLE = "data-role", DATA_ROLE_SELECTOR = "data-role=", DATA_CHART_TYPE_ATTR = "data-chart-type", SELECTED_STATE = "k-selected", FILL_MODE_OUTLINE = "outline", FILL_MODE_FLAT = "flat", STACKED = "stacked", INITIAL_TYPE = "bar", HUNDRED_STACKED = "hundredstacked", REG_EXP_CAPITAL = /(?=[A-Z])/;
const cssClasses = {
chartWizard: "k-chart-wizard",
previewPane: "k-chart-wizard-preview-pane",
previewPaneHeader: "k-preview-pane-header",
previewPaneContent: "k-preview-pane-content",
propertyPane: "k-chart-wizard-property-pane",
splitter: "k-chart-wizard-splitter",
expansionPanelWrapper: "k-expander",
cols2gap4: "k-grid-cols-2 k-gap-x-4",
colSpan2: "k-col-span-2"
};
const inputRoles = {
numericTextBox: "numerictextbox",
colorPicker: "colorpicker",
textBox: "textbox",
comboBox: "combobox",
checkBox: "checkbox",
dropDownList: "dropdownlist",
switch: "switch"
};
const exportButtonOptions = {
icon: "export",
fillMode: FILL_MODE_FLAT,
items: [
{
id: "export-pdf",
icon: "file-pdf"
},
{
id: "export-svg",
icon: "file"
},
{
id: "export-png",
icon: "file-image"
}
]
};
const expansionPanelForChart = {
bar: { content: {
bar: "chart-bar-clustered",
stackedBar: "chart-bar-stacked",
hundredStackedBar: "chart-bar-stacked100"
} },
pie: { content: { pie: "chart-pie" } },
column: { content: {
column: "chart-column-clustered",
stackedColumn: "chart-column-stacked",
hundredStackedColumn: "chart-column-stacked100"
} },
line: { content: {
line: "chart-line",
stackedLine: "chart-line-stacked",
hundredStackedLine: "chart-line-stacked100"
} },
scatter: { content: { scatter: "chart-scatter" } }
};
const dataTabPanel = (messages) => [
{
legend: messages.configuration.categoryAxis,
editors: {
id: "category-axis",
role: inputRoles.dropDownList,
action: "categoryAxisX"
}
},
{
legend: messages.configuration.valueAxis,
editors: {
id: "value-axis",
role: inputRoles.dropDownList,
action: "valueAxisY"
}
},
{
legend: messages.configuration.series.title,
editors: { custom: `<div class="k-grid" ${DATA_ACTION}="seriesChange"></div>` }
}
];
const chartAreaPanel = (messages) => [{
legend: messages.chartArea.margins.default,
layoutClass: cssClasses.cols2gap4,
editors: [
{
label: {
text: messages.chartArea.margins.left,
for: "left"
},
field: {
id: "left",
role: inputRoles.numericTextBox,
placeholder: messages.chartArea.margins.auto,
action: "areaMarginLeft"
}
},
{
label: {
text: messages.chartArea.margins.right,
for: "right"
},
field: {
id: "right",
role: inputRoles.numericTextBox,
placeholder: messages.chartArea.margins.auto,
action: "areaMarginRight"
}
},
{
label: {
text: messages.chartArea.margins.top,
for: "top"
},
field: {
id: "top",
role: inputRoles.numericTextBox,
placeholder: messages.chartArea.margins.auto,
action: "areaMarginTop"
}
},
{
label: {
text: messages.chartArea.margins.bottom,
for: "bottom"
},
field: {
id: "bottom",
role: inputRoles.numericTextBox,
placeholder: messages.chartArea.margins.auto,
action: "areaMarginBottom"
}
}
]
}, {
legend: messages.chartArea.background.default,
editors: [{
label: {
text: messages.chartArea.background.color,
for: "background"
},
field: {
id: "background",
role: inputRoles.colorPicker,
action: "areaBackground"
}
}]
}];
const titlePanel = (messages) => [{
layoutClass: cssClasses.cols2gap4,
editors: [
{
label: {
text: messages.title.applyTo,
for: "apply-to-title"
},
field: {
id: "apply-to-title",
role: inputRoles.dropDownList,
action: "activateTitle"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.title.label,
for: "title-text"
},
field: {
id: "title-text",
role: inputRoles.textBox,
action: "titleText"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.title.font,
for: "title-font"
},
field: {
id: "title-font",
role: inputRoles.comboBox,
placeholder: messages.title.fontPlaceholder,
action: "titleFontName"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.title.size,
for: "title-size"
},
field: {
id: "title-size",
role: inputRoles.comboBox,
placeholder: messages.title.sizePlaceholder,
action: "titleFontSize"
}
},
{
label: {
text: messages.title.color,
for: "title-color"
},
field: {
id: "title-color",
role: inputRoles.colorPicker,
action: "titleColor"
}
}
]
}];
const seriesPanel = (messages) => [{ editors: [
{
label: {
text: messages.series.applyTo,
for: "apply-to-series"
},
field: {
id: "apply-to-series",
role: inputRoles.dropDownList,
action: "activateSeries"
}
},
{
label: {
text: messages.series.color,
for: "series-color"
},
field: {
id: "series-color",
role: inputRoles.colorPicker,
action: "seriesColor"
}
},
{ field: {
id: "show-labels",
type: "checkbox",
role: inputRoles.checkBox,
action: "seriesLabel"
} }
] }];
const legendPanel = (messages) => [{
layoutClass: cssClasses.cols2gap4,
editors: [
{
nowrap: true,
label: {
text: messages.legend.showLegend,
for: "show-legend"
}
},
{
nowrap: true,
field: {
id: "show-legend",
role: inputRoles.switch,
action: "legendVisible"
}
},
{
label: {
text: messages.legend.font,
for: "legend-font"
},
field: {
id: "legend-font",
placeholder: messages.legend.fontPlaceholder,
role: inputRoles.comboBox,
action: "legendFontName"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.legend.size,
for: "legend-size"
},
field: {
id: "legend-size",
role: inputRoles.comboBox,
placeholder: messages.legend.sizePlaceholder,
action: "legendFontSize"
}
},
{
label: {
text: messages.title.color,
for: "legend-color"
},
field: {
id: "legend-color",
role: inputRoles.colorPicker,
action: "legendColor"
}
},
{
label: {
text: messages.legend.position.default,
for: "legend-position"
},
field: {
id: "legend-position",
role: inputRoles.dropDownList,
action: "legendPosition"
},
className: cssClasses.colSpan2
}
]
}];
const categoryAxisPanel = (messages) => [{
legend: messages.categoryAxis.title.text,
layoutClass: cssClasses.cols2gap4,
editors: [
{
field: {
id: "category-axis-title",
role: inputRoles.textBox,
placeholder: messages.categoryAxis.title.placeholder,
action: "categoryAxisTitleText"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.categoryAxis.title.font,
for: "category-axis-title-font"
},
field: {
id: "category-axis-title-font",
role: inputRoles.comboBox,
placeholder: messages.categoryAxis.title.fontPlaceholder,
action: "categoryAxisTitleFontName"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.categoryAxis.title.size,
for: "category-axis-title-size"
},
field: {
id: "category-axis-title-size",
role: inputRoles.comboBox,
placeholder: messages.categoryAxis.title.sizePlaceholder,
action: "categoryAxisTitleFontSize"
}
},
{
label: {
text: messages.categoryAxis.title.color,
for: "category-axis-title-color"
},
field: {
id: "category-axis-title-color",
role: inputRoles.colorPicker,
action: "categoryAxisTitleColor"
}
}
]
}, {
layoutClass: cssClasses.cols2gap4,
legend: messages.categoryAxis.labels.text,
editors: [
{
label: {
text: messages.categoryAxis.labels.font,
for: "category-axis-labels-font"
},
field: {
id: "category-axis-labels-font",
role: inputRoles.comboBox,
placeholder: messages.categoryAxis.labels.fontPlaceholder,
action: "categoryAxisLabelsFontName"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.categoryAxis.labels.size,
for: "category-axis-labels-size"
},
field: {
id: "category-axis-labels-size",
role: inputRoles.comboBox,
placeholder: messages.categoryAxis.labels.sizePlaceholder,
action: "categoryAxisLabelsFontSize"
}
},
{
label: {
text: messages.categoryAxis.labels.color,
for: "category-axis-labels-color"
},
field: {
id: "category-axis-labels-color",
role: inputRoles.colorPicker,
action: "categoryAxisLabelsColor"
}
},
{
label: {
text: messages.categoryAxis.labels.rotation.text,
for: "category-axis-labels-rotation"
},
field: {
id: "category-axis-labels-rotation",
role: inputRoles.numericTextBox,
placeholder: messages.categoryAxis.labels.rotation.auto,
action: "categoryAxisLabelsRotation"
}
},
{
field: {
id: "category-axis-labels-reverse-order",
role: inputRoles.checkBox,
action: "categoryAxisReverseOrder"
},
className: cssClasses.colSpan2
}
]
}];
const valueAxisPanel = (messages) => [{
legend: messages.valueAxis.title.text,
layoutClass: cssClasses.cols2gap4,
editors: [
{
field: {
id: "value-axis-title",
role: inputRoles.textBox,
placeholder: messages.valueAxis.title.placeholder,
action: "valueAxisTitleText"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.categoryAxis.title.font,
for: "value-axis-title-font"
},
field: {
id: "value-axis-title-font",
role: inputRoles.comboBox,
placeholder: messages.valueAxis.title.fontPlaceholder,
action: "valueAxisTitleFontName"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.valueAxis.title.size,
for: "value-axis-title-size"
},
field: {
id: "value-axis-title-size",
role: inputRoles.comboBox,
placeholder: messages.valueAxis.title.sizePlaceholder,
action: "valueAxisTitleFontSize"
}
},
{
label: {
text: messages.valueAxis.title.color,
for: "value-axis-title-color"
},
field: {
id: "value-axis-title-color",
role: inputRoles.colorPicker,
action: "valueAxisTitleColor"
}
}
]
}, {
layoutClass: cssClasses.cols2gap4,
legend: messages.valueAxis.labels.text,
editors: [
{
label: {
text: messages.valueAxis.labels.labelFormat.default,
for: "value-axis-label-format"
},
field: {
id: "value-axis-label-format",
role: inputRoles.dropDownList,
action: "valueAxisLabelsFormat"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.valueAxis.labels.font,
for: "value-axis-label-font"
},
field: {
id: "value-axis-label-font",
role: inputRoles.comboBox,
placeholder: messages.valueAxis.labels.fontPlaceholder,
action: "valueAxisLabelsFontName"
},
className: cssClasses.colSpan2
},
{
label: {
text: messages.valueAxis.labels.size,
for: "value-axis-label-size"
},
field: {
id: "value-axis-label-size",
role: inputRoles.comboBox,
placeholder: messages.valueAxis.labels.sizePlaceholder,
action: "valueAxisLabelsFontSize"
}
},
{
label: {
text: messages.valueAxis.labels.color,
for: "value-axis-labels-color"
},
field: {
id: "value-axis-labels-color",
role: inputRoles.colorPicker,
action: "valueAxisLabelsColor"
}
},
{
label: {
text: messages.valueAxis.labels.rotation.text,
for: "value-axis-labels-rotation"
},
field: {
id: "value-axis-labels-rotation",
role: inputRoles.numericTextBox,
placeholder: messages.valueAxis.labels.rotation.auto,
action: "valueAxisLabelsRotation"
}
}
]
}];
function createState(data, seriesType) {
return _progress_kendo_charts.ChartWizardCommon.createState(data, seriesType);
}
function createInitialStateInstance(data, seriesType, defaultState, stateObject) {
var state = createState(data, defaultState && defaultState.seriesType || seriesType);
if (stateObject) {
state = deepExtend({}, state, stateObject);
}
return typeof (defaultState && defaultState.stack) !== "undefined" ? updateState(state, actionTypes.stacked, defaultState.stack) : state;
}
function getFormatPanels() {
return [
{
ref: "chartarea",
getData: chartAreaPanel
},
{
ref: "title",
getData: titlePanel
},
{
ref: "series",
getData: seriesPanel
},
{
ref: "legend",
getData: legendPanel
},
{
ref: "categoryaxis",
getData: categoryAxisPanel
},
{
ref: "valueaxis",
getData: valueAxisPanel
}
];
}
function getNewState({ state, data, type, action, change }) {
let newState = state;
if (data && type) {
newState = mergeStates(state, createState(data, type));
}
if (action && change !== null && change !== undefined) {
newState = updateState(newState, action, change);
}
newState.transitions = false;
return newState;
}
function prepareReorderedDataForGrid(grid, prevIndex, currentIndex) {
const data = grid.options.dataSource;
const item = data.splice(prevIndex, 1);
data.splice(currentIndex, 0, item[0]);
return data;
}
const templates = {
chartTypesWrapper: () => `<div class="k-chart-types-wrapper"></div>`,
iconTextItem: (iconWrapper, text, attribute) => `<div class="k-icon-text-wrapper" ${attribute ?? ""}>${iconWrapper}${kendo.htmlEncode(text)}</div>`,
iconWrapper: (icon, size) => `<div class="k-icon-background-area" tabindex="0">${kendo.ui.icon({
icon,
size
})}</div>`,
formElement: () => `<form class="k-form"></form>`,
formFieldSet: (legend, editorsBase) => `<fieldset class="k-form-fieldset">
${legend ? `<legend class="k-form-legend">${legend}</legend>` : ""}
${editorsBase}
</fieldset>`,
divContentWrapper: (ref) => `<div ref=${ref}></div>`,
formFieldWrap: (field) => `<div class="k-form-field-wrap">${field}</div>`,
formField: (content, className) => `<div class="k-form-field${className ? " " + className : ""}">
${content}
</div>`,
fieldContent: (label, field) => `
${label}
${field}`,
label: (text, editorId, className) => `<label for="${editorId}" class="k-label${className ? " " + className : ""}">${text}</label>`,
formGridLayout: (classes) => `<div class="k-form-layout k-d-grid${" " + classes}"></div>`,
inputBaseElement: (field) => `<input ${field.id ? `id="${field.id}"` : ""} ${DATA_ROLE}=${field.role} ${DATA_ACTION}=${field.action} ${field.type ? `type="${field.type}"` : ""} ${field.placeholder ? `placeholder="${kendo.htmlEncode(field.placeholder)}"` : ""}/>`
};
const legendPositions = (messages) => [
{
value: "bottom",
text: messages.position.bottom
},
{
value: "top",
text: messages.position.top
},
{
value: "left",
text: messages.position.left
},
{
value: "right",
text: messages.position.right
}
];
const labelFormats = (messages) => [
{
value: "",
text: messages.labels.labelFormat.text
},
{
value: "n0",
text: messages.labels.labelFormat.number
},
{
value: "c0",
text: messages.labels.labelFormat.currency
},
{
value: "p0",
text: messages.labels.labelFormat.percent
}
];
const titles = (messages) => [{
value: "title",
text: messages.format.title.chartTitle
}, {
value: "subtitle",
text: messages.format.title.chartSubtitle
}];
const commonOptions = {
colorPicker: {
fillMode: FILL_MODE_OUTLINE,
view: "gradient",
buttons: false,
format: "rgb",
opacity: true
},
comboBox: {
filter: "contains",
suggest: true,
dataTextField: "text",
dataValueField: "value"
},
numericTextBox: {
step: 1,
fillMode: FILL_MODE_OUTLINE
},
dropDownList: {
fillMode: FILL_MODE_OUTLINE,
animation: false,
dataTextField: "text",
dataValueField: "value",
index: 0
},
tabStrip: {
dataTextField: "name",
dataContentField: "content"
},
grid: {
columns: [
{
id: 1,
field: "reoreder",
draggable: true,
editable: () => false,
width: "40px"
},
{
id: 2,
field: "name"
},
{
id: 3,
field: "remove",
editable: () => false,
width: "40px",
template: () => `<button ${DATA_ACTION}="remove" tabindex="0"></button>`
}
],
pageable: false,
scrollable: false,
navigatable: false,
editable: {
confirmation: false,
mode: "incell"
},
reorderable: { rows: true }
}
};
const generateDataRows = (data, columns) => {
let rows = [];
data.forEach((item) => {
const row = rows.find((rowInstance) => rowInstance.uid === item.uid);
if (!row) {
rows.push(item);
} else {
extend(row, item);
}
});
const dataRows = rows.map((row) => ({
dataItem: row,
dataColumns: columns
}));
return getWizardDataFromDataRows(dataRows);
};
const ChartWizard = Widget.extend({
init: function(element, options) {
let that = this;
options = options || {};
that.options = deepExtend({}, that.options, options);
Widget.fn.init.call(that, element, options);
that._initial = true;
that._dataSource();
kendo.notify(that);
},
options: {
name: "ChartWizard",
dataSource: [],
dataColumns: [],
defaultState: {},
state: {},
window: {
actions: ["Maximize", "Close"],
resizable: true,
visible: true,
modal: true,
scrollable: false,
animation: false,
width: 700,
height: 550
},
exportOptions: {
fileName: "chart",
pdf: { margin: "1cm" },
image: {
width: 800,
height: 600
}
},
messages: {
window: { title: "Chart Preview" },
export: "Export",
exportPDF: "PDF File",
exportSVG: "SVG File",
exportPNG: "PNG File",
tab: {
chart: "Chart",
data: "Data",
format: "Format"
},
chart: {
bar: {
expandText: "Bar Chart",
bar: "Bar",
stackedBar: "Stacked Bar",
hundredStackedBar: "100% Stacked Bar"
},
pie: {
expandText: "Pie Chart",
pie: "Pie"
},
column: {
expandText: "Column Chart",
column: "Column",
stackedColumn: "Stacked Column",
hundredStackedColumn: "100% Stacked Column"
},
line: {
expandText: "Line Chart",
line: "Line",
stackedLine: "Stacked Line",
hundredStackedLine: "100% Stacked Line"
},
scatter: {
expandText: "Scatter Chart",
scatter: "Scatter"
}
},
data: { configuration: {
expandText: "Configuration",
series: {
title: "Series",
add: "Add"
},
valueAxis: "Value Axis",
categoryAxis: "Category Axis",
xAxis: "X Axis"
} },
format: {
chartArea: {
expandText: "Chart Area",
margins: {
default: "Margins",
auto: "Auto",
left: "Left",
right: "Right",
top: "Top",
bottom: "Bottom"
},
background: {
default: "Background",
color: "Color"
}
},
title: {
expandText: "Title",
applyTo: "Apply to",
chartTitle: "Chart Title",
chartSubtitle: "Chart Subtitle",
label: "Title",
font: "Font",
fontPlaceholder: "(inherited font)",
size: "Size",
sizePlaceholder: "px",
color: "Color"
},
series: {
expandText: "Series",
applyTo: "Apply to",
allSeries: "All Series",
color: "Color",
showLabels: "Show Labels"
},
legend: {
expandText: "Legend",
showLegend: "Show Legend",
font: "Font",
fontPlaceholder: "(inherited font)",
size: "Size",
sizePlaceholder: "px",
color: "Color",
position: {
default: "Position",
top: "Top",
bottom: "Bottom",
left: "Left",
right: "Right"
}
},
categoryAxis: {
expandText: "Category Axis",
title: {
text: "Title",
placeholder: "Axis Title",
font: "Font",
fontPlaceholder: "(inherited font)",
size: "Size",
sizePlaceholder: "px",
color: "Color"
},
labels: {
text: "Labels",
font: "Font",
fontPlaceholder: "(inherited font)",
size: "Size",
sizePlaceholder: "px",
color: "Color",
rotation: {
text: "Rotation",
auto: "Auto"
},
reverseOrder: "Reverse Order"
}
},
valueAxis: {
expandText: "Value Axis",
title: {
text: "Title",
placeholder: "Axis Title",
font: "Font",
fontPlaceholder: "(inherited font)",
size: "Size",
sizePlaceholder: "px",
color: "Color"
},
labels: {
text: "Labels",
labelFormat: {
default: "Label Format",
text: "Text",
number: "Number",
currency: "Currency",
percent: "Percent"
},
font: "Font",
fontPlaceholder: "(inherited font)",
size: "Size",
sizePlaceholder: "px",
color: "Color",
rotation: {
text: "Rotation",
auto: "Auto"
}
}
},
xAxis: { expandText: "X Axis" },
yAxis: { expandText: "Y Axis" }
}
}
},
events: [
RESIZING,
DATA_BINGING,
DATA_BOUND,
RESIZE,
CLICK,
KEYDOWN,
OPEN,
CLOSE,
CHANGE,
EXPORT_PDF,
EXPORT_SVG,
EXPORT_IMAGE
],
open: function() {
const that = this;
that.window.open();
},
close: function() {
const that = this;
that.window.close();
},
_attachEvents: function() {
const that = this;
that.splitter.bind(RESIZING, ({ pane }) => {
kendo.resize(pane);
});
that.splitter.bind(RESIZE, (event) => {
event.sender.element.find(DOT + "k-pane").each((_, pane) => {
kendo.resize(pane);
});
});
that.window.bind(ACTIVATE, that._windowActivateHandler.bind(that));
that.window.bind(RESIZE, that._windowResizeHandler.bind(that));
that.window.bind(MAXIMIZE, that._windowActivateHandler.bind(that));
that.window.bind(RESTORE, that._windowActivateHandler.bind(that));
that.window.bind(CLOSE, function() {
that.trigger(CLOSE);
});
that.window.bind(OPEN, function() {
that.trigger(OPEN);
});
that.tabStrip.contentElements.on(CLICK + NS, DOT + "k-icon-text-wrapper", that._handleChartTypeClick.bind(that));
that.tabStrip.contentElements.on(KEYDOWN + NS, DOT + "k-icon-text-wrapper", that._handleChartTypeKeydown.bind(that));
},
_dataSource: function() {
const that = this, options = that.options;
let dataSource = options.dataSource;
if (that.dataSource && that._refreshHandler) {
that.dataSource.unbind(CHANGE, that._refreshHandler);
} else {
that._refreshHandler = that._refresh.bind(that);
}
if (dataSource && dataSource instanceof DataSource) {
that.dataSource = dataSource.bind(CHANGE, that._refreshHandler);
} else {
dataSource = Array.isArray(dataSource) ? { data: dataSource } : dataSource;
that.dataSource = DataSource.create(dataSource).bind(CHANGE, that._refreshHandler);
}
if (that.dataSource.data().length) {
that._refresh();
} else if (!that.dataSource._requestInProgress) {
that.dataSource.fetch();
}
},
_refreshContent: function() {
const that = this;
const options = that.options;
const chartState = that._getChartStateInstance(options);
const previewHeader = that.previewPane.find(DOT + cssClasses.previewPaneHeader);
that.window.setOptions({
title: kendo.htmlEncode(options.messages.window.title),
...options.window
});
that._oldType = null;
that._setChartContainerHeight();
that.chartState = extend(that.chartState, chartState);
that.chart.setOptions(that.chartState);
that._detachEvents();
kendo.destroy(previewHeader);
previewHeader.empty();
that._createExportButton(previewHeader);
kendo.destroy(that.propertyPane);
that.propertyPane.empty();
that._seriesGrid = null;
that._seriesValueAxisDDL = null;
that._initPropertyPane();
that._attachEvents();
if (!that.window.wrapper.is(":visible") && options.window.visible) {
that.window.open();
}
if (!options.position) {
that.window.center();
}
},
_refresh: function(e) {
const that = this;
let data = Array.from(that.dataSource.data());
that.trigger(DATA_BINGING, { data });
data = that._data = that._getWizardData(data);
if (that._initial) {
that._initWindow();
that._initSplitter();
that._initPreviewPane();
that._initPropertyPane();
that._attachEvents();
that._initial = false;
} else {
that._refreshContent();
}
that.trigger(DATA_BOUND, { data });
},
_getWizardData: function(data) {
const that = this;
let wizardData = data;
const dataColumns = that.options.dataColumns ? that.options.dataColumns.map((column) => {
if (typeof column === "string") {
return { field: column };
}
return column;
}) : [];
if (data.length && data[0].dataItem && data[0].dataColumns) {
wizardData = getWizardDataFromDataRows(data);
} else if (data.length && !Array.isArray(data[0]) && dataColumns.length) {
wizardData = generateDataRows(data, dataColumns);
}
return wizardData;
},
setDataSource: function(dataSource) {
const that = this;
const options = that.options;
if (dataSource) {
options.dataSource = dataSource;
that._dataSource();
}
},
setDataColumns: function(dataColumns) {
const that = this;
const options = that.options;
if (dataColumns.length) {
options.dataColumns = dataColumns;
}
},
_detachEvents: function() {
const that = this;
that.splitter.unbind(RESIZING);
that.splitter.unbind(RESIZE);
that.window.unbind(ACTIVATE);
that.window.unbind(RESIZE);
that.window.unbind(CLOSE);
that.window.unbind(OPEN);
that.window.unbind(MAXIMIZE);
that.window.unbind(RESTORE);
that.tabStrip.contentElements.off(CLICK + NS);
that.tabStrip.contentElements.off(KEYDOWN + NS);
},
_setChartContainerHeight: function() {
const that = this;
that.previewPane.find(DOT + cssClasses.previewPaneContent).css({ height: that.previewPane.height() - 50 });
},
_windowActivateHandler: function() {
const that = this;
that._setChartContainerHeight();
that.chart.resize();
},
_windowResizeHandler: function() {
const that = this;
that._setChartContainerHeight();
},
_handleChartTypeKeydown: function(e) {
if (e.keyCode === keys.ENTER) {
this._handleChartTypeClick(e);
}
},
_handleChartTypeClick: function(e) {
const that = this;
const item = $(e.currentTarget);
const newType = that._getRefAttributeValue(item.closest(DOT + "k-expander-content")[0])[0];
const chartType = item.attr(DATA_CHART_TYPE_ATTR);
const chartState = that.chartState;
let change = null;
let action = null;
if (chartType.includes(HUNDRED_STACKED)) {
action = actionTypes.stacked;
change = { type: "100%" };
} else if (chartType.includes(STACKED)) {
action = actionTypes.stacked;
change = { type: "normal" };
}
that._executeAction(change, { element: item }, chartState.data, newType, action);
item.closest(DOT + "k-tabstrip-content").find(DOT + SELECTED_STATE).removeClass(SELECTED_STATE);
item.addClass(SELECTED_STATE);
that._toggleFieldsForSeriesPanel(newType);
that._toggleFormatPanels();
that._refreshEditors();
},
_refreshEditors: function() {
const that = this;
const editors = that.propertyPane.find(DATA_ACTION_SELECTOR + ":not('.k-button')");
editors.each((_, editor) => {
const element = $(editor);
const kendoElement = element.data("handler");
const id = element.attr("id");
const panel = $(editor).closest(`[${REF}]`);
const elementRole = element.attr(DATA_ROLE);
const panelRef = that._getRefAttributeValue(panel[0])[0];
if (kendoElement && kendoElement.setOptions) {
const changed = that._getOptionsForPanel(id)[panelRef][elementRole];
if (changed && changed.options) {
if (elementRole === inputRoles.checkBox) {
kendoElement.check(changed.options.checked);
} else if (panelRef === "series") {
kendoElement.setOptions(changed.options);
if (changed.options && changed.options.enable) {
kendoElement.enable(changed.options.enable);
}
} else {
let val = changed.options.value;
if (val && typeof val !== "string" && val.value) {
val = val.value;
}
kendoElement.value(val);
}
}
if (elementRole === inputRoles.comboBox) {
const state = that._getFontState(element);
if (state && state.value) {
kendoElement.value(state.value);
}
}
}
});
if (that._seriesGrid) {
that._seriesGrid.setDataSource(that.chartState.series);
}
},
_initWindow: function() {
const that = this;
const messages = that.options.messages;
const options = that.options.window;
const centered = !options.position;
that.window = that.element.kendoWindow({
title: kendo.htmlEncode(messages.window.title),
...options
}).data("kendoWindow");
if (centered) {
that.window.center();
}
that.window.element.attr("tabindex", "-1");
that.wrapper = that.window.wrapper.addClass(cssClasses.chartWizard);
},
_initSplitter: function() {
const that = this;
that.splitter = $("<div>").kendoSplitter({ orientation: "horizontal" }).data("kendoSplitter");
that.previewPane = that.splitter.append({ scrollable: false });
that.propertyPane = that.splitter.append({
size: "300px",
collapsible: true
});
that.splitter.wrapper.addClass(cssClasses.splitter);
that.window.content(that.splitter.wrapper);
},
_initPreviewPane: function() {
const that = this;
const options = that.options;
that.previewPane.addClass(cssClasses.previewPane);
const previewHeader = $("<div></div>").addClass(cssClasses.previewPaneHeader);
const previewContent = $("<div></div>").addClass(cssClasses.previewPaneContent);
if (that.options.window.visible) {
previewContent.css({ height: that.previewPane.height() - 50 });
}
const chart = $("<div id='chart'>");
that._createExportButton(previewHeader);
previewContent.append(chart);
that.previewPane.append(previewHeader.add(previewContent));
that._initChart(chart, options);
},
_getChartStateInstance: function(options, skipDefault) {
const that = this;
const defaultState = skipDefault ? {} : options.defaultState;
const hasState = Object.keys(options.state).length;
const data = hasState ? options.state.data : that._data;
const seriesType = hasState ? !skipDefault && options.state.seriesType || INITIAL_TYPE : INITIAL_TYPE;
return createInitialStateInstance(data || [], seriesType, defaultState, options.state);
},
_initChart: function(element, options) {
const that = this;
const isPie = options.defaultState && options.defaultState.seriesType === "pie" || options.state && options.state.seriesType === "pie";
let initialState = that._getChartStateInstance(options, isPie);
const chartArea = initialState.area;
initialState.chartArea = chartArea;
initialState.transitions = false;
that.chartState = initialState;
that.chart = element.kendoChart(initialState).data("kendoChart");
that.chart.wrapper.css({
width: "100%",
height: "100%"
});
if (isPie) {
const pieState = that._getChartStateInstance(options);
that.chartState = extend(that.chartState, pieState);
that.chart.setOptions(that.chartState);
}
if (!that._initialState) {
that._initialState = that.chart.options;
}
},
_createExportButton: function(previewHeader) {
const that = this;
that._configureExportButton(exportButtonOptions);
const dropDownButton = $(`<button>${kendo.htmlEncode(that.options.messages.export)}</button>`).kendoDropDownButton(exportButtonOptions);
previewHeader.append(dropDownButton);
},
_configureExportButton: function(options) {
const that = this;
const messages = that.options.messages;
const idSeparator = "-";
const exportHandlers = {
"export-pdf": function() {
if (!that.trigger(EXPORT_PDF, {
chart: that.chart,
exportOptions: that.options.exportOptions
})) {
that.chart.exportPDF(that.options.exportOptions.pdf).done(function(data) {
kendo.saveAs({
dataURI: data,
fileName: that.options.exportOptions.fileName
});
});
}
},
"export-svg": function() {
if (!that.trigger(EXPORT_SVG, {
chart: that.chart,
exportOptions: that.options.exportOptions
})) {
that.chart.exportSVG(that.options.exportOptions.fileName).done(function(data) {
kendo.saveAs({
dataURI: data,
fileName: that.options.exportOptions.fileName
});
});
}
},
"export-png": function() {
if (!that.trigger(EXPORT_IMAGE, {
chart: that.chart,
exportOptions: that.options.exportOptions
})) {
that.chart.exportImage(that.options.exportOptions.image).done(function(data) {
kendo.saveAs({
dataURI: data,
fileName: that.options.exportOptions.fileName
});
});
}
}
};
options.items.forEach((item) => {
const textParts = item.id.split(idSeparator);
const text = textParts[0] + textParts[1].toUpperCase();
item.text = kendo.htmlEncode(messages[text]);
item.click = exportHandlers[item.id];
});
},
_preventLabelPointerEvents: function() {
const that = this;
that.propertyPane.find(".k-label").addClass("k-pointer-events-none");
},
_initPropertyPane: function() {
const that = this;
const tabStripOptions = commonOptions.tabStrip;
tabStripOptions.dataSource = Object.values(that.options.messages.tab).map((tab) => ({ name: kendo.htmlEncode(tab) }));
that._createTabsContent(tabStripOptions.dataSource);
that.tabStrip = $("<div>").kendoTabStrip({
...tabStripOptions,
activate: function(e) {
const contentElement = $(e.contentElement);
if (contentElement.find(`[${REF_SELECTOR}'data']`).length) {
const content = $(e.contentElement).find("#category-axis").parent().siblings(DOT + "k-form-legend");
if (content.length && that.chart.options.seriesType === "scatter") {
content.text(kendo.htmlEncode(that.options.messages.data.configuration.xAxis));
} else if (content.length) {
content.text(kendo.htmlEncode(that.options.messages.data.configuration.categoryAxis));
}
}
if (that._seriesGrid && that._seriesGrid.wrapper.is(":visible")) {
that._seriesGrid._draggableRows();
that._seriesGrid._reorderableRows();
}
}
}).data("kendoTabStrip");
that.propertyPane.addClass(cssClasses.propertyPane);
that.propertyPane.append(that.tabStrip.wrapper);
that._expansionPanels();
that._prepareDataTab();
that._prepareFormatTab();
that._initStaticEditors();
that.tabStrip.activateTab(that.tabStrip.tabGroup.children().first());
if (that.options.window.visible) {
that.chart.resize();
}
},
_createTabsContent: function(tabs) {
const that = this;
tabs.forEach((tab) => {
tab.content = that._createExpansionPanelContent(tab.name) ?? "";
});
},
_createExpansionPanelContent: function(tab) {
const that = this;
let content = "";
const tabs = that.options.messages.tab;
if (tab === tabs[CHART]) {
const fields = Object.keys(expansionPanelForChart);
fields.forEach((chartType) => {
content += that._createChartTypesPanel(expansionPanelForChart[chartType].content, `${chartType}-chart-panel`, chartType);
});
} else if (tab === tabs[DATA]) {
const data = dataTabPanel(that.options.messages.data);
content += that._createFormPanel(data, "configuration-data-panel");
} else if (tab === tabs[FORMAT]) {
const formatPanels = getFormatPanels();
formatPanels.forEach((panel) => {
const panelData = panel.getData(that.options.messages.format);
content += that._createFormPanel(panelData, `${panel.ref}-format-panel`);
});
}
return content;
},
_createChartTypesPanel: function(data, ref, mainChartType) {
const that = this;
const messages = that.options.messages.chart;
const content = $(templates.divContentWrapper(ref));
const chartTypesWrapper = $(templates.chartTypesWrapper());
const chartTypes = Object.keys(data);
chartTypes.forEach((chartType) => {
const text = kendo.htmlEncode(messages[mainChartType][chartType]);
const attribute = `${DATA_CHART_TYPE_ATTR}=${chartType.toLowerCase()}`;
chartTypesWrapper.append(templates.iconTextItem(templates.iconWrapper(data[chartType], ICON_SIZE), text, attribute));
});
content.append(chartTypesWrapper);
return content[0].outerHTML;
},
_createFormPanel: function(data, ref) {
const content = $(templates.divContentWrapper(ref));
const form = $(templates.formElement());
data.forEach((fields) => {
const legend = fields.legend;
const layoutClass = fields.layoutClass;
const editors = fields.editors;
let target = "";
if (editors instanceof Array) {
let formFields = "";
editors.forEach((editor) => {
const nowrap = editor.nowrap;
const label = editor.label ? templates.label(kendo.htmlEncode(editor.label.text), editor.label.for, !nowrap && "k-form-label") : "";
const className = editor.className;
let field;
if (editor.field && editor.field.custom) {
field = editor.field.custom;
} else if (editor.field) {
field = templates.inputBaseElement(editor.field);
} else {
field = "";
}
if (nowrap) {
formFields += templates.fieldContent(label, field);
} else {
formFields += templates.formField(templates.fieldContent(label, templates.formFieldWrap(field)), className);
}
});
if (layoutClass) {
const formGridLayout = $(templates.formGridLayout(layoutClass));
formGridLayout.append(formFields);
target = formGridLayout[0].outerHTML;
} else {
target = formFields;
}
} else if (editors && editors.custom) {
target = editors.custom;
} else {
target = templates.inputBaseElement(editors);
}
if (legend) {
form.append(templates.formFieldSet(kendo.htmlEncode(legend), target));
} else {
form.append(target);
}
});
content.append(form);
return content[0].outerHTML;
},
_ensureSizeValue: function(fontSize, callback) {
const numberRegExp = /^\d+$/;
const size = fontSize.toString();
let item = fontSizes.find((fs) => fs.text === size);
if (!item) {
if (!numberRegExp.test(size) || isNaN(parseInt(size, 10))) {
return false;
}
item = {
text: size,
value: size + "px"
};
fontSizes.push(item);
fontSizes.sort((a, b) => parseInt(a.text, 10) - parseInt(b.text, 10));
callback(fontSizes);
}
return true;
},
_executeAction: function(change, from, data, type, dataAction) {
const that = this;
const action = from.element.data("action");
const chartState = that.chartState;
const state = {
state: chartState,
action: dataAction ?? actionTypes[action],
change
};
if (data) {
state.data = data;
state.type = type ?? that.chartState.seriesType;
}
const newState = getNewState(state);
newState.chartArea = newState.area;
that.chart.setOptions(newState);
that.chartState = newState;
return newState;
},
_seriesDropDownChange: function(e) {
const that = this;
that._seriesChange = true;
e.preventChange = true;
const newState = that._handlePropertyChange(e);
delete that._seriesChange;
that._seriesGrid && that._seriesGrid.setDataSource(newState.series);
},
_prepareDataTab: function() {
const that = this;
const form = that.element.find(`[${REF_SELECTOR}'data'] > form`);
const gridField = form.find(".k-grid").closest(".k-form-fieldset");
const valueAxisField = form.find("#value-axis").closest(".k-form-fieldset");
that._dynamicConfigurationFields = {
grid: gridField.clone(),
valueAxis: valueAxisField.clone(),
container: form
};
gridField.remove();
valueAxisField.remove();
},
_resetFontValue: function(isInitial, field) {
if (isInitial && field) {
field.font = "";
return true;
}
return false;
},
_getFontField: function(activeField, activeFieldInitial, isInitial) {
const that = this;
let newValue;
if (isInitial) {
newValue = activeFieldInitial && activeFieldInitial.font;
} else {
newValue = activeField && activeField.font;
}
that._valueReset = that._resetFontValue(isInitial, activeField);
return newValue;
},
_getFontValue: function(fontState, field, type, fromSibling) {
const that = this;
let newValue;
const isInitial = type === "initial";
const activeFieldInitial = that._initialState[fontState.active];
const activeField = that.chartState[fontState.active];
if (Array.isArray(activeField)) {
newValue = that._getFontField(activeField[0], activeFieldInitial, isInitial, fromSibling);
} else {
newValue = that._getFontField(activeField, activeFieldInitial, isInitial, fromSibling);
}
if (!newValue && fontState.subfield) {
const sub = fontState.subfield.toLowerCase();
if (Array.isArray(activeField)) {
newValue = that._getFontField(activeField[0][sub], activeFieldInitial[sub], isInitial, fromSibling);
} else {
newValue = that._getFontField(activeField[sub], activeFieldInitial[sub], isInitial, fromSibling);
}
}
if (newValue) {
newValue = that._parseFont(newValue)[field];
}
return newValue;
},
_createFontCombobox: function(element) {
const that = this;
const state = that._getFontState(element);
const comboBox = element.kendoComboBox({
dataSource: state.dataSource,
value: state.value,
change: function(e) {
const fontState = e.sender._fontState;
const fontNameChanged = fontState.type === "name";
const applySubfieldToSelector = fontState.subfield && state.active !== "legend";
const selector = `${fontState.active}${fontState.subfield && applySubfieldToSelector ? `${fontState.subfield}` : ""}Font`;
let field = fontNameChanged ? "Size" : "Name";
let value = e.sender.value();
const sibling = e.sender.wrapper.closest(".k-form").find(`[${DATA_ACTION}*=${selector + field}]`).data("kendoComboBox");
field = field.toLowerCase();
const initial = !value;
if (initial) {
that._getFontValue(fontState, fontState.type, "initial");
if (that._valueReset) {
e.sender.value("");
sibling.value("");
return that.chart.setOptions(that.chartState);
}
} else {
if (!fontNameChanged) {
value = value.replace("px", "");
}
if (value !== "" && !fontNameChanged && !that._ensureSizeValue(value, e.sender.setDataSource.bind(e.sender))) {
return;
}
that._handlePropertyChange(e);
}
if (!initial && !sibling.value()) {
let newValue = that._getFontValue(fontState, field);
let change;
if (!fontNameChanged) {
newValue = newValue.replace(/^['"]*([a-zA-Z0-9\s]+)['"]*$/g, "$1");
change = fontNames.find((item) => item.value.includes(newValue));
} else if (that._ensureSizeValue(newValue, sibling.setDataSource.bind(sibling))) {
change = fontSizes.find((item) => item.text === newValue.toString());
}
if (change && change.value) {
sibling.value(change.text);
that._handlePropertyChange({
sender: sibling,
preventChange: true
}, change.value);
}
}
},
...commonOptions.comboBox
}).data("kendoComboBox");
comboBox._fontState = state;
return comboBox;
},
_createDropDownList: function(element, options, handler) {
const that = this;
const dropdownlist = $(element).kendoDropDownList({
...commonOptions.dropDownList,
...options,
change: handler || function(e) {
that._handlePropertyChange(e);
}
}).data("kendoDropDownList");
return dropdownlist;
},
_createSwitch: function(element, options, handler) {
const that = this;
const switchElement = element.kendoSwitch({
...options,
change: handler || function(e) {
that._handlePropertyChange(e);
}
}).data("kendoSwitch");
return switchElement;
},
_createCheckBox: function(element, options, handler) {
const that = this;
const checkbox = element.kendoCheckBox({
...options,
change: handler || function(e) {
that._handlePropertyChange(e);
}
}).data("kendoCheckBox");
return checkbox;
},
_createColorPicker: function(element, options, handler) {
const that = this;
const config = options ?? {};
const enabled = config.enable !== undefined ? config.enable : true;
delete config.enabled;
const colorPicker = element.kendoColorPicker({
...commonOptions.colorPicker,
...config,
change: handler || function(e) {
that._handlePropertyChange(e);
},
select: handler || function(e) {
that._handlePropertyChange(e, e.value);
}
}).data("kendoColorPicker");
colorPicker.enable(enabled);
return colorPicker;
},
_createNumericTextBox: function(element, options, handler) {
const that = this;
const numeric = element.kendoNumericTextBox({
...commonOptions.numericTextBox,
...options,
change: handler || function(e) {
that._handlePropertyChange(e);
},
spin: handler || function(e) {
that._handlePropertyChange(e);
}
}).data("kendoNumericTextBox");
return numeric;
},
_createTextBox: function(element, options) {
const that = this;
const textbox = element.kendoTextBox({ ...options });
textbox.on("input" + NS, function(e) {
const sender = { element: $(e.target) };
that._handlePropertyChange({ sender }, $(e.target).val());
});
return textbox.data("kendoTextBox");
},
_getFieldValue: function(action) {
const parts = action.split(REG_EXP_CAPITAL);
const fontIndex = parts.indexOf("Font");
const path = parts.slice(0, fontIndex);
const type = parts[fontIndex + 1].toLowerCase();
let field;
let subfield;
if (path.length === 1) {
field = path[0];
} else if (path.length > 1) {
subfield = path.pop();
field = path.join("");
}
return {
type,
field,
subfield: field === "legend" ? "Labels" : subfield
};
},
_getFontState: function(element) {
const that = this;
const state = that.chartState;
const action = element.data("action");
const parts = that._getFieldValue(action);
const field = parts.field;
const subfield = parts.subfield && parts.subfield.toLowerCase();
let font = state[field] && state[field].font;
if (!font && subfield) {
font = state[field] && state[field][subfield] && state[field][subfield].font;
}
let value = null;
let dataSource = [];
if (parts.type === "name") {
dataSource = fontNames;
value = font && dataSource.find((f) => f.value === that._parseFont(font).name) || null;
} else {
dataSource = fontSizes;
value = font && dataSource.find((f) => f.value === that._parseFont(font).size) || null;
}
return {
dataSource,
value,
type: parts.type,
active: field,
subfield: parts.subfield
};
},
_parseFont: function(font) {
const el = $("<span></span>");
el.css("font", font);
return