我是 d3.js 的新手。我从站点“observablehq”下载了两个代码生成图。这是代码的链接。
1-可缩放区域图
2-焦点上下文
我想在同一个浏览器窗口中显示这两个图。为此,我将文件放在同一目录中。这是可缩放区域图表的 html 代码
<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoomable Area Chart</title>
<link rel="stylesheet" type="text/css" href="./inspector.css">
<body>
<script type="module">
import define from "./index.js";
import {Runtime, Library, Inspector} from "./runtime.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
这是焦点上下文的html代码
<!DOCTYPE html>
<meta charset="utf-8">
<title>Focus + Context</title>
<link rel="stylesheet" type="text/css" href="inspector1.css">
<body>
<script type="module">
import define from "./index1.js";
import {Runtime, Library, Inspector} from "./runtime1.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
我像这样在“可缩放区域图”的html文件中放置了“焦点+上下文”“脚本”
<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoomable Area Chart</title>
<link rel="stylesheet" type="text/css" href="./inspector.css">
<body>
<script type="module">
import define from "./index.js";
import {Runtime, Library, Inspector} from "./runtime.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
<script type="module">
import define from "./index1.js";
import {Runtime, Library, Inspector} from "./runtime1.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
然后我使用“webstorm”将该html文件运行到浏览器中。它不会在同一个浏览器窗口中显示两个图表。它显示第一个图的错误并显示第二个图
这是“可缩放区域图”的 js 文件
// https://observablehq.com/@d3/zoomable-area-chart@212
export default function define(runtime, observer) {
const main = runtime.module();
const fileAttachments = new Map([["flights.csv",new URL("./files/1171cb24da0255c434c1ff554b4964c39c1253aa9349f2d356a25351acd3579367f92b24366ae5b6c208c9336811489c0a176cbc0cc62e31feff51e294a178fe",import.meta.url)]]);
main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
main.variable(observer()).define(["md"], function(md){return(
md`# Zoomable Area Chart
This zoomable time series area chart shows the number of flights per day. The effect of the September 11, 2001 attacks on air travel is evident.`
)});
main.variable(observer("chart")).define("chart", ["d3","margin","width","height","DOM","area","data","x","xAxis","yAxis","y"], function(d3,margin,width,height,DOM,area,data,x,xAxis,yAxis,y)
{
const zoom = d3.zoom()
.scaleExtent([1, 32])
.extent([[margin.left, 0], [width - margin.right, height]])
.translateExtent([[margin.left, -Infinity], [width - margin.right, Infinity]])
.on("zoom", zoomed);
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
const clip = DOM.uid("clip");
svg.append("clipPath")
.attr("id", clip.id)
.append("rect")
.attr("x", margin.left)
.attr("y", margin.top)
.attr("width", width - margin.left - margin.right)
.attr("height", height - margin.top - margin.bottom);
const path = svg.append("path")
.attr("clip-path", clip)
.attr("fill", "steelblue")
.attr("d", area(data, x));
const gx = svg.append("g")
.call(xAxis, x);
svg.append("g")
.call(yAxis, y);
svg.call(zoom)
.transition()
.duration(750)
.call(zoom.scaleTo, 4, [x(Date.UTC(2001, 8, 1)), 0]);
function zoomed() {
const xz = d3.event.transform.rescaleX(x);
path.attr("d", area(data, xz));
gx.call(xAxis, xz);
}
return svg.node();
}
);
main.variable(observer("height")).define("height", function(){return(
500
)});
main.variable(observer("margin")).define("margin", function(){return(
{top: 20, right: 20, bottom: 30, left: 30}
)});
main.variable(observer("x")).define("x", ["d3","data","margin","width"], function(d3,data,margin,width){return(
d3.scaleUtc()
.domain(d3.extent(data, d => d.date))
.range([margin.left, width - margin.right])
)});
main.variable(observer("y")).define("y", ["d3","data","height","margin"], function(d3,data,height,margin){return(
d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
)});
main.variable(observer("xAxis")).define("xAxis", ["height","margin","d3","width"], function(height,margin,d3,width){return(
(g, x) => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0))
)});
main.variable(observer("yAxis")).define("yAxis", ["margin","d3","data"], function(margin,d3,data){return(
(g, y) => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(null, "s"))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
)});
main.variable(observer("area")).define("area", ["d3","y"], function(d3,y){return(
(data, x) => d3.area()
.curve(d3.curveStepAfter)
.x(d => x(d.date))
.y0(y(0))
.y1(d => y(d.value))
(data)
)});
main.variable(observer("data")).define("data", ["d3","FileAttachment"], async function(d3,FileAttachment){return(
Object.assign(d3.csvParse(await FileAttachment("flights.csv").text(), d3.autoType), {y: "Flights"})
)});
main.variable(observer("d3")).define("d3", ["require"], function(require){return(
require("d3@5")
)});
return main;
}
这是“焦点+上下文”的js文件
// https://observablehq.com/@d3/focus-context@320
export default function define(runtime, observer) {
const main = runtime.module();
const fileAttachments = new Map([["aapl.csv",new URL("./files/de259092d525c13bd10926eaf7add45b15f2771a8b39bc541a5bba1e0206add4880eb1d876be8df469328a85243b7d813a91feb8cc4966de582dc02e5f8609b7",import.meta.url)]]);
main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
main.variable(observer()).define(["md"], function(md){return(
md`# Focus + Context
This [area chart](/@d3/area-chart) uses brushing to specify a focused area. Drag the gray region to pan, or brush to zoom. Compare to a [zoomable chart](/@d3/zoomable-area-chart). Data: [Yahoo Finance](https://finance.yahoo.com/lookup)`
)});
main.variable(observer("chart")).define("chart", ["d3","width","height","DOM","margin","data","xAxis","yAxis","area"], function(d3,width,height,DOM,margin,data,xAxis,yAxis,area)
{
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("display", "block");
const clipId = DOM.uid("clip");
svg.append("clipPath")
.attr("id", clipId.id)
.append("rect")
.attr("x", margin.left)
.attr("y", 0)
.attr("height", height)
.attr("width", width - margin.left - margin.right);
const gx = svg.append("g");
const gy = svg.append("g");
const path = svg.append("path")
.datum(data)
.attr("clip-path", clipId)
.attr("fill", "steelblue");
return Object.assign(svg.node(), {
update(focusX, focusY) {
gx.call(xAxis, focusX, height);
gy.call(yAxis, focusY, data.y);
path.attr("d", area(focusX, focusY));
}
});
}
);
main.variable(observer("viewof focus")).define("viewof focus", ["d3","width","focusHeight","margin","x","xAxis","data","area","y"], function(d3,width,focusHeight,margin,x,xAxis,data,area,y)
{
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, focusHeight])
.style("display", "block");
const brush = d3.brushX()
.extent([[margin.left, 0.5], [width - margin.right, focusHeight - margin.bottom + 0.5]])
.on("brush", brushed)
.on("end", brushended);
const defaultSelection = [x(d3.utcYear.offset(x.domain()[1], -1)), x.range()[1]];
svg.append("g")
.call(xAxis, x, focusHeight);
svg.append("path")
.datum(data)
.attr("fill", "steelblue")
.attr("d", area(x, y.copy().range([focusHeight - margin.bottom, 4])));
const gb = svg.append("g")
.call(brush)
.call(brush.move, defaultSelection);
function brushed() {
if (d3.event.selection) {
svg.property("value", d3.event.selection.map(x.invert, x).map(d3.utcDay.round));
svg.dispatch("input");
}
}
function brushended() {
if (!d3.event.selection) {
gb.call(brush.move, defaultSelection);
}
}
return svg.node();
}
);
main.variable(observer("focus")).define("focus", ["Generators", "viewof focus"], (G, _) => G.input(_));
main.variable(observer()).define(["focus","d3","data","chart","x","y"], function(focus,d3,data,chart,x,y)
{
const [minX, maxX] = focus;
const maxY = d3.max(data, d => minX <= d.date && d.date <= maxX ? d.value : NaN);
chart.update(x.copy().domain(focus), y.copy().domain([0, maxY]));
}
);
main.variable(observer("data")).define("data", ["d3","FileAttachment"], async function(d3,FileAttachment){return(
Object.assign(d3.csvParse(await FileAttachment("aapl.csv").text(), d3.autoType).map(({date, close}) => ({date, value: close})), {y: "↑ Close $"})
)});
main.variable(observer("area")).define("area", ["d3"], function(d3){return(
(x, y) => d3.area()
.defined(d => !isNaN(d.value))
.x(d => x(d.date))
.y0(y(0))
.y1(d => y(d.value))
)});
main.variable(observer("x")).define("x", ["d3","data","margin","width"], function(d3,data,margin,width){return(
d3.scaleUtc()
.domain(d3.extent(data, d => d.date))
.range([margin.left, width - margin.right])
)});
main.variable(observer("y")).define("y", ["d3","data","height","margin"], function(d3,data,height,margin){return(
d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([height - margin.bottom, margin.top])
)});
main.variable(observer("xAxis")).define("xAxis", ["margin","d3","width"], function(margin,d3,width){return(
(g, x, height) => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0))
)});
main.variable(observer("yAxis")).define("yAxis", ["margin","d3"], function(margin,d3){return(
(g, y, title) => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".title").data([title]).join("text")
.attr("class", "title")
.attr("x", -margin.left)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text(title))
)});
main.variable(observer("margin")).define("margin", function(){return(
{top: 20, right: 20, bottom: 30, left: 40}
)});
main.variable(observer("height")).define("height", function(){return(
440
)});
main.variable(observer("focusHeight")).define("focusHeight", function(){return(
100
)});
main.variable(observer("d3")).define("d3", ["require"], function(require){return(
require("d3@5")
)});
return main;
}
如何在同一个浏览器窗口中正确显示两个图表。您可以从此链接下载完整的项目