I am trying to display multiple d3 charts on a page using Rails 7 using different div (or svg) ids:
view.html.erb
<%= content_tag "svg", class: 'chart', id: raw(chart_type)+'_'+raw(chart_num), data: {chart_type: chart_type, chart_num: chart_num} do %>
<script>
line('#line_1');
</script>
<% end %>
javascript\component\charts\line.js
import * as d3 from "d3";
function line(chart_id) {
const svg = d3.select('#line_1')
.attr('width', 400)
.attr('height', 400)
.style('background-color', 'black');
svg.append(chart_id)
.style("stroke", "lightgreen")
.style("stroke-width", 10)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 200)
.attr("y2", 200);
}
importmap.
pin_all_from "app/javascript/components", under: "components"
application.js
import "components/charts/line"
I have tried the suggestions in this posts: How to get a Rails variable into JavaScript file (D3) mainly because the div/svg id is the data that needs to be passed. Also, I know how to do this with in-line javascript but I can't figure out how to pass the div id as a variable to the chart as a function.
Any help would be greatly appreciated.
I'm not exactly clear what you're asking here, but I see a couple of obvious issues. Because we're working with modules, line
function is not global, it has to be exported/imported where needed or it has to be explicitly made global.
import * as d3 from "d3";
function line (chart_id) {
const svg = d3.select(chart_id)
.attr('width', 400)
.attr('height', 400)
.style('background-color', 'black');
svg.append("line")
.style("stroke", "lightgreen")
.style("stroke-width", 10)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 200)
.attr("y2", 200);
}
window.line = line;
// or like this
//
// window.line = function (chart_id) {
// ...
// }
Another issue is plain script tags get loaded before module scripts, so line
function would not be defined yet:
<script type="module">
line("#line_1");
</script>
You might want to consider making a Stimulus controller instead of making inline scripts and adding global functions:
https://stimulus.hotwired.dev/
$ bin/rails stimulus chart
// app/javascript/controllers/chart_controller.js
import { Controller } from "@hotwired/stimulus"
import * as d3 from "d3";
// Connects to data-controller="chart"
export default class extends Controller {
// https://stimulus.hotwired.dev/reference/values
static values = {
type: String,
num: Number,
}
connect() {
// this.typeValue
// this.numValue
this.line();
}
line() {
const svg = d3.select(this.element)
.attr('width', 400)
.attr('height', 400)
.style('background-color', 'black');
svg.append("line")
.style("stroke", "lightgreen")
.style("stroke-width", 10)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 200)
.attr("y2", 200);
}
}
# app/views/home/index.html.erb
<%= tag.svg data: {
controller: "chart",
chart_type_value: "line",
chart_num_value: 1
} %>