PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.78
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.78
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / Charts / script.js

script.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.78, at includes/widgets/Charts/script.js

415 lines 25.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // noinspection JSUnresolvedReference
2
3 "use strict";
4 (function ($) {
5 $(window).on("elementor/frontend/init", function () {
6 elementorFrontend.hooks.addAction(
7 "frontend/element_ready/king-addons-charts.default",
8 function ($scope) {
9 const BaseHandler = elementorModules.frontend.handlers.Base.extend({
10 onInit() {
11 const $container = this.$element.find(".king-addons-charts-container");
12 const chartSettings = JSON.parse($container.attr("data-settings"));
13 const labels = chartSettings.chart_labels;
14 const customDatasets = chartSettings.chart_datasets
15 ? JSON.parse(chartSettings.chart_datasets)
16 : "";
17
18 // Helper for common grid/ticks setup
19 const axisConfig = (axis, gridColor, lineWidth, dashed = false) => ({
20 display: chartSettings[`display_${axis}_axis`],
21 drawBorder: chartSettings[`display_${axis}_axis`],
22 drawOnChartArea: chartSettings[`display_${axis}_axis`],
23 drawTicks: chartSettings[`display_${axis}_axis`],
24 color: gridColor,
25 borderDash: dashed
26 ? [chartSettings[`border_dash_length_${axis[0]}`], chartSettings[`border_dash_spacing_${axis[0]}`]]
27 : undefined,
28 borderDashOffset: dashed
29 ? chartSettings[`border_dash_offset_${axis[0]}`]
30 : undefined,
31 lineWidth: lineWidth,
32 });
33
34 // Reusable tick/font setup
35 const tickConfig = (axis) => ({
36 stepSize: chartSettings[`${axis}_step_size`],
37 display: chartSettings[`display_${axis}_ticks`],
38 padding: chartSettings[`ticks_padding_${axis}`],
39 autoSkip: false,
40 maxRotation: chartSettings[`rotation_${axis}`],
41 minRotation: chartSettings[`rotation_${axis}`],
42 color: chartSettings[`ticks_color_${axis}`],
43 font: {
44 size: chartSettings[`ticks_font_size_${axis}`],
45 family: chartSettings[`ticks_font_family_${axis}`],
46 style: chartSettings[`ticks_font_style_${axis}`],
47 weight: chartSettings[`ticks_font_weight_${axis}`],
48 },
49 });
50
51 // Configure scales based on chart type
52 const scales =
53 ["bar", "bar_horizontal", "line"].includes(chartSettings.chart_type)
54 ? {
55 x: {
56 reverse: chartSettings.reverse_x === "yes",
57 stacked: chartSettings.stacked_bar_chart === "yes",
58 type:
59 chartSettings.chart_type === "bar_horizontal"
60 ? chartSettings.data_type
61 : "category",
62 min: chartSettings.min_value || null,
63 max: chartSettings.max_value || null,
64 grid: axisConfig("x", chartSettings.axis_grid_line_color_x, chartSettings.grid_line_width_x, true),
65 title: {
66 display: chartSettings.display_x_axis_title,
67 text: chartSettings.x_axis_title,
68 color: chartSettings.axis_title_color_x,
69 font: {
70 size: chartSettings.axis_title_font_size_x,
71 family: chartSettings.axis_title_font_family_x,
72 style: chartSettings.axis_title_font_style_x,
73 weight: chartSettings.axis_title_font_weight_x,
74 },
75 },
76 ticks: {
77 stepSize:
78 chartSettings.chart_type === "bar_horizontal"
79 ? chartSettings.x_step_size
80 : "",
81 ...tickConfig("x"),
82 },
83 },
84 y: {
85 reverse: chartSettings.reverse_y === "yes",
86 stacked: chartSettings.stacked_bar_chart === "yes",
87 type:
88 ["bar", "line"].includes(chartSettings.chart_type)
89 ? chartSettings.data_type
90 : "category",
91 min: chartSettings.min_value || null,
92 max: chartSettings.max_value || null,
93 grid: axisConfig("y", chartSettings.axis_grid_line_color_y, chartSettings.grid_line_width_y, true),
94 title: {
95 display: chartSettings.display_y_axis_title,
96 text: chartSettings.y_axis_title,
97 color: chartSettings.axis_title_color_y,
98 font: {
99 size: chartSettings.axis_title_font_size_y,
100 family: chartSettings.axis_title_font_family_y,
101 style: chartSettings.axis_title_font_style_y,
102 weight: chartSettings.axis_title_font_weight_y,
103 },
104 },
105 ticks: tickConfig("y"),
106 },
107 }
108 : {};
109
110 // Global options
111 const globalOptions = {
112 responsive: true,
113 showLine: chartSettings.show_lines,
114 animation: chartSettings.chart_animation === "yes",
115 animations: {
116 tension: {
117 duration: chartSettings.chart_animation_duration,
118 easing: chartSettings.animation_transition_type,
119 from: 1,
120 to: 0,
121 loop: chartSettings.chart_animation_loop === "yes",
122 },
123 },
124 events: [
125 chartSettings.trigger_tooltip_on,
126 chartSettings.exclude_dataset_on_click === "yes" ? "click" : "",
127 ],
128 interaction: {
129 mode: chartSettings.chart_interaction_mode || "nearest",
130 },
131 elements: {
132 point: {
133 radius:
134 chartSettings.line_dots === "yes"
135 ? window.innerWidth >= 768
136 ? chartSettings.line_dots_radius
137 : chartSettings.line_dots_radius_mobile
138 : 0,
139 },
140 },
141 scales,
142 plugins: {
143 datalabels: {
144 color: chartSettings.inner_datalabels_color,
145 font: {
146 size: chartSettings.inner_datalabels_font_size,
147 style: chartSettings.inner_datalabels_font_style,
148 weight: chartSettings.inner_datalabels_font_weight,
149 },
150 },
151 legend: {
152 onHover: (event) => {
153 event.native.target.style.cursor = "pointer";
154 },
155 onLeave: (event) => {
156 event.native.target.style.cursor = "default";
157 },
158 onClick: (e, legendItem, legend) => {
159 if (
160 ["bar", "bar_horizontal", "line"].includes(chartSettings.chart_type) ||
161 chartSettings.chart_type === "radar"
162 ) {
163 const ci = legend.chart;
164 const index = legendItem.datasetIndex;
165 legendItem.hidden
166 ? (ci.show(index), (legendItem.hidden = false))
167 : (ci.hide(index), (legendItem.hidden = true));
168 }
169 },
170 reverse: chartSettings.reverse_legend === "yes",
171 display: chartSettings.show_chart_legend === "yes",
172 position: chartSettings.legend_position || "top",
173 align: chartSettings.legend_align || "center",
174 labels: {
175 usePointStyle: chartSettings.legend_shape === "point",
176 padding: chartSettings.legend_padding,
177 boxWidth: chartSettings.legend_box_width,
178 boxHeight: chartSettings.legend_font_size,
179 color: chartSettings.legend_text_color,
180 font: {
181 family: chartSettings.legend_font_family,
182 size: chartSettings.legend_font_size,
183 style: chartSettings.legend_font_style,
184 weight: chartSettings.legend_font_weight,
185 },
186 },
187 },
188 title: {
189 display: chartSettings.show_chart_title === "yes",
190 text: chartSettings.chart_title,
191 align: chartSettings.chart_title_align || "center",
192 position: chartSettings.chart_title_position || "top",
193 color: chartSettings.chart_title_color || "#000",
194 padding: chartSettings.title_padding,
195 font: {
196 family: chartSettings.title_font_family,
197 size: chartSettings.title_font_size,
198 style: chartSettings.title_font_style,
199 weight: chartSettings.title_font_weight,
200 },
201 },
202 tooltip: {
203 callbacks: {
204 footer(tooltipItems) {
205 let sum = 0;
206 tooltipItems.forEach((item) => {
207 sum += item.parsed.y;
208 });
209 if (chartSettings.chart_type === "bar_horizontal") {
210 sum = 0;
211 tooltipItems.forEach((item) => {
212 sum += item.parsed.x;
213 });
214 }
215 if (
216 ["radar", "pie", "doughnut", "polarArea"].includes(
217 chartSettings.chart_type
218 )
219 ) {
220 return false;
221 }
222 return "Sum: " + sum;
223 },
224 },
225 enabled: chartSettings.show_chart_tooltip === "yes",
226 position: chartSettings.tooltip_position || "nearest",
227 padding: chartSettings.tooltip_padding || 10,
228 caretSize:
229 window.innerWidth >= 768
230 ? chartSettings.tooltip_caret_size
231 : chartSettings.chart_tooltip_caret_size_mobile,
232 backgroundColor:
233 chartSettings.chart_tooltip_bg_color || "rbga(0, 0, 0, 0.2)",
234 titleColor: chartSettings.chart_tooltip_title_color || "#FFF",
235 titleFont: {
236 family: chartSettings.chart_tooltip_title_font,
237 size: chartSettings.chart_tooltip_title_font_size,
238 },
239 titleAlign: chartSettings.chart_tooltip_title_align,
240 titleMarginBottom: chartSettings.chart_tooltip_title_margin_bottom,
241 bodyColor: chartSettings.chart_tooltip_item_color || "#FFF",
242 bodyFont: {
243 family: chartSettings.chart_tooltip_item_font,
244 size: chartSettings.chart_tooltip_item_font_size,
245 },
246 bodyAlign: chartSettings.chart_tooltip_item_align,
247 bodySpacing: chartSettings.chart_tooltip_item_spacing,
248 boxPadding: 3,
249 },
250 },
251 };
252
253 // Adjust scales for non-standard chart types
254 if (
255 !["bar", "bar_horizontal", "line"].includes(chartSettings.chart_type) &&
256 !["doughnut", "pie", "polarArea"].includes(chartSettings.chart_type)
257 ) {
258 globalOptions.scales = {
259 r: {
260 angleLines: { color: chartSettings.angle_lines_color },
261 pointLabels: {
262 color: chartSettings.point_labels_color_r,
263 font: {
264 size: chartSettings.point_labels_font_size_r,
265 family: chartSettings.point_labels_font_family_r,
266 style: chartSettings.point_labels_font_style_r,
267 weight: chartSettings.point_labels_font_weight_r,
268 },
269 },
270 ticks: {
271 stepSize: chartSettings.r_step_size,
272 display: chartSettings.display_r_ticks,
273 backdropColor: chartSettings.axis_labels_bg_color,
274 backdropPadding: +chartSettings.axis_labels_padding,
275 color: chartSettings.axis_labels_color,
276 },
277 grid: axisConfig("r", chartSettings.axis_grid_line_color_r, chartSettings.grid_line_width_r, true),
278 },
279 };
280 }
281
282 // Chart creation
283 let config;
284 if (chartSettings.data_source === "custom") {
285 const data = {
286 labels,
287 datasets: JSON.parse(chartSettings.chart_datasets),
288 };
289 config = {
290 type:
291 chartSettings.chart_type === "bar_horizontal"
292 ? "bar"
293 : chartSettings.chart_type,
294 data,
295 options: globalOptions,
296 plugins: chartSettings.inner_datalabels ? [ChartDataLabels] : [],
297 };
298 if (chartSettings.chart_type === "bar_horizontal") {
299 config.options.indexAxis = "y";
300 }
301 if (
302 chartSettings.tooltips_percent ||
303 ["pie", "doughnut", "polarArea"].includes(chartSettings.chart_type)
304 ) {
305 config.options.plugins.tooltip.callbacks.label = (data) => {
306 let prefix = data.dataset.label + ": ";
307 if (["pie", "doughnut", "polarArea"].includes(chartSettings.chart_type)) {
308 prefix = `${data.label} (${data.dataset.label}): `;
309 }
310 const total = data.dataset.data.reduce(
311 (sum, val) => parseFloat(sum) + parseFloat(val),
312 0
313 );
314 const percentage = ((data.formattedValue / total) * 100).toPrecision(3);
315 return prefix + (chartSettings.tooltips_percent ? percentage + "%" : data.formattedValue);
316 };
317 }
318 new Chart($scope.find(".king-addons-chart"), config);
319 } else {
320 // Handle CSV data source or errors
321 if (chartSettings.url && (["bar", "bar_horizontal", "line", "radar"].includes(chartSettings.chart_type))) {
322 $.ajax({
323 url: chartSettings.url,
324 type: "GET",
325 success(res) {
326 $scope.find(".king-addons-rotating-plane").remove();
327 renderCSVChart(res);
328 },
329 error(err) {
330 // console.error(err);
331 },
332 });
333 } else {
334 $scope.find(".king-addons-rotating-plane").remove();
335 const errorMsg =
336 !chartSettings.url
337 ? '<p class="king-addons-charts-error-notice">Provide a csv file or remote URL</p>'
338 : '<p class="king-addons-charts-error-notice">doughnut, pie and polarArea charts only work with custom data source</p>';
339 $scope.find(".king-addons-charts-container").html(errorMsg);
340 }
341 }
342
343 // Window resize handler
344 $(window).resize(() => {
345 const newRadius =
346 window.innerWidth >= 768
347 ? chartSettings.line_dots_radius
348 : chartSettings.line_dots_radius_mobile;
349 config.options.elements.point.radius = newRadius;
350 config.options.plugins.tooltip.caretSize =
351 window.innerWidth >= 768
352 ? chartSettings.tooltip_caret_size
353 : chartSettings.chart_tooltip_caret_size_mobile;
354 });
355
356 // Render chart from CSV data
357 function renderCSVChart(csvData) {
358 const ctx = $scope.find(".king-addons-chart");
359 const rows = csvData.split(/\r?\n|\r/);
360 const csvLabels = rows.shift().split(chartSettings.separator);
361 const data = { labels: csvLabels, datasets: [] };
362 const csvConfig = {
363 type: chartSettings.chart_type === "bar_horizontal" ? "bar" : chartSettings.chart_type,
364 data,
365 options: globalOptions,
366 plugins: [
367 ...(chartSettings.inner_datalabels ? [ChartDataLabels] : []),
368 {
369 beforeInit(chart) {
370 chart.legend.afterFit = function () {
371 this.height += 50;
372 };
373 },
374 },
375 ],
376 };
377 if (chartSettings.chart_type === "bar_horizontal") {
378 csvConfig.options.indexAxis = "y";
379 }
380 if (chartSettings.tooltips_percent) {
381 csvConfig.options.plugins.tooltip.callbacks.label = (data) => {
382 let prefix = data.dataset.label + ": ";
383 if (["pie", "doughnut", "polarArea"].includes(chartSettings.chart_type)) {
384 prefix = `${data.label} (${data.dataset.label}): `;
385 }
386 const total = data.dataset.data.reduce(
387 (sum, val) => parseFloat(sum) + parseFloat(val),
388 0
389 );
390 const percentage = ((data.formattedValue / total) * 100).toPrecision(3);
391 return prefix + (chartSettings.tooltips_percent ? percentage + "%" : data.formattedValue);
392 };
393 }
394 const csvChart = new Chart(ctx, csvConfig);
395 rows.forEach((row, idx) => {
396 if (row) {
397 const dataset = { data: row.split(chartSettings.separator) };
398 if (customDatasets[idx]) {
399 Object.assign(dataset, customDatasets[idx]);
400 }
401 data.datasets.push(dataset);
402 csvChart.update();
403 }
404 });
405 }
406 },
407 });
408
409 elementorFrontend.elementsHandler.addHandler(BaseHandler, {
410 $element: $scope,
411 });
412 }
413 );
414 });
415 })(jQuery);