d3.js项目_渲染问题

ruoxqz4g  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(166)

我有一个基于d3 lib v.7.6.1构建的project
它托管在GitHub页面上,在我的笔记本电脑上完全可以正常工作:

但在大多数其他设备上呈现不正确:

ycy属性的控制台出错:

我在这里复制了代码。有什么问题吗?

  1. async function drawLineChart() {
  2. const pathToCsv = 'https://raw.githubusercontent.com/dsibi/portfolio/main/projects/line-graph-2/data/time_entries.csv';
  3. let rawDataset = await d3.dsv(";", pathToCsv);
  4. const record = {
  5. date: '',
  6. duration: ''
  7. };
  8. let dataset = [];
  9. for (let i = 0; i < rawDataset.length; i++) {
  10. let currRecord = Object.create(record);
  11. const [day, month, year] = rawDataset[i]['Start date'].split('.');
  12. currRecord.date = new Date(+year, +month - 1, +day);
  13. const [hours, minutes, seconds] = rawDataset[i]['Duration'].split(':');
  14. currRecord.duration = new Date(+year, +month - 1, +day, +hours, +minutes, +seconds);
  15. dataset.push(currRecord);
  16. }
  17. dataset.forEach(function(element) {
  18. let timeString = element.duration.toLocaleTimeString();
  19. let timeEl = timeString.split(':');
  20. element.durationSeconds = (+timeEl[0]) * 60 * 60 + (+timeEl[1]) * 60 + (+timeEl[2]);
  21. });
  22. var groupedDataset = [];
  23. dataset.reduce(function(res, value) {
  24. if (!res[value.date]) {
  25. res[value.date] = {
  26. date: value.date,
  27. totalDurationSeconds: 0
  28. };
  29. groupedDataset.push(res[value.date])
  30. }
  31. res[value.date].totalDurationSeconds += value.durationSeconds;
  32. return res;
  33. }, {});
  34. const xAccessor = d => d.date;
  35. const formatHours = d3.format(".2f");
  36. const yAccessor = d => +formatHours(d['totalDurationSeconds'] / 3600);
  37. const yAccessorLine = d => d['meanDurationHours'];
  38. let datasetWeeks = downsampleData(groupedDataset, xAccessor, yAccessor);
  39. const vacation = [{
  40. name: 'vacation',
  41. start: new Date('2022-06-16'),
  42. end: new Date('2022-06-26'),
  43. }, ];
  44. let dimensions = {
  45. width: window.innerWidth * 0.8,
  46. height: 400,
  47. margin: {
  48. top: 15,
  49. right: 40,
  50. bottom: 40,
  51. left: 40,
  52. },
  53. }
  54. dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right
  55. dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom
  56. // 3. Draw Canvas
  57. const wrapper = d3.select("#wrapper")
  58. .append("svg")
  59. .attr("width", dimensions.width)
  60. .attr("height", dimensions.height);
  61. const bounds = wrapper.append("g")
  62. .style("transform", `translate(${dimensions.margin.left}px, ${dimensions.margin.top}px)`);
  63. // 4. Scales
  64. const xScale = d3.scaleTime()
  65. .domain(d3.extent(groupedDataset, xAccessor))
  66. .range([0, dimensions.boundedWidth]);
  67. const yScale = d3.scaleLinear()
  68. .domain(d3.extent(groupedDataset, yAccessor))
  69. .range([dimensions.boundedHeight, 0])
  70. .nice();
  71. const meanHours = d3.mean(groupedDataset, yAccessor);
  72. bounds.append('line').attr('class', 'mean');
  73. const meanLine = bounds.select('.mean')
  74. .attr('x1', 0)
  75. .attr('x2', dimensions.boundedWidth)
  76. .attr('y1', yScale(meanHours))
  77. .attr('y2', yScale(meanHours));
  78. const xAxisGenerator = d3.axisBottom()
  79. .scale(xScale);
  80. const xAxis = bounds.append("g")
  81. .attr("class", "x-axis")
  82. .style("transform", `translateY(${dimensions.boundedHeight}px)`)
  83. .call(xAxisGenerator);
  84. // 5. Draw Data
  85. //dots
  86. const dots = bounds.selectAll(".dot")
  87. .data(groupedDataset)
  88. .enter()
  89. .append("circle")
  90. .attr("cx", d => xScale(xAccessor(d)))
  91. .attr("cy", d => yScale(yAccessor(d)))
  92. .attr("r", 2)
  93. .attr("class", "dot");
  94. //line
  95. const lineGenerator = d3.line()
  96. .x(function(d) {
  97. // console.log(xScale(xAccessor(d)))
  98. return xScale(xAccessor(d))
  99. })
  100. .y(d => yScale(yAccessorLine(d)))
  101. .curve(d3.curveCatmullRom.alpha(.5));
  102. // .curve(d3.curveMonotoneX);
  103. const line = bounds.append("path")
  104. .attr("class", "line")
  105. .attr("d", lineGenerator(datasetWeeks))
  106. // 6. Draw Peripherals
  107. const yAxisGenerator = d3.axisLeft()
  108. .scale(yScale)
  109. .ticks(7);
  110. const yAxis = bounds.append("g")
  111. .attr("class", "y-axis")
  112. .call(yAxisGenerator);
  113. };
  114. drawLineChart();
  115. function downsampleData(data, xAccessor, yAccessor) {
  116. const weeks = d3.timeWeeks(xAccessor(data[0]), xAccessor(data[data.length - 1]))
  117. return weeks.map((week, index) => {
  118. const weekEnd = weeks[index + 1] || new Date()
  119. const days = data.filter(d => xAccessor(d) > week && xAccessor(d) <= weekEnd)
  120. const meanTotalDurationHours = d3.mean(days, yAccessor)
  121. const meanDurationHours = meanTotalDurationHours === undefined ? 0 : d3.mean(days, yAccessor)
  122. return {
  123. date: week,
  124. meanDurationHours: meanDurationHours
  125. }
  126. })
  127. };
  1. .line {
  2. fill: none;
  3. stroke: #eb4511;
  4. stroke-width: 3;
  5. }
  6. .mean {
  7. stroke: #7d82b8;
  8. stroke-dasharray: 2px 4px;
  9. }
  10. .y-axis-label {
  11. fill: black;
  12. font-size: 1.4em;
  13. text-anchor: middle;
  14. }
  15. .x-axis-label {
  16. fill: black;
  17. font-size: 1.4em;
  18. text-anchor: middle;
  19. }
  20. .dot {
  21. fill: #9c9b98;
  22. }
  23. .mean_text,
  24. .vacation_text {
  25. fill: #7d82b8;
  26. font-size: .8em;
  27. font-weight: 800;
  28. text-anchor: start;
  29. }
  30. .x-axis line,
  31. .y-axis line,
  32. .domain {
  33. stroke: gray;
  34. }
  35. .tick text,
  36. .y-axis-label {
  37. fill: gray
  38. }
  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
  2. <html lang="en">
  3. <body>
  4. <div id="wrapper">
  5. </div>
  6. </body>
  7. </html>
yptwkmov

yptwkmov1#

您的问题是由toLocaleTimeString()引起的。
当将console.log()添加到以下部件时:

  1. dataset.forEach(function(element) {
  2. let timeString = element.duration.toLocaleTimeString();
  3. let timeEl = timeString.split(':');
  4. console.log(timeString, timeEl)
  5. element.durationSeconds = (+timeEl[0]) * 60 * 60 + (+timeEl[1]) * 60 + (+timeEl[2]);
  6. });

字符串
Dekstop显示:

  1. 00:19:34 (3) ['00', '19', '34']


但我的移动的(使用Chrome远程检查器)显示:

  1. 12:06:53 AM (3) ['12', '06', '53 AM']


所以当你计算* 60 + (+timeEl[2])时,你会得到NaN,因为53 AM
您应该更改时间逻辑,以便能够解析24和12小时格式的时间,例如,使用:

这是我试图解决这个问题。
我已经使用new Date()将其转换为日期对象。然后使用valueOf()to get the unix timestamp。现在我们只需要将它们相互子合并以获得durationSeconds

  1. dataset.forEach(function(element) {
  2. let secondsDiff = new Date(element.duration).valueOf() - new Date(element.date).valueOf();
  3. element.durationSeconds = secondsDiff;
  4. });


这既适用于我的笔记本电脑作为移动的:

更新片段:

  1. async function drawLineChart() {
  2. const pathToCsv = 'https://raw.githubusercontent.com/dsibi/portfolio/main/projects/line-graph-2/data/time_entries.csv';
  3. let rawDataset = await d3.dsv(";", pathToCsv);
  4. const record = {
  5. date: '',
  6. duration: ''
  7. };
  8. let dataset = [];
  9. for (let i = 0; i < rawDataset.length; i++) {
  10. let currRecord = Object.create(record);
  11. const [day, month, year] = rawDataset[i]['Start date'].split('.');
  12. currRecord.date = new Date(+year, +month - 1, +day);
  13. const [hours, minutes, seconds] = rawDataset[i]['Duration'].split(':');
  14. currRecord.duration = new Date(+year, +month - 1, +day, +hours, +minutes, +seconds);
  15. dataset.push(currRecord);
  16. }
  17. dataset.forEach(function(element) {
  18. let secondsDiff = new Date(element.duration).valueOf() - new Date(element.date).valueOf();
  19. element.durationSeconds = secondsDiff;
  20. });
  21. var groupedDataset = [];
  22. dataset.reduce(function(res, value) {
  23. if (!res[value.date]) {
  24. res[value.date] = {
  25. date: value.date,
  26. totalDurationSeconds: 0
  27. };
  28. groupedDataset.push(res[value.date])
  29. }
  30. res[value.date].totalDurationSeconds += value.durationSeconds;
  31. return res;
  32. }, {});
  33. const xAccessor = d => d.date;
  34. const formatHours = d3.format(".2f");
  35. const yAccessor = d => +formatHours(d['totalDurationSeconds'] / 3600);
  36. const yAccessorLine = d => d['meanDurationHours'];
  37. let datasetWeeks = downsampleData(groupedDataset, xAccessor, yAccessor);
  38. const vacation = [{
  39. name: 'vacation',
  40. start: new Date('2022-06-16'),
  41. end: new Date('2022-06-26'),
  42. }, ];
  43. let dimensions = {
  44. width: window.innerWidth * 0.8,
  45. height: 400,
  46. margin: {
  47. top: 15,
  48. right: 40,
  49. bottom: 40,
  50. left: 40,
  51. },
  52. }
  53. dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right
  54. dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom
  55. // 3. Draw Canvas
  56. const wrapper = d3.select("#wrapper")
  57. .append("svg")
  58. .attr("width", dimensions.width)
  59. .attr("height", dimensions.height);
  60. const bounds = wrapper.append("g")
  61. .style("transform", `translate(${dimensions.margin.left}px, ${dimensions.margin.top}px)`);
  62. // 4. Scales
  63. const xScale = d3.scaleTime()
  64. .domain(d3.extent(groupedDataset, xAccessor))
  65. .range([0, dimensions.boundedWidth]);
  66. const yScale = d3.scaleLinear()
  67. .domain(d3.extent(groupedDataset, yAccessor))
  68. .range([dimensions.boundedHeight, 0])
  69. .nice();
  70. const meanHours = d3.mean(groupedDataset, yAccessor);
  71. bounds.append('line').attr('class', 'mean');
  72. const meanLine = bounds.select('.mean')
  73. .attr('x1', 0)
  74. .attr('x2', dimensions.boundedWidth)
  75. .attr('y1', yScale(meanHours))
  76. .attr('y2', yScale(meanHours));
  77. const xAxisGenerator = d3.axisBottom()
  78. .scale(xScale);
  79. const xAxis = bounds.append("g")
  80. .attr("class", "x-axis")
  81. .style("transform", `translateY(${dimensions.boundedHeight}px)`)
  82. .call(xAxisGenerator);
  83. // 5. Draw Data
  84. //dots
  85. const dots = bounds.selectAll(".dot")
  86. .data(groupedDataset)
  87. .enter()
  88. .append("circle")
  89. .attr("cx", d => xScale(xAccessor(d)))
  90. .attr("cy", d => yScale(yAccessor(d)))
  91. .attr("r", 2)
  92. .attr("class", "dot");
  93. //line
  94. const lineGenerator = d3.line()
  95. .x(function(d) {
  96. // console.log(xScale(xAccessor(d)))
  97. return xScale(xAccessor(d))
  98. })
  99. .y(d => yScale(yAccessorLine(d)))
  100. .curve(d3.curveCatmullRom.alpha(.5));
  101. // .curve(d3.curveMonotoneX);
  102. const line = bounds.append("path")
  103. .attr("class", "line")
  104. .attr("d", lineGenerator(datasetWeeks))
  105. // 6. Draw Peripherals
  106. const yAxisGenerator = d3.axisLeft()
  107. .scale(yScale)
  108. .ticks(7);
  109. const yAxis = bounds.append("g")
  110. .attr("class", "y-axis")
  111. .call(yAxisGenerator);
  112. };
  113. drawLineChart();
  114. function downsampleData(data, xAccessor, yAccessor) {
  115. const weeks = d3.timeWeeks(xAccessor(data[0]), xAccessor(data[data.length - 1]))
  116. return weeks.map((week, index) => {
  117. const weekEnd = weeks[index + 1] || new Date()
  118. const days = data.filter(d => xAccessor(d) > week && xAccessor(d) <= weekEnd)
  119. const meanTotalDurationHours = d3.mean(days, yAccessor)
  120. const meanDurationHours = meanTotalDurationHours === undefined ? 0 : d3.mean(days, yAccessor)
  121. return {
  122. date: week,
  123. meanDurationHours: meanDurationHours
  124. }
  125. })
  126. };
  1. .line {
  2. fill: none;
  3. stroke: #eb4511;
  4. stroke-width: 3;
  5. }
  6. .mean {
  7. stroke: #7d82b8;
  8. stroke-dasharray: 2px 4px;
  9. }
  10. .y-axis-label {
  11. fill: black;
  12. font-size: 1.4em;
  13. text-anchor: middle;
  14. }
  15. .x-axis-label {
  16. fill: black;
  17. font-size: 1.4em;
  18. text-anchor: middle;
  19. }
  20. .dot {
  21. fill: #9c9b98;
  22. }
  23. .mean_text,
  24. .vacation_text {
  25. fill: #7d82b8;
  26. font-size: .8em;
  27. font-weight: 800;
  28. text-anchor: start;
  29. }
  30. .x-axis line,
  31. .y-axis line,
  32. .domain {
  33. stroke: gray;
  34. }
  35. .tick text,
  36. .y-axis-label {
  37. fill: gray
  38. }
  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
  2. <html lang="en">
  3. <body>
  4. <div id="wrapper">
  5. </div>
  6. </body>
  7. </html>
展开查看全部

相关问题