如何将d3.js柱状图创建为Svelte组件并正确绑定d3到SVG?

huangapple go评论127阅读模式
英文:

how to create d3.js bar chart as a Svelte component and bind d3 to SVG properly?

问题

以下是d3.js图表的代码部分的中文翻译:

  1. const data = [{
  2. "date": "2010-08-06",
  3. "count": 32348
  4. },
  5. {
  6. "date": "2010-08-07",
  7. "count": 32454
  8. },
  9. {
  10. "date": "2010-08-08",
  11. "count": 32648
  12. },
  13. {
  14. "date": "2010-08-09",
  15. "count": 32812
  16. },
  17. {
  18. "date": "2010-08-10",
  19. "count": 32764
  20. },
  21. {
  22. "date": "2010-08-11",
  23. "count": 32668
  24. },
  25. {
  26. "date": "2010-08-12",
  27. "count": 32484
  28. },
  29. {
  30. "date": "2010-08-13",
  31. "count": 32167
  32. },
  33. {
  34. "date": "2010-08-14",
  35. "count": 32304
  36. },
  37. {
  38. "date": "2010-08-15",
  39. "count": 32446
  40. },
  41. {
  42. "date": "2010-08-16",
  43. "count": 32670
  44. },
  45. {
  46. "date": "2010-08-17",
  47. "count": 32778
  48. },
  49. {
  50. "date": "2010-08-18",
  51. "count": 32756
  52. },
  53. {
  54. "date": "2010-08-19",
  55. "count": 32580
  56. }
  57. ]
  58. const formatDate4 = d3.timeFormat("%m%d%Y")
  59. const formatDate5 = d3.timeFormat('%Y-%m-%d')
  60. const formatDate6 = d3.timeFormat("%b %d, %Y");
  61. const bisectDate = d3.bisector(function(d) {
  62. return d.date;
  63. }).left;
  64. var parseTime = d3.timeParse("%Y-%m-%d")
  65. const pageWidth = window.innerWidth
  66. let wrapWidth = 969,
  67. mapRatio = .51
  68. let margin = {
  69. top: 0,
  70. right: 0,
  71. bottom: 10,
  72. left: 0
  73. }
  74. let timeW = 960,
  75. timeH = 450
  76. let timeMargin = {
  77. top: 20,
  78. right: 250,
  79. bottom: 80,
  80. left: 60
  81. },
  82. timeMargin2 = {
  83. top: 410,
  84. right: 250,
  85. bottom: 30,
  86. left: 60
  87. },
  88. timeWidth = timeW - timeMargin.left - timeMargin.right,
  89. timeHeight = timeH - timeMargin.top - timeMargin.bottom,
  90. timeHeight2 = timeH - timeMargin2.top - timeMargin2.bottom;
  91. let timeseries = d3.select("#timeseries-container").append('svg')
  92. .attr('id', 'timeseries')
  93. .attr("width", timeWidth + timeMargin.left + timeMargin.right)
  94. .attr("height", timeHeight + timeMargin.top + timeMargin.bottom)
  95. var graph = timeseries.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  96. var parseDate = d3.timeParse("%Y-%m-%d");
  97. var x2 = d3.scaleTime().range([0, timeWidth]),
  98. x3 = d3.scaleTime().range([0, timeWidth]),
  99. y2 = d3.scaleLinear().range([timeHeight, 0]),
  100. y3 = d3.scaleLinear().range([timeHeight2, 0]);
  101. var xAxis2 = d3.axisBottom(x2).ticks(5)
  102. .tickFormat(d3.timeFormat("%b %d %Y")),
  103. yAxis2 = d3.axisLeft(y2).ticks(3);
  104. timeseries.append("defs").append("clipPath")
  105. .attr("id", "clip")
  106. .append("rect")
  107. .attr("width", timeWidth)
  108. .attr("height", timeHeight)
  109. var chartfocus = timeseries.append("g")
  110. .attr("class", "chartfocus")
  111. .attr("transform", "translate(" + timeMargin.left + "," + timeMargin.top + ")");
  112. const natlData = data;
  113. console.log('natlData', natlData)
  114. updateChart(natlData)
  115. function updateChart(data) {
  116. const dataOld = data.map(a => ({ ...a }));
  117. data.forEach(d => {
  118. d.date = parseTime(d.date);
  119. })
  120. x2.domain(d3.extent(data, function(d) {
  121. return d.date;
  122. }));
  123. const charttooltip = d3.select("#time").append("div")
  124. .attr("class", "charttooltip");
  125. const chartguideline = d3.select("body").append("div")
  126. .attr("class", "chartguideline");
  127. let topY = d3.max(data, d => d.count)
  128. timeseries.selectAll(".axis").remove();
  129. let bisectDate = d3.bisector(function(d) {
  130. return d.date;
  131. }).left;
  132. chartfocus
  133. .on("mouseover", mouseover)
  134. .on("mousemove", mousemove)
  135. .on("mouseout", mouseout)
  136. y2.domain([0, topY]).nice();
  137. d3.select(".axis--y")
  138. .transition(1000)
  139. .call(yAxis2)
  140. d3.selectAll('.bar').remove()
  141. let dailyBars = chartfocus.selectAll(".bar")
  142. .data(data)
  143. .enter().append("rect")
  144. .attr("clip-path", "url(#clip)")
  145. .attr('class', d => 'bar d' + formatDate4(d.date))
  146. y2.domain([0, topY]).nice();
  147. d3.select(".axis--y")
  148. .transition(1000)
  149. .call(yAxis2)
  150. dailyBars.transition()
  151. .attr("width", d => x2(d3.timeDay.offset(d.date)) - x2(d.date))
  152. .attr('x', d => x2(d.date))
  153. .attr("y", d => y2(d.count))
  154. .attr("height", d => timeHeight - y2(d.count))
  155. chartfocus.append("g")
  156. .attr("class", "axis axis--x")
  157. .attr("transform", "translate(0," + timeHeight + ")")
  158. .call(xAxis2);
  159. chartfocus.append("g")
  160. .attr("class", "axis axis--y")
  161. .call(yAxis2);
  162. chartfocus.append("rect")
  163. .attr("class", "chartzoom")
  164. .attr("width", timeWidth)
  165. .attr("height", timeHeight)
  166. d3.selectAll('.focus').remove()
  167. function mouseover(event) {}
  168. function mousemove(event, d) {
  169. let outerMargins = pageWidth - wrapWidth
  170. let outerLeftMargin = outerMargins / 2
  171. let ex = event.x - timeMargin.left - outerLeftMargin
  172. var x0 = x2.invert(ex),
  173. i = bisectDate(data, x0, 1),
  174. d0 = data[i - 1],
  175. <details>
  176. <summary>英文:</summary>
  177. I have a focus/context bar chart that I created in d3. I want to put it in Svelte so that I can use it as a component. But I&#39;m getting stuck figuring out how to bind the elements created in d3 to the html in the svelte component.
  178. Below is the code for the d3.js chart
  179. &lt;!-- begin snippet: js hide: true console: true babel: false --&gt;
  180. &lt;!-- language: lang-js --&gt;
  181. const data = [{
  182. &quot;date&quot;: &quot;2010-08-06&quot;,
  183. &quot;count&quot;: 32348
  184. },
  185. {
  186. &quot;date&quot;: &quot;2010-08-07&quot;,
  187. &quot;count&quot;: 32454
  188. },
  189. {
  190. &quot;date&quot;: &quot;2010-08-08&quot;,
  191. &quot;count&quot;: 32648
  192. },
  193. {
  194. &quot;date&quot;: &quot;2010-08-09&quot;,
  195. &quot;count&quot;: 32812
  196. },
  197. {
  198. &quot;date&quot;: &quot;2010-08-10&quot;,
  199. &quot;count&quot;: 32764
  200. },
  201. {
  202. &quot;date&quot;: &quot;2010-08-11&quot;,
  203. &quot;count&quot;: 32668
  204. },
  205. {
  206. &quot;date&quot;: &quot;2010-08-12&quot;,
  207. &quot;count&quot;: 32484
  208. },
  209. {
  210. &quot;date&quot;: &quot;2010-08-13&quot;,
  211. &quot;count&quot;: 32167
  212. },
  213. {
  214. &quot;date&quot;: &quot;2010-08-14&quot;,
  215. &quot;count&quot;: 32304
  216. },
  217. {
  218. &quot;date&quot;: &quot;2010-08-15&quot;,
  219. &quot;count&quot;: 32446
  220. },
  221. {
  222. &quot;date&quot;: &quot;2010-08-16&quot;,
  223. &quot;count&quot;: 32670
  224. },
  225. {
  226. &quot;date&quot;: &quot;2010-08-17&quot;,
  227. &quot;count&quot;: 32778
  228. },
  229. {
  230. &quot;date&quot;: &quot;2010-08-18&quot;,
  231. &quot;count&quot;: 32756
  232. },
  233. {
  234. &quot;date&quot;: &quot;2010-08-19&quot;,
  235. &quot;count&quot;: 32580
  236. }
  237. ]
  238. const formatDate4 = d3.timeFormat(&quot;%m%d%Y&quot;)
  239. const formatDate5 = d3.timeFormat(&#39;%Y-%m-%d&#39;)
  240. const formatDate6 = d3.timeFormat(&quot;%b %d, %Y&quot;);
  241. const bisectDate = d3.bisector(function(d) {
  242. return d.date;
  243. }).left;
  244. var parseTime = d3.timeParse(&quot;%Y-%m-%d&quot;)
  245. const pageWidth = window.innerWidth
  246. let wrapWidth = 969,
  247. mapRatio = .51
  248. let margin = {
  249. top: 0,
  250. right: 0,
  251. bottom: 10,
  252. left: 0
  253. }
  254. let timeW = 960,
  255. timeH = 450
  256. let timeMargin = {
  257. top: 20,
  258. right: 250,
  259. bottom: 80,
  260. left: 60
  261. },
  262. timeMargin2 = {
  263. top: 410,
  264. right: 250,
  265. bottom: 30,
  266. left: 60
  267. },
  268. timeWidth = timeW - timeMargin.left - timeMargin.right,
  269. timeHeight = timeH - timeMargin.top - timeMargin.bottom,
  270. timeHeight2 = timeH - timeMargin2.top - timeMargin2.bottom;
  271. let timeseries = d3.select(&quot;#timeseries-container&quot;).append(&#39;svg&#39;)
  272. .attr(&#39;id&#39;, &#39;timeseries&#39;)
  273. .attr(&quot;width&quot;, timeWidth + timeMargin.left + timeMargin.right)
  274. .attr(&quot;height&quot;, timeHeight + timeMargin.top + timeMargin.bottom)
  275. var graph = timeseries.append(&#39;g&#39;).attr(&#39;transform&#39;, &#39;translate(&#39; + margin.left + &#39;,&#39; + margin.top + &#39;)&#39;);
  276. var parseDate = d3.timeParse(&quot;%Y-%m-%d&quot;);
  277. var x2 = d3.scaleTime().range([0, timeWidth]),
  278. x3 = d3.scaleTime().range([0, timeWidth]),
  279. y2 = d3.scaleLinear().range([timeHeight, 0]),
  280. y3 = d3.scaleLinear().range([timeHeight2, 0]);
  281. var xAxis2 = d3.axisBottom(x2).ticks(5)
  282. .tickFormat(d3.timeFormat(&quot;%b %d %Y&quot;)),
  283. yAxis2 = d3.axisLeft(y2).ticks(3);
  284. timeseries.append(&quot;defs&quot;).append(&quot;clipPath&quot;)
  285. .attr(&quot;id&quot;, &quot;clip&quot;)
  286. .append(&quot;rect&quot;)
  287. .attr(&quot;width&quot;, timeWidth)
  288. .attr(&quot;height&quot;, timeHeight)
  289. var chartfocus = timeseries.append(&quot;g&quot;)
  290. .attr(&quot;class&quot;, &quot;chartfocus&quot;)
  291. .attr(&quot;transform&quot;, &quot;translate(&quot; + timeMargin.left + &quot;,&quot; + timeMargin.top + &quot;)&quot;);
  292. const natlData = data;
  293. console.log(&#39;natlData&#39;, natlData)
  294. updateChart(natlData)
  295. function updateChart(data) {
  296. const dataOld = data.map(a =&gt; ({ ...a
  297. }));
  298. data.forEach(d =&gt; {
  299. d.date = parseTime(d.date);
  300. })
  301. x2.domain(d3.extent(data, function(d) {
  302. return d.date;
  303. }));
  304. const charttooltip = d3.select(&quot;#time&quot;).append(&quot;div&quot;)
  305. .attr(&quot;class&quot;, &quot;charttooltip&quot;);
  306. const chartguideline = d3.select(&quot;body&quot;).append(&quot;div&quot;)
  307. .attr(&quot;class&quot;, &quot;chartguideline&quot;);
  308. let topY = d3.max(data, d =&gt; d.count)
  309. timeseries.selectAll(&quot;.axis&quot;).remove();
  310. let bisectDate = d3.bisector(function(d) {
  311. return d.date;
  312. }).left;
  313. chartfocus
  314. .on(&quot;mouseover&quot;, mouseover)
  315. .on(&quot;mousemove&quot;, mousemove)
  316. .on(&quot;mouseout&quot;, mouseout)
  317. y2.domain([0, topY]).nice();
  318. d3.select(&quot;.axis--y&quot;)
  319. .transition(1000)
  320. .call(yAxis2)
  321. d3.selectAll(&#39;.bar&#39;).remove()
  322. let dailyBars = chartfocus.selectAll(&quot;bar&quot;)
  323. .data(data)
  324. .enter().append(&quot;rect&quot;)
  325. .attr(&quot;clip-path&quot;, &quot;url(#clip)&quot;)
  326. .attr(&#39;class&#39;, d =&gt; &#39;bar d&#39; + formatDate4(d.date))
  327. y2.domain([0, topY]).nice();
  328. d3.select(&quot;.axis--y&quot;)
  329. .transition(1000)
  330. .call(yAxis2)
  331. dailyBars.transition()
  332. .attr(&quot;width&quot;, d =&gt; x2(d3.timeDay.offset(d.date)) - x2(d.date))
  333. .attr(&#39;x&#39;, d =&gt; x2(d.date))
  334. .attr(&quot;y&quot;, d =&gt; y2(d.count))
  335. .attr(&quot;height&quot;, d =&gt; timeHeight - y2(d.count))
  336. chartfocus.append(&quot;g&quot;)
  337. .attr(&quot;class&quot;, &quot;axis axis--x&quot;)
  338. .attr(&quot;transform&quot;, &quot;translate(0,&quot; + timeHeight + &quot;)&quot;)
  339. .call(xAxis2);
  340. chartfocus.append(&quot;g&quot;)
  341. .attr(&quot;class&quot;, &quot;axis axis--y&quot;)
  342. .call(yAxis2);
  343. chartfocus.append(&quot;rect&quot;)
  344. .attr(&quot;class&quot;, &quot;chartzoom&quot;)
  345. .attr(&quot;width&quot;, timeWidth)
  346. .attr(&quot;height&quot;, timeHeight)
  347. d3.selectAll(&#39;.focus&#39;).remove()
  348. function mouseover(event) {}
  349. function mousemove(event, d) {
  350. let outerMargins = pageWidth - wrapWidth
  351. let outerLeftMargin = outerMargins / 2
  352. let ex = event.x - timeMargin.left - outerLeftMargin
  353. var x0 = x2.invert(ex),
  354. i = bisectDate(data, x0, 1),
  355. d0 = data[i - 1],
  356. d1 = data[i],
  357. d = x0 - d0.date &gt; d1.date - x0 ? d1 : d0;
  358. let dateX = d.date
  359. let dateXSimple = formatDate5(dateX)
  360. indvData = dataOld.filter(d =&gt; d.date == dateXSimple)
  361. dailyCount = []
  362. dailyCounts = []
  363. let tooltip_str = formatDate5(dateX) + &quot;&lt;/p&gt;Count: &lt;strong&gt;&quot; + indvData[0].count
  364. charttooltip
  365. .style(&#39;left&#39;, event.x - outerLeftMargin + &#39;px&#39;)
  366. .style(&quot;top&quot;, 0)
  367. .attr(&#39;x&#39;, 0)
  368. .html(d =&gt; tooltip_str)
  369. chartguideline
  370. .style(&#39;left&#39;, event.x - 1 + &#39;px&#39;)
  371. .style(&quot;top&quot;, timeMargin.top + &#39;px&#39;)
  372. .attr(&quot;width&quot;, d =&gt; x2(d3.timeDay.offset(dateX)) - x2(dateX))
  373. .style(&#39;height&#39;, timeHeight + timeMargin.top - timeMargin.bottom + 45 + &#39;px&#39;)
  374. .attr(&#39;x&#39;, 0)
  375. charttooltip
  376. .style(&quot;visibility&quot;, &quot;visible&quot;)
  377. chartguideline
  378. .style(&quot;visibility&quot;, &quot;visible&quot;)
  379. }
  380. function mouseout() {
  381. d3.selectAll(&#39;.bar&#39;).style(&#39;fill&#39;, &#39;#aaa&#39;)
  382. d3.selectAll(&#39;.bar&#39;).transition()
  383. .attr(&quot;width&quot;, d =&gt; x2(d3.timeDay.offset(d.date)) - x2(d.date))
  384. charttooltip.transition()
  385. .duration(0)
  386. .style(&quot;visibility&quot;, &quot;hidden&quot;)
  387. chartguideline.transition()
  388. .duration(0)
  389. .style(&quot;visibility&quot;, &quot;hidden&quot;)
  390. }
  391. };
  392. &lt;!-- language: lang-css --&gt;
  393. .chartzoom {
  394. cursor: move;
  395. fill: none;
  396. pointer-events: all;
  397. }
  398. .charttooltip {
  399. position: absolute;
  400. pointer-events: none;
  401. padding: 10px;
  402. background: #fff;
  403. visibility: hidden;
  404. opacity: .9;
  405. -moz-box-shadow: 0 0 15px #aaa;
  406. -webkit-box-shadow: 0 0 15px #aaa;
  407. box-shadow: 0 0 15px #aaa;
  408. margin-left: 10px;
  409. }
  410. .charttooltip:before {
  411. right: 100%;
  412. top: 50%;
  413. border: solid transparent;
  414. content: &quot; &quot;;
  415. height: 0;
  416. width: 0;
  417. position: absolute;
  418. pointer-events: none;
  419. border-color: rgba(255, 255, 255, 0);
  420. border-right-color: #ffffff;
  421. border-width: 10px;
  422. margin-top: -10px;
  423. }
  424. .chartguideline {
  425. position: absolute;
  426. width: 1px;
  427. opacity: .5;
  428. pointer-events: none;
  429. background: #ef4136;
  430. visibility: hidden;
  431. }
  432. .bar {
  433. fill: #aaa;
  434. stroke-width: 1px;
  435. stroke: #000;
  436. }
  437. &lt;!-- language: lang-html --&gt;
  438. &lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;
  439. &lt;div id=&quot;time&quot;&gt;
  440. &lt;div id=&quot;timeseries-container&quot;&gt;&lt;/div&gt;
  441. &lt;/div&gt;
  442. &lt;!-- end snippet --&gt;
  443. The code I&#39;m using for the Svelte component is below. I&#39;m trying to put the main SVG in the body, and then bind my d3 code to it, but I&#39;m not able to get that working. Any help would be greatly appreciated.
  444. I also made a [REPL][1], if that&#39;s easier.
  445. &lt;script&gt;
  446. import * as d3 from &quot;d3&quot;;
  447. const data = [
  448. {
  449. date: &quot;2010-08-06&quot;,
  450. count: 32348,
  451. },
  452. {
  453. date: &quot;2010-08-07&quot;,
  454. count: 32454,
  455. },
  456. {
  457. date: &quot;2010-08-08&quot;,
  458. count: 32648,
  459. },
  460. {
  461. date: &quot;2010-08-09&quot;,
  462. count: 32812,
  463. },
  464. {
  465. date: &quot;2010-08-10&quot;,
  466. count: 32764,
  467. },
  468. {
  469. date: &quot;2010-08-11&quot;,
  470. count: 32668,
  471. },
  472. {
  473. date: &quot;2010-08-12&quot;,
  474. count: 32484,
  475. },
  476. {
  477. date: &quot;2010-08-13&quot;,
  478. count: 32167,
  479. },
  480. {
  481. date: &quot;2010-08-14&quot;,
  482. count: 32304,
  483. },
  484. {
  485. date: &quot;2010-08-15&quot;,
  486. count: 32446,
  487. },
  488. {
  489. date: &quot;2010-08-16&quot;,
  490. count: 32670,
  491. },
  492. {
  493. date: &quot;2010-08-17&quot;,
  494. count: 32778,
  495. },
  496. {
  497. date: &quot;2010-08-18&quot;,
  498. count: 32756,
  499. },
  500. {
  501. date: &quot;2010-08-19&quot;,
  502. count: 32580,
  503. },
  504. ];
  505. let el;
  506. const formatDate4 = d3.timeFormat(&quot;%m%d%Y&quot;);
  507. const formatDate5 = d3.timeFormat(&quot;%Y-%m-%d&quot;);
  508. const formatDate6 = d3.timeFormat(&quot;%b %d, %Y&quot;);
  509. const bisectDate = d3.bisector(function (d) {
  510. return d.date;
  511. }).left;
  512. var parseTime = d3.timeParse(&quot;%Y-%m-%d&quot;);
  513. const pageWidth = window.innerWidth;
  514. let wrapWidth = 969,
  515. mapRatio = 0.51;
  516. let margin = { top: 0, right: 0, bottom: 10, left: 0 };
  517. let timeW = 960,
  518. timeH = 450;
  519. let timeMargin = { top: 20, right: 250, bottom: 80, left: 60 },
  520. timeMargin2 = { top: 410, right: 250, bottom: 30, left: 60 },
  521. timeWidth = timeW - timeMargin.left - timeMargin.right,
  522. timeHeight = timeH - timeMargin.top - timeMargin.bottom,
  523. timeHeight2 = timeH - timeMargin2.top - timeMargin2.bottom;
  524. let timeseries = d3
  525. .select(el)
  526. .attr(&quot;id&quot;, &quot;timeseries&quot;)
  527. .attr(&quot;width&quot;, timeWidth + timeMargin.left + timeMargin.right)
  528. .attr(&quot;height&quot;, timeHeight + timeMargin.top + timeMargin.bottom);
  529. var graph = timeseries
  530. .append(&quot;g&quot;)
  531. .attr(&quot;transform&quot;, &quot;translate(&quot; + margin.left + &quot;,&quot; + margin.top + &quot;)&quot;);
  532. var parseDate = d3.timeParse(&quot;%Y-%m-%d&quot;);
  533. var x2 = d3.scaleTime().range([0, timeWidth]),
  534. x3 = d3.scaleTime().range([0, timeWidth]),
  535. y2 = d3.scaleLinear().range([timeHeight, 0]),
  536. y3 = d3.scaleLinear().range([timeHeight2, 0]);
  537. var xAxis2 = d3.axisBottom(x2).ticks(5).tickFormat(d3.timeFormat(&quot;%b %d %Y&quot;)),
  538. yAxis2 = d3.axisLeft(y2).ticks(3);
  539. timeseries
  540. .append(&quot;defs&quot;)
  541. .append(&quot;clipPath&quot;)
  542. .attr(&quot;id&quot;, &quot;clip&quot;)
  543. .append(&quot;rect&quot;)
  544. .attr(&quot;width&quot;, timeWidth)
  545. .attr(&quot;height&quot;, timeHeight);
  546. var chartfocus = timeseries
  547. .append(&quot;g&quot;)
  548. .attr(&quot;class&quot;, &quot;chartfocus&quot;)
  549. .attr(
  550. &quot;transform&quot;,
  551. &quot;translate(&quot; + timeMargin.left + &quot;,&quot; + timeMargin.top + &quot;)&quot;
  552. );
  553. const natlData = data;
  554. console.log(&quot;natlData&quot;, natlData);
  555. updateChart(natlData);
  556. function updateChart(data) {
  557. const dataOld = data.map((a) =&gt; ({ ...a }));
  558. data.forEach((d) =&gt; {
  559. d.date = parseTime(d.date);
  560. });
  561. x2.domain(
  562. d3.extent(data, function (d) {
  563. return d.date;
  564. })
  565. );
  566. const charttooltip = d3
  567. .select(&quot;#time&quot;)
  568. .append(&quot;div&quot;)
  569. .attr(&quot;class&quot;, &quot;charttooltip&quot;);
  570. const chartguideline = d3
  571. .select(&quot;body&quot;)
  572. .append(&quot;div&quot;)
  573. .attr(&quot;class&quot;, &quot;chartguideline&quot;);
  574. let topY = d3.max(data, (d) =&gt; d.count);
  575. timeseries.selectAll(&quot;.axis&quot;).remove();
  576. let bisectDate = d3.bisector(function (d) {
  577. return d.date;
  578. }).left;
  579. chartfocus
  580. .on(&quot;mouseover&quot;, mouseover)
  581. .on(&quot;mousemove&quot;, mousemove)
  582. .on(&quot;mouseout&quot;, mouseout);
  583. y2.domain([0, topY]).nice();
  584. d3.select(&quot;.axis--y&quot;).transition(1000).call(yAxis2);
  585. d3.selectAll(&quot;.bar&quot;).remove();
  586. let dailyBars = chartfocus
  587. .selectAll(&quot;bar&quot;)
  588. .data(data)
  589. .enter()
  590. .append(&quot;rect&quot;)
  591. .attr(&quot;clip-path&quot;, &quot;url(#clip)&quot;)
  592. .attr(&quot;class&quot;, (d) =&gt; &quot;bar d&quot; + formatDate4(d.date));
  593. y2.domain([0, topY]).nice();
  594. d3.select(&quot;.axis--y&quot;).transition(1000).call(yAxis2);
  595. dailyBars
  596. .transition()
  597. .attr(&quot;width&quot;, (d) =&gt; x2(d3.timeDay.offset(d.date)) - x2(d.date))
  598. .attr(&quot;x&quot;, (d) =&gt; x2(d.date))
  599. .attr(&quot;y&quot;, (d) =&gt; y2(d.count))
  600. .attr(&quot;height&quot;, (d) =&gt; timeHeight - y2(d.count));
  601. chartfocus
  602. .append(&quot;g&quot;)
  603. .attr(&quot;class&quot;, &quot;axis axis--x&quot;)
  604. .attr(&quot;transform&quot;, &quot;translate(0,&quot; + timeHeight + &quot;)&quot;)
  605. .call(xAxis2);
  606. chartfocus.append(&quot;g&quot;).attr(&quot;class&quot;, &quot;axis axis--y&quot;).call(yAxis2);
  607. chartfocus
  608. .append(&quot;rect&quot;)
  609. .attr(&quot;class&quot;, &quot;chartzoom&quot;)
  610. .attr(&quot;width&quot;, timeWidth)
  611. .attr(&quot;height&quot;, timeHeight);
  612. d3.selectAll(&quot;.focus&quot;).remove();
  613. function mouseover(event) {}
  614. function mousemove(event, d) {
  615. let outerMargins = pageWidth - wrapWidth;
  616. let outerLeftMargin = outerMargins / 2;
  617. let ex = event.x - timeMargin.left - outerLeftMargin;
  618. var x0 = x2.invert(ex),
  619. i = bisectDate(data, x0, 1),
  620. d0 = data[i - 1],
  621. d1 = data[i],
  622. d = x0 - d0.date &gt; d1.date - x0 ? d1 : d0;
  623. let dateX = d.date;
  624. let dateXSimple = formatDate5(dateX);
  625. indvData = dataOld.filter((d) =&gt; d.date == dateXSimple);
  626. dailyCount = [];
  627. dailyCounts = [];
  628. let tooltip_str =
  629. formatDate5(dateX) + &quot;&lt;/p&gt;Count: &lt;strong&gt;&quot; + indvData[0].count;
  630. charttooltip
  631. .style(&quot;left&quot;, event.x - outerLeftMargin + &quot;px&quot;)
  632. .style(&quot;top&quot;, 0)
  633. .attr(&quot;x&quot;, 0)
  634. .html((d) =&gt; tooltip_str);
  635. chartguideline
  636. .style(&quot;left&quot;, event.x - 1 + &quot;px&quot;)
  637. .style(&quot;top&quot;, timeMargin.top + &quot;px&quot;)
  638. .attr(&quot;width&quot;, (d) =&gt; x2(d3.timeDay.offset(dateX)) - x2(dateX))
  639. .style(
  640. &quot;height&quot;,
  641. timeHeight + timeMargin.top - timeMargin.bottom + 45 + &quot;px&quot;
  642. )
  643. .attr(&quot;x&quot;, 0);
  644. charttooltip.style(&quot;visibility&quot;, &quot;visible&quot;);
  645. chartguideline.style(&quot;visibility&quot;, &quot;visible&quot;);
  646. }
  647. function mouseout() {
  648. d3.selectAll(&quot;.bar&quot;).style(&quot;fill&quot;, &quot;#aaa&quot;);
  649. d3.selectAll(&quot;.bar&quot;)
  650. .transition()
  651. .attr(&quot;width&quot;, (d) =&gt; x2(d3.timeDay.offset(d.date)) - x2(d.date));
  652. charttooltip.transition().duration(0).style(&quot;visibility&quot;, &quot;hidden&quot;);
  653. chartguideline.transition().duration(0).style(&quot;visibility&quot;, &quot;hidden&quot;);
  654. }
  655. }
  656. &lt;/script&gt;
  657. &lt;div id=&quot;time&quot;&gt;
  658. &lt;div id=&quot;timeseries-container&quot;&gt;
  659. &lt;svg width=&quot;100%&quot; viewBox=&quot;0 0 {timeW} {timeH}&quot; id=&quot;chart&quot; bind:this={el} /&gt;
  660. &lt;/div&gt;
  661. &lt;/div&gt;
  662. &lt;style&gt;
  663. .chartzoom {
  664. cursor: move;
  665. fill: none;
  666. pointer-events: all;
  667. }
  668. .charttooltip {
  669. position: absolute;
  670. pointer-events: none;
  671. padding: 10px;
  672. background: #fff;
  673. visibility: hidden;
  674. opacity: 0.9;
  675. -moz-box-shadow: 0 0 15px #aaa;
  676. -webkit-box-shadow: 0 0 15px #aaa;
  677. box-shadow: 0 0 15px #aaa;
  678. margin-left: 10px;
  679. }
  680. .charttooltip:before {
  681. right: 100%;
  682. top: 50%;
  683. border: solid transparent;
  684. content: &quot; &quot;;
  685. height: 0;
  686. width: 0;
  687. position: absolute;
  688. pointer-events: none;
  689. border-color: rgba(255, 255, 255, 0);
  690. border-right-color: #ffffff;
  691. border-width: 10px;
  692. margin-top: -10px;
  693. }
  694. .chartguideline {
  695. position: absolute;
  696. width: 1px;
  697. opacity: 0.5;
  698. pointer-events: none;
  699. background: #ef4136;
  700. visibility: hidden;
  701. }
  702. .bar {
  703. fill: #aaa;
  704. stroke-width: 1px;
  705. stroke: #000;
  706. }
  707. [1]: https://svelte.dev/repl/5e39f2a5622a43ba830b055b8fd6acf9?version=4.1.2
  708. </details>
  709. # 答案1
  710. **得分**: 2
  711. 你已经非常接近了只需等待HTML元素被挂载到页面上然后再执行任何d3渲染逻辑因为它们会操作DOM在它们存在之前你不能操作它们对吗
  712. 我看到你将svg绑定到了`el`变量上在初始化阶段它是`undefined`所以`d3.select(el)`会选择到空内容这就是原因
  713. 要解决这个问题只需将任何涉及DOM的操作包装在`onMount`生命周期回调中
  714. <details>
  715. <summary>英文:</summary>
  716. Youre very close! Just need to wait for the HTML elements to be mounted onto the page before executing any d3 render logics, cus they manipulate the DOM. You cant manipulate things before they even exist, can you?
  717. I see that you bind the svg to `el` variable. Its `undefined` during the initialization phase, so `d3.select(el)` would select nothing, thats why.
  718. To fix it, simply wrap anything DOM related in the `onMount` lifecycle callback.

import { onMount } from "svelte"
// ……

let el;
let timeW = 960,
timeH = 450;

// ……
onMount(() => {
let timeseries = d3
.select(el)
// …

})

答案2

得分: 1

你也可以只使用一个action。这不需要任何导入、状态变量声明或this绑定:

&lt;script&gt;
  // ...
  function initialize(svg) {
    d3.select(svg)...
  }
&lt;/script&gt;

&lt;svg use:initialize ...&gt;
英文:

You also just use an action. This does not require any imports, state variable declarations or this bindings:

&lt;script&gt;
  // ...
  function initialize(svg) {
    d3.select(svg)...
  }
&lt;/script&gt;

&lt;svg use:initialize ...&gt;

(Also, by using d3 like this you are losing most of the advantages of Svelte. Unless any of its advanced algorithms are used, I would recommend just building the SVG directly in Svelte markup. That way it stays declarative and more readable.)

huangapple
  • 本文由 发表于 2023年8月10日 23:40:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76877308.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定