528 lines
20 KiB
JavaScript
528 lines
20 KiB
JavaScript
/**
|
|
* WordPress dependencies
|
|
*/
|
|
import { __ } from '@wordpress/i18n';
|
|
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
|
|
import {
|
|
PanelBody,
|
|
Panel,
|
|
ColorPicker,
|
|
RangeControl,
|
|
ToggleControl,
|
|
TabPanel,
|
|
TextControl,
|
|
Button,
|
|
Popover,
|
|
TextareaControl
|
|
} from '@wordpress/components';
|
|
|
|
import {useState} from '@wordpress/element';
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import './editor.scss';
|
|
import LCPDataSelector from '../../../components/LCPDataSelector';
|
|
import BarGraph from './components/BarGraph';
|
|
import LCPDimensionControl from '../../../components/LCPDimensionControl';
|
|
import ColorControls from './components/ColorControls';
|
|
|
|
export default function Edit({ attributes, setAttributes }) {
|
|
const {
|
|
chartHeight,
|
|
chartWidth,
|
|
barColor,
|
|
barOpacity,
|
|
backgroundColor,
|
|
showGridY,
|
|
yGridColor,
|
|
xGridColor,
|
|
xGridWidth,
|
|
yGridWidth,
|
|
chartData,
|
|
dataSource,
|
|
displayChartTitle,
|
|
chartTitle,
|
|
allowDownload,
|
|
downloadMaxWidth,
|
|
showSorting,
|
|
showFiltering,
|
|
showBarValues,
|
|
showGridX,
|
|
xAxisLabel,
|
|
yAxisLabel,
|
|
chartColorSource,
|
|
chartCustomColors,
|
|
enableHierarchicalView,
|
|
selectedParentId } = attributes;
|
|
|
|
const blockProps = useBlockProps();
|
|
|
|
const handleDataChange = (newData) => {
|
|
console.log('New data:', newData); // Debug log
|
|
setAttributes({ chartData: newData });
|
|
};
|
|
|
|
const handleDataSourceChange = (newSource) => {
|
|
setAttributes({
|
|
dataSource: newSource,
|
|
chartData: {} // Reset data when source changes
|
|
});
|
|
};
|
|
|
|
const handleCustomColorChange = (dataset, label, color) => {
|
|
const existingColors = [...chartCustomColors];
|
|
const existingIndex = existingColors.findIndex(
|
|
c => c.dataset === dataset && c.label === label
|
|
);
|
|
|
|
if (existingIndex >= 0) {
|
|
existingColors[existingIndex].color = color;
|
|
} else {
|
|
existingColors.push({ dataset, label, color });
|
|
}
|
|
|
|
setAttributes({ chartCustomColors: existingColors });
|
|
};
|
|
|
|
const handleDownload = () => {
|
|
// Get the SVG element
|
|
const svg = document.querySelector('.bar-graph svg');
|
|
if (!svg) return;
|
|
|
|
// Create a canvas
|
|
const canvas = document.createElement('canvas');
|
|
const svgData = new XMLSerializer().serializeToString(svg);
|
|
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
|
|
const DOMURL = window.URL || window.webkitURL || window;
|
|
const url = DOMURL.createObjectURL(svgBlob);
|
|
const img = new Image();
|
|
|
|
img.onload = () => {
|
|
// Set canvas dimensions
|
|
canvas.width = svg.width.baseVal.value;
|
|
canvas.height = svg.height.baseVal.value;
|
|
|
|
// Draw background
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.fillStyle = backgroundColor;
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
// Draw the image
|
|
ctx.drawImage(img, 0, 0);
|
|
|
|
// Convert to blob and download
|
|
canvas.toBlob((blob) => {
|
|
const downloadUrl = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = downloadUrl;
|
|
a.download = 'bar-graph.png';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(downloadUrl);
|
|
DOMURL.revokeObjectURL(url);
|
|
}, 'image/png');
|
|
};
|
|
|
|
img.src = url;
|
|
};
|
|
|
|
// Grid Color Popovers
|
|
const [isYGridColorPopoverOpen, setIsYGridColorPopoverOpen] = useState(false);
|
|
const [isXGridColorPopoverOpen, setIsXGridColorPopoverOpen] = useState(false);
|
|
|
|
// Toggle the popover visibility
|
|
const toggleYGridColorPopover = () => {
|
|
setIsYGridColorPopoverOpen(!isYGridColorPopoverOpen);
|
|
};
|
|
|
|
const toggleXGridColorPopover = () => {
|
|
setIsXGridColorPopoverOpen(!isXGridColorPopoverOpen);
|
|
};
|
|
|
|
// Handle color changes
|
|
const onYGridColorChange = (newColor) => {
|
|
setAttributes({ yGridColor: newColor });
|
|
};
|
|
|
|
const onXGridColorChange = (newColor) => {
|
|
setAttributes({ xGridColor: newColor });
|
|
};
|
|
|
|
// Background Color Popover
|
|
const [isBackgroundColorPopoverOpen, setIsBackgroundColorPopoverOpen] = useState(false);
|
|
|
|
// Toggle the background popover visibility
|
|
const toggleBackgroundColorPopover = () => {
|
|
setIsBackgroundColorPopoverOpen(!isBackgroundColorPopoverOpen);
|
|
};
|
|
|
|
// Handle color change
|
|
const onBackgroundColorChange = (newColor) => {
|
|
setAttributes({ backgroundColor: newColor });
|
|
};
|
|
|
|
|
|
// Debug log to check chartData
|
|
console.log('Chart data:', chartData);
|
|
|
|
// Ensure chartData is an object
|
|
if (!attributes.chartData || typeof attributes.chartData !== 'object') {
|
|
setAttributes({ chartData: {} });
|
|
}
|
|
|
|
const updateChartData = (value) => {
|
|
try {
|
|
// Attempt to parse the JSON input
|
|
const parsedData = JSON.parse(value);
|
|
|
|
// Validate the structure
|
|
if (typeof parsedData === 'object' && parsedData !== null) {
|
|
// Check if the data follows our expected format
|
|
let isValid = true;
|
|
Object.entries(parsedData).forEach(([dataset, items]) => {
|
|
if (!Array.isArray(items)) {
|
|
isValid = false;
|
|
} else {
|
|
items.forEach(item => {
|
|
if (!item.id || typeof item.id !== 'string') {
|
|
isValid = false;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
if (isValid) {
|
|
setAttributes({ chartData: parsedData });
|
|
} else {
|
|
console.error('Invalid data structure');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error('Invalid JSON:', e);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div {...blockProps}>
|
|
<InspectorControls>
|
|
<TabPanel
|
|
className="lcp-tab-panel"
|
|
activeClass="active-tab"
|
|
tabs={[
|
|
{
|
|
name: 'data',
|
|
title: __('Data Settings', 'lcp'),
|
|
className: 'tab-data',
|
|
},
|
|
{
|
|
name: 'appearance',
|
|
title: __('Appearance', 'lcp'),
|
|
className: 'tab-appearance',
|
|
},
|
|
{
|
|
name: 'tools',
|
|
title: __('Tools Settings', 'lcp'),
|
|
className: 'tab-tools',
|
|
},
|
|
]}
|
|
>
|
|
{(tab) => {
|
|
if (tab.name === 'data') {
|
|
return (
|
|
<Panel>
|
|
<PanelBody title="Data Settings">
|
|
|
|
<LCPDataSelector
|
|
value={chartData}
|
|
onChange={handleDataChange}
|
|
dataSource={dataSource}
|
|
onDataSourceChange={handleDataSourceChange}
|
|
/>
|
|
</PanelBody>
|
|
<PanelBody title="Chart Settings">
|
|
<ToggleControl
|
|
label={__('Enable Hierarchical View', 'lcp')}
|
|
help={__('Display data hierarchically. Click bars to show their children.', 'lcp')}
|
|
checked={attributes.enableHierarchicalView}
|
|
onChange={(value) => {
|
|
setAttributes({
|
|
enableHierarchicalView: value,
|
|
selectedParentId: null // Reset when toggling
|
|
});
|
|
}}
|
|
/>
|
|
<ToggleControl
|
|
label={__('Display Chart Title', 'lcp')}
|
|
checked={displayChartTitle}
|
|
onChange={(value) => setAttributes({ displayChartTitle: value })}
|
|
/>
|
|
{displayChartTitle && (
|
|
<TextControl
|
|
label={__('Chart Title', 'lcp')}
|
|
value={chartTitle}
|
|
onChange={(value) => setAttributes({ chartTitle: value })}
|
|
/>
|
|
)}
|
|
<LCPDimensionControl
|
|
label={__('Chart Width', 'lcp')}
|
|
value={chartWidth}
|
|
onChange={(value) => setAttributes({ chartWidth: value })}
|
|
/>
|
|
<LCPDimensionControl
|
|
label={__('Chart Height', 'lcp')}
|
|
value={chartHeight}
|
|
onChange={(value) => setAttributes({ chartHeight: value })}
|
|
/>
|
|
</PanelBody>
|
|
<PanelBody title="Appearance">
|
|
|
|
<div className="background-color-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '10px' }}>
|
|
<span>Background Color</span>
|
|
<Button
|
|
className="background-color-button"
|
|
onClick={toggleBackgroundColorPopover}
|
|
style={{
|
|
backgroundColor: backgroundColor,
|
|
width: '26px',
|
|
height: '26px',
|
|
borderRadius: '50%',
|
|
border: '1px solid #ccc',
|
|
}}
|
|
></Button>
|
|
{isBackgroundColorPopoverOpen && (
|
|
<Popover
|
|
position="bottom center"
|
|
onClose={toggleBackgroundColorPopover} // Close the popover when clicked outside
|
|
>
|
|
<ColorPicker
|
|
color={backgroundColor}
|
|
onChangeComplete={(color) => onBackgroundColorChange(color.hex)} // Update color
|
|
/>
|
|
</Popover>
|
|
)}
|
|
</div>
|
|
<ColorControls
|
|
data={chartData}
|
|
colorSource={chartColorSource}
|
|
singleColor={barColor}
|
|
customColors={chartCustomColors}
|
|
onColorSourceChange={(value) => setAttributes({ chartColorSource: value })}
|
|
onSingleColorChange={(color) => setAttributes({ barColor: color })}
|
|
onCustomColorChange={handleCustomColorChange}
|
|
/>
|
|
<RangeControl
|
|
label={__('Bar Opacity', 'lcp')}
|
|
value={barOpacity}
|
|
onChange={(value) => setAttributes({ barOpacity: value })}
|
|
min={0}
|
|
max={1}
|
|
step={0.1}
|
|
/>
|
|
|
|
<ToggleControl
|
|
label={__('Show Bar Values', 'lcp')}
|
|
checked={showBarValues}
|
|
onChange={(value) => setAttributes({ showBarValues: value })}
|
|
/>
|
|
</PanelBody>
|
|
<PanelBody title="Grid Settings">
|
|
<TextControl
|
|
label={__('X-Axis Label', 'lcp')}
|
|
value={xAxisLabel}
|
|
onChange={(value) => setAttributes({ xAxisLabel: value })}
|
|
/>
|
|
<TextControl
|
|
label={__('Y-Axis Label', 'lcp')}
|
|
value={yAxisLabel}
|
|
onChange={(value) => setAttributes({ yAxisLabel: value })}
|
|
/>
|
|
<ToggleControl
|
|
label={__('Show X-Axis Grid', 'lcp')}
|
|
checked={showGridX}
|
|
onChange={(value) => setAttributes({ showGridX: value })}
|
|
/>
|
|
<ToggleControl
|
|
label={__('Show Y-Axis Grid', 'lcp')}
|
|
checked={showGridY}
|
|
onChange={(value) => setAttributes({ showGridY: value })}
|
|
/>
|
|
{showGridY && (
|
|
<>
|
|
<div className="y-grid-color-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '8px' }}>
|
|
<span>Y-Axis Grid Color</span>
|
|
<Button
|
|
className="grid-color-button"
|
|
onClick={toggleYGridColorPopover}
|
|
style={{
|
|
backgroundColor: yGridColor,
|
|
width: '26px',
|
|
height: '26px',
|
|
borderRadius: '50%',
|
|
border: '1px solid #ccc',
|
|
}}
|
|
></Button>
|
|
{isYGridColorPopoverOpen && (
|
|
<Popover
|
|
position="bottom center"
|
|
onClose={toggleYGridColorPopover}
|
|
>
|
|
<ColorPicker
|
|
color={yGridColor}
|
|
onChangeComplete={(color) => onYGridColorChange(color.hex)}
|
|
/>
|
|
</Popover>
|
|
)}
|
|
</div>
|
|
<RangeControl
|
|
label={__('Y-Axis Grid Width', 'lcp')}
|
|
value={yGridWidth}
|
|
onChange={(value) => setAttributes({ yGridWidth: value })}
|
|
min={1}
|
|
max={5}
|
|
step={1}
|
|
/>
|
|
</>
|
|
)}
|
|
|
|
{showGridX && (
|
|
<>
|
|
<div className="x-grid-color-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '8px' }}>
|
|
<span>X-Axis Grid Color</span>
|
|
<Button
|
|
className="grid-color-button"
|
|
onClick={toggleXGridColorPopover}
|
|
style={{
|
|
backgroundColor: xGridColor,
|
|
width: '26px',
|
|
height: '26px',
|
|
borderRadius: '50%',
|
|
border: '1px solid #ccc',
|
|
}}
|
|
></Button>
|
|
{isXGridColorPopoverOpen && (
|
|
<Popover
|
|
position="bottom center"
|
|
onClose={toggleXGridColorPopover}
|
|
>
|
|
<ColorPicker
|
|
color={xGridColor}
|
|
onChangeComplete={(color) => onXGridColorChange(color.hex)}
|
|
/>
|
|
</Popover>
|
|
)}
|
|
</div>
|
|
<RangeControl
|
|
label={__('X-Axis Grid Width', 'lcp')}
|
|
value={xGridWidth}
|
|
onChange={(value) => setAttributes({ xGridWidth: value })}
|
|
min={1}
|
|
max={5}
|
|
step={1}
|
|
/>
|
|
</>
|
|
)}
|
|
</PanelBody>
|
|
</Panel>
|
|
);
|
|
}
|
|
if (tab.name === 'appearance') {
|
|
return (
|
|
<PanelBody>
|
|
|
|
</PanelBody>
|
|
);
|
|
}
|
|
if (tab.name === 'tools') {
|
|
return (
|
|
<PanelBody>
|
|
<ToggleControl
|
|
label={__('Allow Download', 'lcp')}
|
|
checked={allowDownload}
|
|
onChange={(value) => setAttributes({ allowDownload: value })}
|
|
/>
|
|
{allowDownload && (
|
|
<TextControl
|
|
type="number"
|
|
label={__('Max Download Width (px)', 'lcp')}
|
|
value={parseInt(downloadMaxWidth)}
|
|
onChange={(value) => setAttributes({ downloadMaxWidth: `${value}px` })}
|
|
min={100}
|
|
max={5000}
|
|
/>
|
|
)}
|
|
<ToggleControl
|
|
label={__('Show Sorting Options', 'lcp')}
|
|
checked={showSorting}
|
|
onChange={(value) => setAttributes({ showSorting: value })}
|
|
/>
|
|
<ToggleControl
|
|
label={__('Show Filtering Options', 'lcp')}
|
|
checked={showFiltering}
|
|
onChange={(value) => setAttributes({ showFiltering: value })}
|
|
/>
|
|
</PanelBody>
|
|
);
|
|
}
|
|
}}
|
|
</TabPanel>
|
|
</InspectorControls>
|
|
|
|
{allowDownload && (
|
|
<div className="lcp-bar-graph-toolbar">
|
|
<Button
|
|
isPrimary
|
|
onClick={handleDownload}
|
|
icon="download"
|
|
>
|
|
{__('Download Graph', 'lcp')}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
|
|
{chartData && Object.keys(chartData).length > 0 ? (
|
|
<BarGraph
|
|
data={chartData}
|
|
height={chartHeight}
|
|
width={chartWidth}
|
|
backgroundColor={backgroundColor}
|
|
defaultBarColor={barColor}
|
|
barOpacity={barOpacity}
|
|
showGridX={showGridX}
|
|
showGridY={showGridY}
|
|
yGridColor={yGridColor}
|
|
xGridColor={xGridColor}
|
|
xGridWidth={xGridWidth}
|
|
yGridWidth={yGridWidth}
|
|
title={displayChartTitle ? chartTitle : ''}
|
|
showBarValues={showBarValues}
|
|
xAxisLabel={xAxisLabel}
|
|
yAxisLabel={yAxisLabel}
|
|
colorSource={chartColorSource}
|
|
customColors={chartCustomColors}
|
|
enableHierarchicalView={enableHierarchicalView}
|
|
selectedParentId={selectedParentId}
|
|
setAttributes={setAttributes}
|
|
/>
|
|
) : (
|
|
<div
|
|
className="lcp-bar-graph-placeholder"
|
|
style={{
|
|
height: chartHeight,
|
|
width: chartWidth,
|
|
backgroundColor: backgroundColor,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
border: '2px dashed #ccc',
|
|
borderRadius: '4px',
|
|
color: '#666',
|
|
}}
|
|
>
|
|
{__('Please add data using the Data Settings panel', 'lcp')}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|