demo.html 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
  6. <style>
  7. body {
  8. margin: 0;
  9. }
  10. #plot {
  11. width: 100vw;
  12. height: 100vh;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="plot"></div>
  18. <script>
  19. const xLabels = ["A", "B", "C"];
  20. const yLabels = ["Monday", "Tuesday", "Wednesday"];
  21. const dataMatrix = [
  22. [5, 8, 6],
  23. [4, 2, 9],
  24. [7, 3, 5],
  25. ];
  26. // 构造立方体柱子
  27. const traces = [];
  28. const barWidth = 0.8;
  29. for (let xi = 0; xi < xLabels.length; xi++) {
  30. for (let yi = 0; yi < yLabels.length; yi++) {
  31. const height = dataMatrix[yi][xi];
  32. const x = xi;
  33. const y = yi;
  34. const z = 0;
  35. // 立方体8个顶点
  36. const vertices = [
  37. [x, y, z],
  38. [x + barWidth, y, z],
  39. [x + barWidth, y + barWidth, z],
  40. [x, y + barWidth, z],
  41. [x, y, z + height],
  42. [x + barWidth, y, z + height],
  43. [x + barWidth, y + barWidth, z + height],
  44. [x, y + barWidth, z + height],
  45. ];
  46. // 每个立方体的面(两个三角形组成一个面)
  47. const faces = [
  48. [0, 1, 2],
  49. [0, 2, 3], // bottom
  50. [4, 5, 6],
  51. [4, 6, 7], // top
  52. [0, 1, 5],
  53. [0, 5, 4], // front
  54. [1, 2, 6],
  55. [1, 6, 5], // right
  56. [2, 3, 7],
  57. [2, 7, 6], // back
  58. [3, 0, 4],
  59. [3, 4, 7], // left
  60. ];
  61. // 拆解为 Plotly mesh3d 的输入格式
  62. const xVals = vertices.map((v) => v[0]);
  63. const yVals = vertices.map((v) => v[1]);
  64. const zVals = vertices.map((v) => v[2]);
  65. const i = faces.map((f) => f[0]);
  66. const j = faces.map((f) => f[1]);
  67. const k = faces.map((f) => f[2]);
  68. traces.push({
  69. type: "mesh3d",
  70. x: xVals,
  71. y: yVals,
  72. z: zVals,
  73. i,
  74. j,
  75. k,
  76. opacity: 1,
  77. color: `rgb(${50 + xi * 50}, ${100 + yi * 50}, 200)`,
  78. flatshading: true,
  79. showscale: false,
  80. });
  81. }
  82. }
  83. const layout = {
  84. scene: {
  85. xaxis: {
  86. title: "X",
  87. tickvals: [0.4, 1.4, 2.4],
  88. ticktext: xLabels,
  89. },
  90. yaxis: {
  91. title: "Y",
  92. tickvals: [0.4, 1.4, 2.4],
  93. ticktext: yLabels,
  94. },
  95. zaxis: { title: "Z" },
  96. aspectratio: {
  97. x: 2.2,
  98. y: 1.7,
  99. z: 1,
  100. },
  101. bgcolor: "#e5ecf6",
  102. aspectmode: "manual",
  103. gridcolor: "#fff",
  104. camera: {
  105. up: {
  106. x: 0.200292643688136,
  107. y: 0.2488259353493132,
  108. z: 0.947612004346693,
  109. },
  110. center: {
  111. x: -0.052807476121180814,
  112. y: 0.02451796399554085,
  113. z: -0.022911006648570736,
  114. },
  115. eye: {
  116. x: -2.126379643342493,
  117. y: -2.551422475965373,
  118. z: 1.0917667684145647,
  119. },
  120. projection: {
  121. type: "orthographic",
  122. },
  123. },
  124. staticPlot: false,
  125. showlegend: true,
  126. legend: {
  127. itemsizing: "constant", // ✅ 统一图例 marker 大小
  128. font: {
  129. size: 12,
  130. },
  131. marker: {
  132. size: 10,
  133. },
  134. },
  135. },
  136. margin: { t: 50, b: 50, l: 50, r: 50 },
  137. };
  138. Plotly.newPlot("plot", traces, layout);
  139. </script>
  140. </body>
  141. </html>