PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.8
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
← All changes | classes/Visualizer/Module/Utility.php +234 -9 3.10.144.0.8 View file →
@@ -35,9 +35,9 @@
35 35 *
36 36 * @since 3.3.0
37 37 *
38 38 * @access private
39 - * @var _CHART_COLORS
39 + * @var string[]
40 40 */
41 41 private static $_CHART_COLORS = array(
42 42 '#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080',
43 43 );
@@ -53,8 +53,9 @@
53 53 * @param Visualizer_Plugin $plugin The instance of the plugin.
54 54 */
55 55 public function __construct( Visualizer_Plugin $plugin ) {
56 56 parent::__construct( $plugin );
57 + $this->_addFilter( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, 'apply_global_style_settings', 999, 3 );
57 58 }
58 59
59 60
60 61 /**
@@ -105,20 +106,236 @@
105 106 return $output;
106 107 }
107 108
108 109 /**
109 - * Gets a random color from the array of chart colors and returns it as well as its transparent equivalent.
110 + * Returns a color at a specific index from the palette, with its transparent equivalent.
110 111 *
111 - * @since 3.3.0
112 + * @return array{string, string}
113 + * @access private
114 + */
115 + private static function get_color_at( int $index ): array {
116 + $colors = self::get_color_palette();
117 + $color = $colors[ $index % count( $colors ) ];
118 + return array( self::hex2rgba( $color, 0.5 ), $color );
119 + }
120 +
121 + /**
122 + * Mixes a hex color toward white by the given factor (0 = original, 1 = white).
112 123 *
113 124 * @access private
114 125 */
115 - private static function get_random_color() {
116 - $color = self::$_CHART_COLORS[ rand( 0, count( self::$_CHART_COLORS ) - 1 ) ];
117 - return array( self::hex2rgba( $color, 0.5 ), $color );
126 + private static function tint_color( string $hex, float $factor ): string {
127 + $hex = ltrim( $hex, '#' );
128 + if ( strlen( $hex ) === 3 ) {
129 + $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
130 + }
131 + $r = (int) round( hexdec( substr( $hex, 0, 2 ) ) + ( 255 - hexdec( substr( $hex, 0, 2 ) ) ) * $factor );
132 + $g = (int) round( hexdec( substr( $hex, 2, 2 ) ) + ( 255 - hexdec( substr( $hex, 2, 2 ) ) ) * $factor );
133 + $b = (int) round( hexdec( substr( $hex, 4, 2 ) ) + ( 255 - hexdec( substr( $hex, 4, 2 ) ) ) * $factor );
134 + return sprintf( '#%02x%02x%02x', $r, $g, $b );
118 135 }
119 136
120 137 /**
138 + * Returns the color palette to use for charts.
139 + *
140 + * When global primary/secondary colors are configured, generates a palette of
141 + * alternating tints: [primary, secondary, primary@25%, secondary@25%, ...].
142 + * Falls back to the built-in colors otherwise.
143 + *
144 + * @return string[]
145 + * @access private
146 + */
147 + private static function get_color_palette(): array {
148 + $global = self::get_global_style_defaults();
149 + $primary = $global['color_primary'];
150 + $secondary = $global['color_secondary'];
151 +
152 + if ( empty( $primary ) && empty( $secondary ) ) {
153 + return self::$_CHART_COLORS;
154 + }
155 +
156 + $bases = array_filter( array( $primary, $secondary ) );
157 + $factors = array( 0, 0.25, 0.5, 0.75 );
158 + $palette = array();
159 +
160 + foreach ( $factors as $factor ) {
161 + foreach ( $bases as $base ) {
162 + $palette[] = $factor === 0 ? $base : self::tint_color( $base, $factor );
163 + }
164 + }
165 +
166 + return $palette;
167 + }
168 +
169 + /**
170 + * Returns the global style defaults stored in the plugin settings.
171 + *
172 + * @return array<string, string>
173 + * @access public
174 + * @static
175 + */
176 + public static function get_global_style_defaults(): array {
177 + $option = get_option( Visualizer_Module_Admin::OPTION_GLOBAL_SETTINGS, array() );
178 + return wp_parse_args(
179 + $option,
180 + array(
181 + 'color_primary' => '',
182 + 'color_secondary' => '',
183 + 'apply_existing' => '0',
184 + )
185 + );
186 + }
187 +
188 + /**
189 + * Applies global styles to existing charts at render time.
190 + *
191 + * @param array<string, mixed>|mixed $settings Chart settings.
192 + * @param int $chart_id Chart ID.
193 + * @param string $type Chart type.
194 + * @return array<string, mixed>
195 + * @access public
196 + */
197 + public function apply_global_style_settings( $settings, $chart_id, $type ): array {
198 + $settings = is_array( $settings ) ? $settings : array();
199 + $global = self::get_global_style_defaults();
200 +
201 + if ( empty( $global['apply_existing'] ) ) {
202 + return $settings;
203 + }
204 +
205 + if ( empty( $global['color_primary'] ) && empty( $global['color_secondary'] ) ) {
206 + return $settings;
207 + }
208 +
209 + if ( empty( $chart_id ) ) {
210 + return $settings;
211 + }
212 +
213 + $library = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, true );
214 + $library = is_string( $library ) ? strtolower( $library ) : '';
215 + if ( empty( $type ) ) {
216 + $type = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true );
217 + }
218 + $type = is_string( $type ) ? strtolower( $type ) : '';
219 +
220 + if ( empty( $library ) ) {
221 + $library = in_array( $type, array( 'datatable', 'tabular' ), true ) ? 'datatable' : 'googlecharts';
222 + }
223 +
224 + if ( 'googlecharts' === $library || 'google' === $library ) {
225 + if ( 'geo' !== $type ) {
226 + $has_explicit = false;
227 + if ( ! empty( $settings['colors'] ) ) {
228 + $has_explicit = true;
229 + }
230 + if ( ! $has_explicit && isset( $settings['series'] ) && is_array( $settings['series'] ) ) {
231 + foreach ( $settings['series'] as $series_settings ) {
232 + if ( ! empty( $series_settings['color'] ) ) {
233 + $has_explicit = true;
234 + break;
235 + }
236 + }
237 + }
238 + if ( ! $has_explicit && isset( $settings['slices'] ) && is_array( $settings['slices'] ) ) {
239 + foreach ( $settings['slices'] as $slice_settings ) {
240 + if ( ! empty( $slice_settings['color'] ) ) {
241 + $has_explicit = true;
242 + break;
243 + }
244 + }
245 + }
246 + if ( ! $has_explicit ) {
247 + $settings['colors'] = self::get_color_palette();
248 + }
249 + }
250 + return $settings;
251 + }
252 +
253 + if ( 'chartjs' === $library ) {
254 + $has_explicit = false;
255 + if ( isset( $settings['series'] ) && is_array( $settings['series'] ) ) {
256 + foreach ( $settings['series'] as $series_settings ) {
257 + if ( ! empty( $series_settings['backgroundColor'] ) || ! empty( $series_settings['borderColor'] ) || ! empty( $series_settings['hoverBackgroundColor'] ) ) {
258 + $has_explicit = true;
259 + break;
260 + }
261 + }
262 + }
263 + if ( ! $has_explicit && isset( $settings['slices'] ) && is_array( $settings['slices'] ) ) {
264 + foreach ( $settings['slices'] as $slice_settings ) {
265 + if ( ! empty( $slice_settings['backgroundColor'] ) || ! empty( $slice_settings['borderColor'] ) || ! empty( $slice_settings['hoverBackgroundColor'] ) ) {
266 + $has_explicit = true;
267 + break;
268 + }
269 + }
270 + }
271 + if ( $has_explicit ) {
272 + return $settings;
273 + }
274 + $series = get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true );
275 + if ( is_array( $series ) ) {
276 + $settings = self::apply_chartjs_palette( $settings, $type, $series, $chart_id );
277 + }
278 + }
279 +
280 + return $settings;
281 + }
282 +
283 + /**
284 + * Applies the global palette to ChartJS settings for a chart.
285 + *
286 + * @param array<string, mixed> $settings Current chart settings.
287 + * @param string $type Chart type.
288 + * @param array<int, mixed> $series Series definitions.
289 + * @param int $chart_id Chart ID.
290 + * @return array<string, mixed>
291 + * @access private
292 + * @static
293 + */
294 + private static function apply_chartjs_palette( array $settings, string $type, array $series, int $chart_id ): array {
295 + $attributes = array();
296 + $name = 'series';
297 + $count = count( $series );
298 + $max = $count - 1;
299 +
300 + switch ( $type ) {
301 + case 'polarArea':
302 + // fall through.
303 + case 'pie':
304 + $chart = get_post( $chart_id );
305 + $raw = $chart instanceof WP_Post ? $chart->post_content : array();
306 + $data = self::maybe_decode_content( $raw );
307 + $name = 'slices';
308 + $max = is_array( $data ) ? count( $data ) : $count;
309 + // fall through.
310 + case 'column':
311 + // fall through.
312 + case 'bar':
313 + for ( $i = 0; $i < $max; $i++ ) {
314 + $colors = self::get_color_at( $i );
315 + $attributes[] = array( 'backgroundColor' => $colors[0], 'hoverBackgroundColor' => $colors[1] );
316 + }
317 + break;
318 + case 'radar':
319 + // fall through.
320 + case 'line':
321 + // fall through.
322 + case 'area':
323 + for ( $i = 0; $i < $max; $i++ ) {
324 + $colors = self::get_color_at( $i );
325 + $attributes[] = array( 'borderColor' => $colors[0] );
326 + }
327 + break;
328 + }
329 +
330 + if ( $attributes ) {
331 + $settings[ $name ] = $attributes;
332 + }
333 +
334 + return $settings;
335 + }
336 +
337 + /**
121 338 * Sets some defaults in the chart.
122 339 *
123 340 * @since 3.3.0
124 341 *
@@ -177,8 +394,16 @@
177 394 $attributes['candlestick']['risingColor']['stroke'] = '#3366cc';
178 395 $attributes['candlestick']['risingColor']['fill'] = '#3366cc';
179 396 break;
180 397 }
398 +
399 + // Apply global color defaults to new Google Charts (not Geo — it uses colorAxis).
400 + if ( 'geo' !== $type ) {
401 + $global = self::get_global_style_defaults();
402 + if ( ! empty( $global['color_primary'] ) || ! empty( $global['color_secondary'] ) ) {
403 + $attributes['colors'] = self::get_color_palette();
404 + }
405 + }
181 406 }
182 407
183 408 if ( $attributes ) {
184 409 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
@@ -209,9 +434,9 @@
209 434 switch ( $type ) {
210 435 case 'polarArea':
211 436 // fall through.
212 437 case 'pie':
213 - $data = unserialize( $chart->post_content );
438 + $data = self::decode_content( $chart->post_content );
214 439 $name = 'slices';
215 440 $max = count( $data );
216 441 // fall through.
217 442 case 'column':
@@ -217,9 +442,9 @@
217 442 case 'column':
218 443 // fall through.
219 444 case 'bar':
220 445 for ( $i = 0; $i < $max; $i++ ) {
221 - $colors = self::get_random_color();
446 + $colors = self::get_color_at( $i );
222 447 $attributes[] = array( 'backgroundColor' => $colors[0], 'hoverBackgroundColor' => $colors[1] );
223 448 }
224 449 break;
225 450 case 'radar':
@@ -227,9 +452,9 @@
227 452 case 'line':
228 453 // fall through.
229 454 case 'area':
230 455 for ( $i = 0; $i < $max; $i++ ) {
231 - $colors = self::get_random_color();
456 + $colors = self::get_color_at( $i );
232 457 $attributes[] = array( 'borderColor' => $colors[0] );
233 458 }
234 459 break;
235 460 }