我有一个在 D3 中使用 observable 创建的图表,它看起来很棒。现在,我使用完全相同的数据和 d3 代码来重新创建此服务器端,其中 JSDOM 充当 dom 的参与者。
这是我的可观察示例的链接:https://observablehq.com/d/ad30674298b77b9e?collection=@colt-street-ws/timewise-reports
效果很好!
现在,当我打印出 SVG 并将其粘贴到 fiddle 或 codepen 中时,它由于某种原因损坏了,我不明白为什么它如此不同。
这是服务器端代码:
const minHtml = "<html><head></head><body></body></html>";
const dom = new JSDOM(`${minHtml}`, { pretendToBeVisual: true });
const window = dom.window;
window.d3 = d3.select(window.document);
let storeData = testdata.filter((d) => d.Store_Value === "15805" && d.SP === 1.04);
let allStoreData = testdata.filter((d) => d.Store_Value === "Total" && d.SP === 1.03);
// Declare the chart dimensions and margins.
const width = 928;
const height = 500;
const margin = ({top: 20, right: 40, bottom: 30, left: 40})
// Create the SVG container.
// const svg = window.d3.select("body").append("svg").attr("width", width).attr("height", height).attr("viewBox", [0, 0, width, height]).attr("style", "max-width: 100%; height: auto;");
const svg = window.d3.select("body").append("svg").attr("width", width).attr("height", height).attr("viewBox", [0, 0, width, height]).attr("style", "max-width: 100%; height: auto;");
const allStoreLine = d3
.line()
.x((d) => x(d.Item_Value) + x.bandwidth() / 2)
.y((d) => y2(d.OOSh_Percent));
const line = d3
.line()
.x((d) => x(d.Item_Value) + x.bandwidth() / 2)
.y((d) => y2(d.OOSh_Percent));
const x = d3
.scaleBand()
.domain(
d3.groupSort(
storeData,
([d]) => -d.Lost_Units,
(d) => d.Item_Value
)
) // descending frequency
.range([margin.left, width - margin.right])
.padding(0.1);
const y1 = d3
.scaleLinear()
.domain([0, d3.max(storeData, (d) => d.Lost_Units)])
.rangeRound([height - margin.bottom, margin.top]);
const y2 = d3
.scaleLinear()
.domain([0, d3.max(storeData, (d) => d.OOSh_Percent)])
.rangeRound([height - margin.bottom, margin.top]);
const xAxis = (g) => g.attr("transform", `translate(0,${height - margin.bottom})`).call(d3.axisBottom(x).tickSizeOuter(0));
const y1Axis = (g) =>
g
.attr("transform", `translate(${margin.left},0)`)
.style("color", "steelblue")
.call(d3.axisLeft(y1).ticks(null, "s"))
.call((g) => g.select(".domain").remove())
.call((g) => g.append("text").attr("x", -margin.left).attr("y", 10).attr("fill", "currentColor").attr("text-anchor", "start").text(storeData.y1));
const y2Axis = (g) =>
g
.attr("transform", `translate(${width - margin.right},0)`)
.call(
d3
.axisRight(y2)
.ticks(null)
.tickFormat(function (d) {
return (d * 100).toFixed(1) + "%";
})
)
.call((g) => g.select(".domain").remove())
.call((g) => g.append("text").attr("x", margin.right).attr("y", 10).attr("fill", "currentColor").attr("text-anchor", "end").text(storeData.y2));
//Create the d3 Chart
svg
.append("g")
.attr("fill", "steelblue")
.attr("fill-opacity", 0.8)
.selectAll("rect")
.data(storeData)
.join("rect")
.attr("x", (d) => x(d.Item_Value))
.attr("width", x.bandwidth())
.attr("y", (d) => y1(d.Lost_Units))
.attr("height", (d) => y1(0) - y1(d.Lost_Units));
svg.append("path").attr("fill", "none").attr("stroke", "currentColor").attr("stroke-miterlimit", 1).attr("stroke-width", 3).attr("d", allStoreLine(allStoreData));
svg.append("path").attr("fill", "none").attr("stroke", "currentColor").attr("stroke-miterlimit", 1).attr("stroke-width", 3).attr("d", line(storeData));
svg
.append("g")
.attr("fill", "none")
.attr("pointer-events", "all")
.selectAll("rect")
.data(storeData)
.join("rect")
.attr("x", (d) => x(d.Item_Value))
.attr("width", x.bandwidth())
.attr("y", 0)
.attr("height", height);
svg.append("g").call(xAxis);
svg.append("g").call(y1Axis);
svg.append("g").call(y2Axis);
console.log(window.d3.select("body").html());
您想要的示例与小提琴示例的输出有很多差异,特别是这不再是有效的 XML,因为缺少几个结束标记。我建议将当前和预期加载到比较工具中,以便自己查看这些差异,但您还会注意到 JSFiddle 向您显示一个错误,指示
<line>
在第 32-42 行没有结束标记。作为参考,以下是您的工作示例的输出 XML:
<svg width="928" height="500" viewBox="0,0,928,500" style="max-width: 100%; height: auto;">
<g fill="steelblue" fill-opacity="0.8">
<rect x="56.627450980392155" width="149.6470588235294" y="20" height="450"></rect>
<rect x="222.9019607843137" width="149.6470588235294" y="65" height="405"></rect>
<rect x="389.17647058823525" width="149.6470588235294" y="110" height="360"></rect>
<rect x="555.4509803921568" width="149.6470588235294" y="155" height="315"></rect>
<rect x="721.7254901960783" width="149.6470588235294" y="200" height="270"></rect>
</g>
<path fill="none" stroke="currentColor" stroke-miterlimit="1" stroke-width="3" d="M131.451,78L297.725,73L464,180L630.275,60L796.549,160"></path>
<path fill="none" stroke="currentColor" stroke-miterlimit="1" stroke-width="3" d="M131.451,39L297.725,34L464,150L630.275,20L796.549,129"></path>
<g fill="none" pointer-events="all">
<rect x="56.627450980392155" width="149.6470588235294" y="0" height="500"></rect>
<rect x="222.9019607843137" width="149.6470588235294" y="0" height="500"></rect>
<rect x="389.17647058823525" width="149.6470588235294" y="0" height="500"></rect>
<rect x="555.4509803921568" width="149.6470588235294" y="0" height="500"></rect>
<rect x="721.7254901960783" width="149.6470588235294" y="0" height="500"></rect>
</g>
<g transform="translate(0,470)" fill="none" font-size="10" font-family="sans-serif" text-anchor="middle">
<path class="domain" stroke="currentColor" d="M40,0H888"></path>
<g class="tick" opacity="1" transform="translate(131.45098039215685,0)"><line stroke="currentColor" y2="6"></line><text fill="currentColor" y="9" dy="0.71em">Packaged Beverages (Non-Alcoholic)</text></g>
<g class="tick" opacity="1" transform="translate(297.7254901960784,0)"><line stroke="currentColor" y2="6"></line><text fill="currentColor" y="9" dy="0.71em">Cigarettes</text></g>
<g class="tick" opacity="1" transform="translate(463.99999999999994,0)"><line stroke="currentColor" y2="6"></line><text fill="currentColor" y="9" dy="0.71em">Beer</text></g>
<g class="tick" opacity="1" transform="translate(630.2745098039215,0)"><line stroke="currentColor" y2="6"></line><text fill="currentColor" y="9" dy="0.71em">Salty Snacks</text></g>
<g class="tick" opacity="1" transform="translate(796.5490196078431,0)"><line stroke="currentColor" y2="6"></line><text fill="currentColor" y="9" dy="0.71em">Candy</text></g>
</g>
<g transform="translate(40,0)" fill="none" font-size="10" font-family="sans-serif" text-anchor="end" style="color: steelblue;">
<g class="tick" opacity="1" transform="translate(0,470)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">0k</text></g>
<g class="tick" opacity="1" transform="translate(0,434)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">5k</text></g>
<g class="tick" opacity="1" transform="translate(0,398)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">10k</text></g>
<g class="tick" opacity="1" transform="translate(0,362)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">15k</text></g>
<g class="tick" opacity="1" transform="translate(0,326)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">20k</text></g>
<g class="tick" opacity="1" transform="translate(0,290)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">25k</text></g>
<g class="tick" opacity="1" transform="translate(0,254)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">30k</text></g>
<g class="tick" opacity="1" transform="translate(0,218)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">35k</text></g>
<g class="tick" opacity="1" transform="translate(0,182)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">40k</text></g>
<g class="tick" opacity="1" transform="translate(0,146)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">45k</text></g>
<g class="tick" opacity="1" transform="translate(0,110)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">50k</text></g>
<g class="tick" opacity="1" transform="translate(0,74)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">55k</text></g>
<g class="tick" opacity="1" transform="translate(0,38)"><line stroke="currentColor" x2="-6"></line><text fill="currentColor" x="-9" dy="0.32em">60k</text></g>
<text x="-40" y="10" fill="currentColor" text-anchor="start"></text>
</g>
<g transform="translate(888,0)" fill="none" font-size="10" font-family="sans-serif" text-anchor="start">
<g class="tick" opacity="1" transform="translate(0,470)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">0.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,431)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">1.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,392)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">2.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,352)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">3.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,313)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">4.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,274)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">5.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,235)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">6.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,195)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">7.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,156)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">8.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,117)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">9.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,78)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">10.0%</text></g>
<g class="tick" opacity="1" transform="translate(0,39)"><line stroke="currentColor" x2="6"></line><text fill="currentColor" x="9" dy="0.32em">11.0%</text></g>
<text x="40" y="10" fill="currentColor" text-anchor="end"></text>
</g>
</svg>