PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.11
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.11
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / bubble-chart / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.11, at blocks/bubble-chart/index.js

161 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = window.wp.element.createElement;
3 var { registerBlockType } = window.wp.blocks;
4 var { InspectorControls, PanelColorSettings } = window.wp.blockEditor;
5 var { PanelBody, RangeControl, SelectControl, TextControl, TextareaControl, ToggleControl, Button, ColorPicker, Popover } = window.wp.components;
6 var { __ } = window.wp.i18n;
7 var { useEffect, useRef, useState } = window.wp.element;
8
9 var LEG_POS = [{label:'Top',value:'top'},{label:'Bottom',value:'bottom'},{label:'Left',value:'left'},{label:'Right',value:'right'}];
10
11 function parseHex(hex, alpha) {
12 hex = (hex||'#6c3fb5').replace('#','');
13 if (hex.length===3) hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
14 var r=parseInt(hex.substring(0,2),16),g=parseInt(hex.substring(2,4),16),b=parseInt(hex.substring(4,6),16);
15 return 'rgba('+r+','+g+','+b+','+(alpha/100).toFixed(2)+')';
16 }
17
18 function parseBubbles(text) {
19 return (text||'').split('\n').filter(Boolean).map(function(line) {
20 var parts = line.split(',').map(function(s){return parseFloat(s)||0;});
21 return { x: parts[0]||0, y: parts[1]||0, r: parts[2]||8 };
22 });
23 }
24
25 function BubblePreview(a) {
26 var canvasRef = useRef(null);
27 var chartRef = useRef(null);
28 useEffect(function() {
29 var canvas = canvasRef.current; if (!canvas) return;
30 function render(ChartJS) {
31 if (chartRef.current) { chartRef.current.destroy(); chartRef.current=null; }
32 var datasets;
33 try { datasets = JSON.parse(a.datasetsJson||'[]'); } catch(e){ datasets=[]; }
34 var dsData = datasets.map(function(ds) {
35 return {
36 label: ds.label||'',
37 data: parseBubbles(ds.bubbles),
38 backgroundColor: parseHex(ds.color||'#6c3fb5', a.fillAlpha),
39 borderColor: ds.color||'#6c3fb5',
40 borderWidth: 2
41 };
42 });
43 var h = a.chartHeight;
44 canvas.style.height = h+'px';
45 chartRef.current = new ChartJS(canvas, {
46 type: 'bubble',
47 data: { datasets: dsData },
48 options: {
49 responsive: true, maintainAspectRatio: false, animation: false,
50 plugins: {
51 legend: { display: !!a.showLegend, position: a.legendPos, labels: { font: { size: a.labelFontSize||12 } } },
52 title: { display: !!(a.showTitle&&a.chartTitle), text: a.chartTitle, font: { size: a.titleFontSize||16 } }
53 },
54 scales: {
55 x: { grid: { display: !!a.showGrid } },
56 y: { grid: { display: !!a.showGrid } }
57 }
58 }
59 });
60 }
61 if (window.Chart) { render(window.Chart); return function(){if(chartRef.current){chartRef.current.destroy();chartRef.current=null;}};}
62 var s = document.createElement('script');
63 s.src = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js';
64 s.onload = function(){ render(window.Chart); };
65 document.head.appendChild(s);
66 return function(){ if(chartRef.current){chartRef.current.destroy();chartRef.current=null;} };
67 }, [a.datasetsJson, a.fillAlpha, a.chartHeight, a.showLegend, a.legendPos, a.showTitle, a.chartTitle, a.showGrid, a.titleFontSize, a.labelFontSize]);
68
69 return el('div',{style:{background:a.bgColor,borderRadius:a.borderRadius+'px',padding:'24px'}},
70 el('div',{style:{position:'relative',height:a.chartHeight+'px'}},
71 el('canvas',{ref:canvasRef,style:{height:a.chartHeight+'px'}})));
72 }
73
74 function DatasetEditor(a, set) {
75 var datasets;
76 try { datasets = JSON.parse(a.datasetsJson||'[]'); } catch(e){ datasets=[]; }
77 function save(ds) { set({datasetsJson: JSON.stringify(ds)}); }
78 return el('div',null,
79 datasets.map(function(ds,i) {
80 return el('div',{key:i,style:{border:'1px solid #e5e7eb',borderRadius:'8px',padding:'12px',marginBottom:'12px'}},
81 el('div',{style:{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:'8px'}},
82 el('strong',null,(ds.label||__('Dataset '+(i+1)))),
83 el(Button,{isDestructive:true,isSmall:true,onClick:function(){var d=[...datasets];d.splice(i,1);save(d);}},__('Remove')),
84 ),
85 el(TextControl,{label:__('Label'),value:ds.label||'',onChange:function(v){var d=[...datasets];d[i]={...d[i],label:v};save(d);}}),
86 el(BkbgColorSwatch,{label:__('Color'),value:ds.color||'#6c3fb5',onChange:function(v){var d=[...datasets];d[i]={...d[i],color:v};save(d);}}),
87 el('p',{style:{margin:'0 0 4px',fontSize:'11px',color:'#757575'}},__('Bubbles: x,y,radius — one per line')),
88 el(TextareaControl,{label:__('Bubbles (x,y,r per line)'),value:ds.bubbles||'',rows:5,onChange:function(v){var d=[...datasets];d[i]={...d[i],bubbles:v};save(d);}}),
89 );
90 }),
91 el(Button,{variant:'secondary',onClick:function(){var d=[...datasets,{label:'Dataset '+(datasets.length+1),color:'#10b981',bubbles:'10,10,8\n20,30,15'}];save(d);}},__('+ Add Dataset')),
92 );
93 }
94
95 /* ── colour-swatch + popover ── */
96 function BkbgColorSwatch(p) {
97 var st = useState(false), open = st[0], setOpen = st[1];
98 return el('div', { style:{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'4px 0', gap:'8px' } },
99 el('span', { style:{ fontSize:'12px', color:'#1e1e1e', flex:1, lineHeight:1.4 } }, p.label),
100 el('div', { style:{ position:'relative', flexShrink:0 } },
101 el('button', { type:'button', title: p.value||'none', onClick: function(){ setOpen(!open); },
102 style:{ width:'28px', height:'28px', borderRadius:'4px', border: open ? '2px solid #007cba' : '2px solid #ddd', cursor:'pointer', padding:0, display:'block', background: p.value||'#ffffff', flexShrink:0 } }),
103 open && el(Popover, { position:'bottom left', onClose: function(){ setOpen(false); } },
104 el('div', { style:{ padding:'8px' }, onMouseDown: function(e){ e.stopPropagation(); } },
105 el('div', { style:{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:'6px' } },
106 el('strong', { style:{ fontSize:'12px' } }, p.label),
107 el(Button, { icon:'no-alt', isSmall:true, onClick: function(){ setOpen(false); } })
108 ),
109 el(ColorPicker, { color: p.value, enableAlpha:true, onChange: p.onChange })
110 )
111 )
112 )
113 );
114 }
115
116 registerBlockType('blockenberg/bubble-chart', {
117 icon: el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', width: 24, height: 24 },
118 el('circle', { cx: 8, cy: 14, r: 5, fill: 'currentColor', opacity: 0.3 }),
119 el('circle', { cx: 16, cy: 8, r: 4, fill: 'currentColor', opacity: 0.5 }),
120 el('circle', { cx: 14, cy: 16, r: 3, fill: 'currentColor', opacity: 0.7 }),
121 el('circle', { cx: 6, cy: 7, r: 2, fill: 'currentColor' })
122 ),
123 edit: function(props) {
124 var a = props.attributes;
125 var set = props.setAttributes;
126 return el('div',null,
127 el(InspectorControls,null,
128 el(PanelBody,{title:__('Datasets'),initialOpen:true},
129 DatasetEditor(a, set),
130 ),
131 el(PanelBody,{title:__('Chart Options'),initialOpen:false},
132 el(ToggleControl,{label:__('Show Title'),checked:a.showTitle,onChange:v=>set({showTitle:v}),__nextHasNoMarginBottom:true}),
133 a.showTitle&&el(TextControl,{label:__('Title'),value:a.chartTitle,onChange:v=>set({chartTitle:v})}),
134 el(RangeControl,{label:__('Chart Height (px)'),value:a.chartHeight,min:200,max:700,onChange:v=>set({chartHeight:v})}),
135 el(RangeControl,{label:__('Fill Opacity %'),value:a.fillAlpha,min:10,max:100,onChange:v=>set({fillAlpha:v})}),
136 el(ToggleControl,{label:__('Show Grid'),checked:a.showGrid,onChange:v=>set({showGrid:v}),__nextHasNoMarginBottom:true}),
137 el(ToggleControl,{label:__('Show Legend'),checked:a.showLegend,onChange:v=>set({showLegend:v}),__nextHasNoMarginBottom:true}),
138 a.showLegend&&el(SelectControl,{label:__('Legend Position'),value:a.legendPos,options:LEG_POS,onChange:v=>set({legendPos:v})}),
139 el(RangeControl,{label:__('Border Radius (px)'),value:a.borderRadius,min:0,max:32,onChange:v=>set({borderRadius:v})}),
140 ),
141 el(PanelBody,{title:__('Typography','blockenberg'),initialOpen:false},
142 el(RangeControl,{label:__('Title Font Size (px)','blockenberg'),value:a.titleFontSize,min:12,max:36,onChange:v=>set({titleFontSize:v})}),
143 el(RangeControl,{label:__('Legend Font Size (px)','blockenberg'),value:a.labelFontSize,min:10,max:24,onChange:v=>set({labelFontSize:v})}),
144 ),
145 el(PanelColorSettings,{title:__('Colors'),initialOpen:false,colorSettings:[
146 {label:__('Card Background'),value:a.bgColor,onChange:v=>set({bgColor:v||'#ffffff'})},
147 ]}),
148 ),
149 el(BubblePreview,a),
150 );
151 },
152
153 save: function({attributes:a}) {
154 var chartData = {datasetsJson:a.datasetsJson,fillAlpha:a.fillAlpha,showLegend:a.showLegend,legendPos:a.legendPos,showTitle:a.showTitle,chartTitle:a.chartTitle,showGrid:a.showGrid};
155 return el('div',{className:'bkbbl-wrap','data-chart':JSON.stringify(chartData),'data-height':a.chartHeight,style:{background:a.bgColor,borderRadius:a.borderRadius+'px',padding:'24px'}},
156 el('div',{style:{position:'relative',height:a.chartHeight+'px'}},
157 el('canvas',{className:'bkbbl-canvas',style:{height:a.chartHeight+'px'}})));
158 }
159 });
160 }() );
161