Added support for front-end rendering

This commit is contained in:
Jeremy Rangel
2025-01-15 03:48:59 -08:00
parent cb0ab8055d
commit 83f5cad36f
8 changed files with 394 additions and 41 deletions

View File

@ -3,12 +3,13 @@
"apiVersion": 2, "apiVersion": 2,
"name": "lcp/bar-graph", "name": "lcp/bar-graph",
"version": "0.1.0", "version": "0.1.0",
"title": "LCP Bar Graph", "title": "Bar Graph",
"category": "widgets", "category": "lcp-blocks",
"icon": "chart-bar", "icon": "chart-bar",
"description": "Display data in a bar graph format.", "description": "Display data as a bar graph",
"supports": { "supports": {
"html": false "html": false,
"anchor": true
}, },
"textdomain": "lcp", "textdomain": "lcp",
"editorScript": "file:./index.js", "editorScript": "file:./index.js",
@ -24,6 +25,14 @@
"type": "array", "type": "array",
"default": [] "default": []
}, },
"chartData": {
"type": "object",
"default": {}
},
"dataSource": {
"type": "string",
"default": ""
},
"showBarValues": { "showBarValues": {
"type": "boolean", "type": "boolean",
"default": true "default": true
@ -60,14 +69,6 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"chartData": {
"type": "object",
"default": {}
},
"dataSource": {
"type": "string",
"default": "manual_json"
},
"barColor": { "barColor": {
"type": "string", "type": "string",
"default": "#0073aa" "default": "#0073aa"

View File

@ -1 +1 @@
<?php return array('dependencies' => array(), 'version' => '7ca23fe6db2e4bfa97aa'); <?php return array('dependencies' => array(), 'version' => '70f08b60c296a36b16fe');

File diff suppressed because one or more lines are too long

View File

@ -51,24 +51,96 @@ function lcp_render_bar_graph_block($attributes, $content) {
} }
// Get attributes with defaults // Get attributes with defaults
$chart_height = $attributes['chartHeight'] ?? '400px'; $chart_height = intval($attributes['chartHeight'] ?? 400);
$chart_width = intval($attributes['chartWidth'] ?? 600);
$background_color = $attributes['backgroundColor'] ?? '#ffffff'; $background_color = $attributes['backgroundColor'] ?? '#ffffff';
$bar_color = $attributes['barColor'] ?? '#0073aa'; $bar_color = $attributes['barColor'] ?? '#0073aa';
$bar_opacity = $attributes['barOpacity'] ?? 1; $bar_opacity = floatval($attributes['barOpacity'] ?? 0.8);
$show_grid_y = $attributes['showGridY'] ?? true; $show_grid_y = $attributes['showGridY'] ?? true;
$grid_color = $attributes['gridColor'] ?? '#e0e0e0'; $show_grid_x = $attributes['showGridX'] ?? true;
$x_grid_color = $attributes['xGridColor'] ?? '#e0e0e0';
$y_grid_color = $attributes['yGridColor'] ?? '#e0e0e0';
$x_grid_width = intval($attributes['xGridWidth'] ?? 1);
$y_grid_width = intval($attributes['yGridWidth'] ?? 1);
$show_bar_values = $attributes['showBarValues'] ?? false;
$display_chart_title = $attributes['displayChartTitle'] ?? false;
$chart_title = $attributes['chartTitle'] ?? '';
$x_axis_label = $attributes['xAxisLabel'] ?? '';
$y_axis_label = $attributes['yAxisLabel'] ?? '';
$chart_color_source = $attributes['chartColorSource'] ?? 'default';
$chart_data = $attributes['chartData'] ?? array();
$chart_custom_colors = $attributes['chartCustomColors'] ?? array();
// Ensure chart data is properly formatted
if (is_string($chart_data)) {
$chart_data = json_decode($chart_data, true) ?? array();
}
if (is_string($chart_custom_colors)) {
$chart_custom_colors = json_decode($chart_custom_colors, true) ?? array();
}
// Create unique ID for this graph instance
$block_id = 'bar-graph-' . uniqid();
// Prepare data for JavaScript
$graph_data = array(
'blockId' => $block_id,
'attributes' => array(
'chartHeight' => $chart_height,
'chartWidth' => $chart_width,
'backgroundColor' => $background_color,
'barColor' => $bar_color,
'barOpacity' => $bar_opacity,
'showGridY' => $show_grid_y,
'showGridX' => $show_grid_x,
'xGridColor' => $x_grid_color,
'yGridColor' => $y_grid_color,
'xGridWidth' => $x_grid_width,
'yGridWidth' => $y_grid_width,
'showBarValues' => $show_bar_values,
'displayChartTitle' => $display_chart_title,
'chartTitle' => $chart_title,
'xAxisLabel' => $x_axis_label,
'yAxisLabel' => $y_axis_label,
'chartColorSource' => $chart_color_source,
'chartData' => $chart_data,
'chartCustomColors' => $chart_custom_colors
)
);
// Enqueue D3.js // Enqueue D3.js
wp_enqueue_script('d3'); wp_enqueue_script(
'lcp-d3',
'https://d3js.org/d3.v7.min.js',
array(),
'7.0.0',
true
);
// Return the block's container // Enqueue our view script
wp_enqueue_script(
'lcp-bar-graph-view',
plugins_url('build/view.js', __FILE__),
array('lcp-d3'),
filemtime(plugin_dir_path(__FILE__) . 'build/view.js'),
true
);
// Pass data to JavaScript
wp_add_inline_script(
'lcp-bar-graph-view',
'window.lcpBarGraphData = window.lcpBarGraphData || {};' .
'window.lcpBarGraphData["' . $block_id . '"] = ' . wp_json_encode($graph_data) . ';',
'before'
);
// Return the block's container with responsive width
return sprintf( return sprintf(
'<div class="wp-block-lcp-bar-graph"><div class="lcp-bar-graph" style="height: %s; background-color: %s;" data-bar-color="%s" data-bar-opacity="%f" data-show-grid="%s" data-grid-color="%s"></div></div>', '<div class="wp-block-lcp-bar-graph" id="%s">
esc_attr($chart_height), <div class="bar-graph-container" style="width: 100%%; height: %dpx;"></div>
esc_attr($background_color), </div>',
esc_attr($bar_color), esc_attr($block_id),
esc_attr($bar_opacity), esc_attr($chart_height)
esc_attr($show_grid_y ? 'true' : 'false'),
esc_attr($grid_color)
); );
} }

View File

@ -0,0 +1,82 @@
<?php
function render_bar_graph_block($attributes, $content) {
// Ensure all required attributes have default values
$defaults = array(
'chartHeight' => 400,
'chartWidth' => 600,
'barColor' => '#FF6384',
'barOpacity' => 0.8,
'backgroundColor' => '#FFFFFF',
'showGridY' => true,
'showGridX' => true,
'yGridColor' => '#e0e0e0',
'xGridColor' => '#e0e0e0',
'xGridWidth' => 1,
'yGridWidth' => 1,
'chartData' => array(),
'displayChartTitle' => false,
'chartTitle' => '',
'showBarValues' => false,
'xAxisLabel' => '',
'yAxisLabel' => '',
'chartColorSource' => 'default',
'chartCustomColors' => array()
);
// Merge provided attributes with defaults
$attributes = wp_parse_args($attributes, $defaults);
// If chartData is a string (JSON), decode it
if (is_string($attributes['chartData'])) {
$attributes['chartData'] = json_decode($attributes['chartData'], true);
}
// If chartCustomColors is a string (JSON), decode it
if (is_string($attributes['chartCustomColors'])) {
$attributes['chartCustomColors'] = json_decode($attributes['chartCustomColors'], true);
}
// Create a unique ID for this instance of the graph
$block_id = 'bar-graph-' . uniqid();
// Prepare the data for JavaScript
$js_data = array(
'attributes' => $attributes,
'blockId' => $block_id
);
// Enqueue D3.js if not already enqueued
wp_enqueue_script(
'lcp-d3',
'https://d3js.org/d3.v7.min.js',
array(),
'7.0.0',
true
);
// Enqueue the view script if not already enqueued
wp_enqueue_script(
'lcp-bar-graph-view',
plugins_url('build/view.js', __FILE__),
array('lcp-d3'),
filemtime(plugin_dir_path(__FILE__) . 'build/view.js'),
true
);
// Pass the data to JavaScript
wp_add_inline_script(
'lcp-bar-graph-view',
'window.lcpBarGraphData = window.lcpBarGraphData || {};' .
'window.lcpBarGraphData["' . $block_id . '"] = ' . wp_json_encode($js_data) . ';',
'before'
);
// Return the container for the graph
return sprintf(
'<div class="wp-block-lcp-bar-graph" id="%s">
<div class="bar-graph-container" style="min-height:%dpx"></div>
</div>',
esc_attr($block_id),
esc_attr($attributes['chartHeight'])
);
}

View File

@ -3,12 +3,13 @@
"apiVersion": 2, "apiVersion": 2,
"name": "lcp/bar-graph", "name": "lcp/bar-graph",
"version": "0.1.0", "version": "0.1.0",
"title": "LCP Bar Graph", "title": "Bar Graph",
"category": "widgets", "category": "lcp-blocks",
"icon": "chart-bar", "icon": "chart-bar",
"description": "Display data in a bar graph format.", "description": "Display data as a bar graph",
"supports": { "supports": {
"html": false "html": false,
"anchor": true
}, },
"textdomain": "lcp", "textdomain": "lcp",
"editorScript": "file:./index.js", "editorScript": "file:./index.js",
@ -24,6 +25,14 @@
"type": "array", "type": "array",
"default": [] "default": []
}, },
"chartData": {
"type": "object",
"default": {}
},
"dataSource": {
"type": "string",
"default": ""
},
"showBarValues": { "showBarValues": {
"type": "boolean", "type": "boolean",
"default": true "default": true
@ -60,14 +69,6 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"chartData": {
"type": "object",
"default": {}
},
"dataSource": {
"type": "string",
"default": "manual_json"
},
"barColor": { "barColor": {
"type": "string", "type": "string",
"default": "#0073aa" "default": "#0073aa"

View File

@ -20,6 +20,192 @@
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script
*/ */
/* eslint-disable no-console */ import * as d3 from 'd3';
console.log( 'Hello World! (from create-block-todo-list block)' );
/* eslint-enable no-console */ window.addEventListener('load', function() {
// Check if we have any bar graphs to render
if (!window.lcpBarGraphData) {
return;
}
// Render each bar graph
Object.entries(window.lcpBarGraphData).forEach(([blockId, data]) => {
const { attributes } = data;
const container = document.getElementById(blockId);
if (!container) return;
renderBarGraph(container, attributes);
});
});
function renderBarGraph(container, attrs) {
// Clear any existing content
const graphContainer = container.querySelector('.bar-graph-container');
if (!graphContainer) return;
graphContainer.innerHTML = '';
// Get the actual width of the container
const containerWidth = graphContainer.clientWidth;
// Set up dimensions
const margin = { top: 40, right: 20, bottom: 60, left: 60 };
const width = containerWidth - margin.left - margin.right;
const height = attrs.chartHeight - margin.top - margin.bottom;
// Convert data to array format
const chartDataArray = [];
if (attrs.chartData && typeof attrs.chartData === 'object') {
Object.entries(attrs.chartData).forEach(([dataset, items]) => {
if (Array.isArray(items)) {
items.forEach(item => {
chartDataArray.push({
dataset,
label: item.label || '',
value: parseFloat(item.value) || 0,
color: item.color || attrs.barColor
});
});
}
});
}
// Create SVG
const svg = d3.select(graphContainer)
.append('svg')
.attr('width', containerWidth)
.attr('height', attrs.chartHeight)
.style('background-color', attrs.backgroundColor);
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Create scales
const xScale = d3.scaleBand()
.domain(chartDataArray.map(d => d.label))
.range([0, width])
.padding(0.1);
const yScale = d3.scaleLinear()
.domain([0, d3.max(chartDataArray, d => d.value) || 100])
.range([height, 0]);
// Get color for a datapoint
const getColor = (datapoint) => {
switch (attrs.chartColorSource) {
case 'singleColor':
return attrs.barColor;
case 'customColors':
const customColor = attrs.chartCustomColors?.find(
c => c.dataset === datapoint.dataset && c.label === datapoint.label
);
return customColor ? customColor.color : datapoint.color;
case 'default':
default:
return datapoint.color;
}
};
// Add X grid
if (attrs.showGridX) {
g.append('g')
.attr('class', 'grid x-grid')
.attr('transform', `translate(0,${height})`)
.style('color', attrs.xGridColor)
.style('stroke-width', attrs.xGridWidth)
.call(d3.axisBottom(xScale)
.tickSize(-height)
.tickFormat(''));
}
// Add Y grid
if (attrs.showGridY) {
g.append('g')
.attr('class', 'grid y-grid')
.style('color', attrs.yGridColor)
.style('stroke-width', attrs.yGridWidth)
.call(d3.axisLeft(yScale)
.tickSize(-width)
.tickFormat(''));
}
// Add bars
g.selectAll('rect')
.data(chartDataArray)
.enter()
.append('rect')
.attr('x', d => xScale(d.label))
.attr('y', d => yScale(d.value))
.attr('width', xScale.bandwidth())
.attr('height', d => height - yScale(d.value))
.attr('fill', d => getColor(d))
.style('opacity', attrs.barOpacity);
// Add bar values
if (attrs.showBarValues) {
g.selectAll('.bar-value')
.data(chartDataArray)
.enter()
.append('text')
.attr('class', 'bar-value')
.attr('x', d => xScale(d.label) + xScale.bandwidth() / 2)
.attr('y', d => yScale(d.value) - 5)
.attr('text-anchor', 'middle')
.text(d => d.value);
}
// Add X axis
g.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(xScale))
.selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em')
.attr('transform', 'rotate(-45)');
// Add Y axis
g.append('g')
.attr('class', 'y-axis')
.call(d3.axisLeft(yScale));
// Add title
if (attrs.displayChartTitle && attrs.chartTitle) {
svg.append('text')
.attr('x', containerWidth / 2)
.attr('y', margin.top / 2)
.attr('text-anchor', 'middle')
.style('font-size', '16px')
.text(attrs.chartTitle);
}
// Add X axis label
if (attrs.xAxisLabel) {
svg.append('text')
.attr('x', containerWidth / 2)
.attr('y', attrs.chartHeight - 10)
.attr('text-anchor', 'middle')
.text(attrs.xAxisLabel);
}
// Add Y axis label
if (attrs.yAxisLabel) {
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', -(attrs.chartHeight / 2))
.attr('y', 20)
.attr('text-anchor', 'middle')
.text(attrs.yAxisLabel);
}
// Add resize handler
const resizeObserver = new ResizeObserver(() => {
const newWidth = graphContainer.clientWidth;
if (newWidth !== containerWidth) {
// Clear and redraw
graphContainer.innerHTML = '';
renderBarGraph(container, attrs);
}
});
resizeObserver.observe(graphContainer);
}

View File

@ -17,6 +17,7 @@ if (!defined('ABSPATH')) {
// Include block files // Include block files
require_once plugin_dir_path(__FILE__) . 'blocks/bar-graph/lcp-bar-graph.php'; require_once plugin_dir_path(__FILE__) . 'blocks/bar-graph/lcp-bar-graph.php';
require_once plugin_dir_path(__FILE__) . 'blocks/bar-graph/render.php';
/** /**
* Add custom category for LCP blocks * Add custom category for LCP blocks
@ -35,6 +36,16 @@ function lcp_block_categories($categories) {
} }
add_filter('block_categories_all', 'lcp_block_categories', 10, 1); add_filter('block_categories_all', 'lcp_block_categories', 10, 1);
function create_block_lcp_data_blocks_block_init() {
register_block_type(
__DIR__ . '/blocks/bar-graph/build',
array(
'render_callback' => 'lcp_render_bar_graph_block'
)
);
}
add_action('init', 'create_block_lcp_data_blocks_block_init');
// Register the Data Collection Custom Post Type // Register the Data Collection Custom Post Type
function lcp_register_data_collection_post_type() { function lcp_register_data_collection_post_type() {
$labels = array( $labels = array(