Closed misaki-web closed 1 year ago
For the record, there's a workaround with the filter do_shortcode_tag
. Example:
# Add this code in the `functions.php` theme file.
function chartjs_filter($output, $tag, $atts) {
if ($tag == 'chartjs') {
$my_custom_options = 'plugins: {legend: {labels: {font: {size: 24}}}}';
$output = str_replace('options = {', 'options = {' . $my_custom_options . ',', $output);
}
return $output;
}
add_filter('do_shortcode_tag', 'chartjs_filter', 10, 3);
@misaki-web thanks for your contributions. I'm working through them slowly.
Re:
There are many ways to add font customization
1.1 Setting typography.fontSize
true in block.json
enables the font size where you enter the CSV data to be adjusted
1.2 But a range control is needed to allow the legend font size to be changed.
1.3 Is it also necessary to set the font size for the labels on the axes? If so, how is this done?
I'd use labelsFontSize
for the attribute/shortcode parameter name
I'm not sure how to implement moreOptions
in the block editor.
Is it also necessary to set the font size for the labels on the axes? If so, how is this done?
Actually, I think it would be useful to be able to customize the font everywhere. For example, IMO the default Chart.js font size is too small for legends, axis labels and tooltips.
Here's the Chart.js documentation for each one:
The following example customizes the font for all of them (so you can see what's the namespace for each one):
function customize_chart_font($options, $atts, $series) {
$custom_options = to_array($options);
$custom_options['plugins']['legend']['labels']['font']['size'] = 16;
$custom_options['plugins']['legend']['labels']['color'] = '#000000';
$custom_options['scales']['x']['ticks']['font']['size'] = 14;
$custom_options['scales']['x']['ticks']['color'] = '#000000';
$custom_options['scales']['y']['ticks']['font']['size'] = 14;
$custom_options['scales']['y']['ticks']['color'] = '#000000';
if (isset($custom_options['scales']['y1'])) {
$custom_options['scales']['y1']['ticks']['font']['size'] = 14;
$custom_options['scales']['y1']['ticks']['color'] = '#000000';
}
$custom_options['plugins']['tooltip']['titleFont']['size'] = 16;
$custom_options['plugins']['tooltip']['bodyFont']['size'] = 15;
$custom_options['plugins']['tooltip']['footerFont']['size'] = 15;
return json_decode(json_encode($custom_options));
}
add_filter('sb_chart_block_options', 'customize_chart_font', 10, 3);
function to_array($data) {
$array = [];
if (is_array($data) || is_object($data)) {
foreach ($data as $key => $value) {
$array[$key] = (is_array($value) || is_object($value)) ? to_array($value) : $value;
}
} else {
$array[] = $data;
}
return $array;
}
I'm not sure how to implement moreOptions in the block editor.
I think it could be a textarea (bonus: with code highlighting for json), something similar to the style/CSS textarea added by some plugins. Example with Blocks CSS:
PR #23 contained some changes for this issue but not all of them.
I struggled to find the best code for setting the nested properties font size options.
Where the original code to set the font size for the legend labels was
$custom_options['plugins']['legend']['labels']['font']['size'] = 16;
I wanted to be able to achieve the equivalent of
$options->plugins->legend->labels->font->size = $this->atts['labelsFontSize'];
but the above only works when all the intermediate properties are objects. It produces a Fatal error when attempting to assign a new property to a null property.
Stack overflow searches helped a bit.
One way of achieving this is to use json_decode
& json_encode
to convert an array to an object.
$temp = [];
$temp['legend']['labels']['font']['size'] = $this->atts['labelsFontSize'];
$options->plugins = json_decode( json_encode( $temp));
or, for simple objects like this casting to an object seems to work.
$options->plugins = (object) ['legend' => ['labels' => ['font' => ['size' => $this->atts['labelsFontSize']]]]];
Here I didn't use $temp
; the array is created on the fly.
The code's a bit ugly but it seems to work.
I could have also tried the json_decode()
method documented in Example 2 in https://www.php.net/manual/en/class.stdclass.php
In relation to this topic, see the section Are there hooks available for developers? I added in the README file some time ago:
Also, what about a function that would take the value and the object path to be set? Let's say we have the following variables:
$options = new stdClass();
$options->abc = 'def';
$options->plugins = new stdClass();
$options->plugins->ghi = 'jkl';
$labelsFontSize = 14;
Here's another way to update the object:
set_object($options, 'legend->labels->font->size', $labelsFontSize);
function set_object(&$object, $path, $value) {
if (is_object($object)) {
if (is_array($path)) {
$keys = $path;
} else {
$keys = explode('->', $path);
}
$tmp_object =& $object;
foreach ($keys as $key) {
if (!isset($tmp_object->$key)) {
$tmp_object->$key = new stdClass();
}
$tmp_object =& $tmp_object->$key;
}
$tmp_object = $value;
$success = true;
}
return;
}
The object is updated as expected:
var_dump($options);
// Output:
/*
object(stdClass)#1 (3) {
["abc"]=>
string(3) "def"
["plugins"]=>
object(stdClass)#2 (1) {
["ghi"]=>
string(3) "jkl"
}
["legend"]=>
object(stdClass)#3 (1) {
["labels"]=>
object(stdClass)#4 (1) {
["font"]=>
object(stdClass)#5 (1) {
["size"]=>
int(14)
}
}
}
}
*/
The object could also be updated with the path as an array:
set_object($options, ['legend', 'labels', 'font', 'size'], $labelsFontSize);
set_object()
is similar to the method I was thinking about/started writing yesterday...setProperty()
.
Rather than using ->
for the separator I would have used .
and I would have returned the value to be set.
eg
$options->plugins = setProperty( $options, 'legend.labels.font.size', $this->atts['labelsFontSize'] );
Also, I'm thinking of extracting the utility functions from the main plugin file into a library file. I've got some non WordPress code that also creates charts. Functions needed:
Rather than using
->
for the separator I would have used.
and I would have returned the value to be set.
Brainstorming: a way to create the object:
$path = 'plugins.legend.labels.font.size';
$value = $this->atts['labelsFontSize'];
$props = explode('.', $path);
while ($prop = array_pop($props)) {
$value = (object) [$prop => $value];
}
var_dump($value);
/*
object(stdClass)#10 (1) {
["plugins"]=>
object(stdClass)#9 (1) {
["legend"]=>
object(stdClass)#8 (1) {
["labels"]=>
object(stdClass)#7 (1) {
["font"]=>
object(stdClass)#2 (1) {
["size"]=>
int(14)
}
}
}
}
}
*/
Tests for this issue are part of the tests for #22. https://s.b/oikcom/block_example/chart-block-multiple-y-axes/
Delivered in v1.2.0
The Chart.js documentation gives an example about font customization using the options object when creating a chart instance:
SB Chart Block creates the instance here:
https://github.com/bobbingwide/sb-chart-block/blob/22ebbf178529f30d678e2c1d558a6660f2625386/libs/class-sb-chart-block.php#L524-L527
@bobbingwide There are many ways to add font customization, if you are open to this new feature:
labelFontSize="16"
)moreOptions="..."
.The third point could be done like that (brainstorming, so not tested):
Shortcode:
Example:
PHP:
json_decode
returns null if the string can't be decoded, but it can also return any PHP type, so it may be a good idea to ensure we have an array:Then, we could merge
$this->atts['moreOptions']
with the options used to create the chart instance.Objects could be used instead of arrays. I see that
$options
is a string, but there's a TODO note about it:https://github.com/bobbingwide/sb-chart-block/blob/22ebbf178529f30d678e2c1d558a6660f2625386/libs/class-sb-chart-block.php#L415-L423