[QUESTION] How to create a group of multiple traits? #6377
Unanswered
fasenderos
asked this question in
Q&A
Replies: 1 comment
-
Hey, I made you an example (note it won't sync, but it's just an example of how the overall structure of the code would look like). Hopefully, you should be able to edit it and make it work for your own use case. <!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GrapesJS Chart.js Plugin</title>
<!-- Include Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Include GrapesJS -->
<link href="https://unpkg.com/grapesjs/dist/css/grapes.min.css" rel="stylesheet" />
<script src="https://unpkg.com/grapesjs"></script>
<style>
body,
html {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
#gjs {
height: 100vh;
}
</style>
</head>
<body>
<div id="gjs"></div>
<script>
const chartJsPlugin = (editor) => {
// Define a custom trait type for the Chart.js data group
editor.TraitManager.addType('chart-data-group', {
// Create the input elements for the trait
createInput({ trait }) {
const el = document.createElement('div');
el.classList.add('chart-data-group');
// Add initial triplet (data, label, color)
this.addTriplet(el, trait);
// Add "+" button to add more triplets
const addButton = document.createElement('button');
addButton.textContent = '+';
addButton.classList.add('add-triplet');
addButton.onclick = () => this.addTriplet(el, trait);
el.appendChild(addButton);
return el;
},
// Add a new triplet (data, label, color)
addTriplet(container, trait) {
const triplet = document.createElement('div');
triplet.classList.add('triplet');
// Data input
const dataInput = document.createElement('input');
dataInput.type = 'number';
dataInput.placeholder = 'Data';
triplet.appendChild(dataInput);
// Label input
const labelInput = document.createElement('input');
labelInput.type = 'text';
labelInput.placeholder = 'Label';
triplet.appendChild(labelInput);
// Color input
const colorInput = document.createElement('input');
colorInput.type = 'color';
triplet.appendChild(colorInput);
// Remove button for the triplet
const removeButton = document.createElement('button');
removeButton.textContent = '×';
removeButton.onclick = () => triplet.remove();
triplet.appendChild(removeButton);
container.insertBefore(triplet, container.lastChild);
},
// Get the value from the inputs
getValue({ trait }) {
const triplets = [];
const container = trait.target.view.el.querySelector('.chart-data-group');
container?.querySelectorAll('.triplet').forEach((triplet) => {
const data = triplet.querySelector('input[type="number"]').value;
const label = triplet.querySelector('input[type="text"]').value;
const color = triplet.querySelector('input[type="color"]').value;
if (data && label && color) {
triplets.push({ data, label, color });
}
});
return triplets;
},
// Set the value to the inputs
setValue({ trait, value }) {
const container = trait.target.view.el.querySelector('.chart-data-group');
container.innerHTML = ''; // Clear existing triplets
if (value && Array.isArray(value)) {
value.forEach(({ data, label, color }) => {
this.addTriplet(container, trait);
const lastTriplet = container.querySelector('.triplet:last-child');
lastTriplet.querySelector('input[type="number"]').value = data;
lastTriplet.querySelector('input[type="text"]').value = label;
lastTriplet.querySelector('input[type="color"]').value = color;
});
}
// Add the "+" button back
const addButton = document.createElement('button');
addButton.textContent = '+';
addButton.classList.add('add-triplet');
addButton.onclick = () => this.addTriplet(container, trait);
container.appendChild(addButton);
},
// Trigger the component's `renderChart` method when the trait value changes
onUpdate({ trait }) {
const value = this.getValue({ trait });
trait.target.set('chart-data', value); // Sync trait value with component property
trait.target.trigger('change:chart-data'); // Trigger chart update
},
});
// Add a custom component type for Chart.js
editor.DomComponents.addType('chart', {
isComponent: (el) => el.tagName === 'CANVAS',
model: {
defaults: {
tagName: 'canvas',
attributes: { id: 'myChart' }, // Unique ID for the canvas
traits: [
{
type: 'chart-data-group',
name: 'chart-data',
label: 'Chart Data',
},
],
// Default chart data (optional)
'chart-data': [
{ data: 10, label: 'January', color: '#FF0000' },
{ data: 20, label: 'February', color: '#00FF00' },
],
},
// Initialize Chart.js when the component is rendered
init() {
this.listenTo(this, 'change:chart-data', this.renderChart);
},
// Render the chart using Chart.js
renderChart() {
const canvas = this.getEl();
const ctx = canvas.getContext('2d');
const chartData = this.get('chart-data');
if (this.chart) {
this.chart.destroy(); // Destroy existing chart instance
}
this.chart = new Chart(ctx, {
type: 'bar', // Chart type (e.g., bar, line, pie)
data: {
labels: chartData.map((item) => item.label),
datasets: [
{
label: 'My Dataset',
data: chartData.map((item) => item.data),
backgroundColor: chartData.map((item) => item.color),
},
],
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
},
},
},
});
},
},
});
// Add a block for the Chart component
editor.BlockManager.add('chart-block', {
label: 'Chart',
content: '<canvas id="myChart"></canvas>',
category: 'Charts',
});
};
// Initialize GrapesJS with the plugin
var editor = grapesjs.init({
container: '#gjs',
storage: false,
fromElement: true,
selectorManager: {
componentFirst: true,
},
plugins: [chartJsPlugin],
});
</script>
</body>
</html> |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hello, I am creating a plugin to integrate
Chart.js
, and I would like to create a group ofTraits
(data, label, color). The functionality should be similar to theBox Shadow
in theStyle Manager
. Basically, it should be a wrapper with a "+" button, and when clicked, a triplet of options (data, label, color) is added. Are there any examples or suggestions on how to implement this?Beta Was this translation helpful? Give feedback.
All reactions