NodeJS 中生成的 SVG 看起来与我的 Observable 示例不同

问题描述 投票:0回答:1

我有一个在 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());
javascript node.js d3.js jsdom
1个回答
0
投票

您想要的示例与小提琴示例的输出有很多差异,特别是这不再是有效的 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>
© www.soinside.com 2019 - 2024. All rights reserved.