I’d like to transpose this barchart to Laravel.
So I create an Alpine.js component to handle the buttons and show it in Laravel as you can see in this fiddle.
Original code:
<button onclick="update(data1)">Variable 1</button>
<button onclick="update(data2)">Variable 2</button>
Modified code:
<div x-data="myComponent()">
<button x-on:click="update(data1)">Data 1</button>
<button x-on:click="update(data2)">Data 2</button>
</div>
And part of the original JavaScript:
// A function that create / update the plot for a given variable:
function update(data) {
// Update the X axis
x.domain(data.map(function(d) { return d.group; }))
xAxis.call(d3.axisBottom(x))
// Update the Y axis
y.domain([0, d3.max(data, function(d) { return d.value }) ]);
yAxis.transition().duration(1000).call(d3.axisLeft(y));
// Create the u variable
var u = svg.selectAll("rect")
.data(data)
u
.enter()
.append("rect") // Add a new rect for each new elements
.merge(u) // get the already existing elements as well
.transition() // and apply changes to all of them
.duration(1000)
.attr("x", function(d) { return x(d.group); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", "#69b3a2")
// If less group in the new dataset, I delete the ones not in use anymore
u
.exit()
.remove()
}
And part of the modified Alpine version:
function myComponent(){ // Component
return { // Object
update(data){ // Method
// Update the X axis
x.domain(data.map(d => d.group))
xAxis.call(d3.axisBottom(x))
...
}
}
}
As you can see in the fiddle it works as expected. When we click on the button Data 1 it shows the chart with the data 1 and when we click on the Data 2 it shows the chart with the data 2.
Nevertheless when I transpose it to Laravel just like in the fiddle it doesn’t work:
File dashboard.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Dashboard') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
<div x-data="myComponent()">
<!-- Add 2 buttons -->
<button x-on:click="update(data1)">Data 1</button>
<button x-on:click="update(data2)">Data 2</button>
</div>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
</div>
</div>
</div>
</div>
</x-app-layout>
<script src="{{ asset('js/data.js') }}" defer></script>
File data.js:
import * as d3 from 'd3';
// create 2 data_set
const data1 = [
{group: "A", value: 4},
{group: "B", value: 16},
{group: "C", value: 8}
];
const data2 = [
{group: "A", value: 7},
{group: "B", value: 1},
{group: "C", value: 20},
{group: "D", value: 10}
];
// set the dimensions and margins of the graph
const margin = {top: 30, right: 30, bottom: 70, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
const svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Initialize the X axis
const x = d3.scaleBand()
.range([ 0, width ])
.padding(0.2);
const xAxis = svg.append("g")
.attr("transform", `translate(0,${height})`)
// Initialize the Y axis
const y = d3.scaleLinear()
.range([ height, 0]);
const yAxis = svg.append("g")
.attr("class", "myYaxis")
function myComponent(){ //Component
return { //Object
update(data){ //Method
// Update the X axis
x.domain(data.map(d => d.group))
xAxis.call(d3.axisBottom(x))
// Update the Y axis
y.domain([0, d3.max(data, d => d.value) ]);
yAxis.transition().duration(1000).call(d3.axisLeft(y));
// Create the u variable
var u = svg.selectAll("rect")
.data(data)
u
.join("rect") // Add a new rect for each new elements
.transition()
.duration(1000)
.attr("x", d => x(d.group))
.attr("y", d => y(d.value))
.attr("width", x.bandwidth())
.attr("height", d => height - y(d.value))
.attr("fill", "#69b3a2")
// Initialize the plot with the first dataset
// update(data1)
}
}
}
I receive the following error messages:
Alpine Expression Error: myComponent is not defined
Expression: "myComponent()"
app.js:434 Uncaught ReferenceError: myComponent is not defined
at eval (eval at safeAsyncFunction (app.js:478:14), <anonymous>:3:16)
at app.js:496:21
at tryCatch (app.js:423:12)
at evaluate (app.js:441:32)
at app.js:2621:15
at Function.<anonymous> (app.js:1152:55)
at flushHandlers (app.js:553:46)
at stopDeferring (app.js:558:5)
at deferHandlingDirectives (app.js:561:3)
at initTree (app.js:764:3)
And when I click in any of the buttons the error is:
Alpine Expression Error: update is not defined
Expression: "update(data1)"
app.js:434 Uncaught ReferenceError: update is not defined
at eval (eval at safeAsyncFunction (app.js:478:14), <anonymous>:3:16)
at app.js:496:21
at tryCatch (app.js:423:12)
at app.js:2910:5
at handler3 (app.js:2302:25)
at app.js:2357:5
at HTMLButtonElement.<anonymous> (app.js:2304:52)
Why does it work in the fiddle, but not in Laravel?