WindRoseChart.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <div>
  3. <div
  4. v-loading="loading"
  5. :id="`plotDiv-${inds}`"
  6. style="width: 100%; height: 450px"
  7. >
  8. <el-empty v-if="isError" description="请求失败"></el-empty>
  9. </div>
  10. </div>
  11. </template>
  12. <script>
  13. import Plotly from "plotly.js-dist";
  14. import axios from "axios";
  15. import { myMixin } from "@/mixins/chartRequestMixin";
  16. import { colorSchemes } from "@/views/overview/js/colors";
  17. import { mapState } from "vuex";
  18. export default {
  19. props: {
  20. fileAddr: {
  21. default: "",
  22. type: String,
  23. },
  24. inds: {
  25. type: [Number, String],
  26. default: 1,
  27. },
  28. },
  29. mixins: [myMixin],
  30. data() {
  31. return {
  32. // 数据结构
  33. chartData: {},
  34. color1: colorSchemes[0].colors, // 默认颜色
  35. // 配色方案列表(每个方案是一个颜色数组)
  36. colorSchemes: [...colorSchemes],
  37. };
  38. },
  39. computed: {
  40. ...mapState("themes", {
  41. themeColor: "themeColor",
  42. }),
  43. },
  44. watch: {
  45. chartData: {
  46. deep: true,
  47. handler(v) {
  48. if (v) {
  49. this.renderChart();
  50. }
  51. },
  52. },
  53. themeColor: {
  54. handler() {
  55. this.color1 = this.themeColor;
  56. this.renderChart();
  57. },
  58. deep: true,
  59. },
  60. },
  61. mounted() {
  62. this.getData();
  63. this.color1 = this.themeColor;
  64. },
  65. methods: {
  66. async getData() {
  67. if (this.fileAddr !== "") {
  68. try {
  69. this.loading = true;
  70. this.cancelToken = axios.CancelToken.source();
  71. console.log(this.cancelToken);
  72. const resultChartsData = await axios.get(this.fileAddr, {
  73. cancelToken: this.cancelToken.token,
  74. });
  75. console.log(resultChartsData);
  76. this.chartData = resultChartsData.data;
  77. this.renderChart();
  78. this.isError = false;
  79. this.loading = false;
  80. } catch (error) {
  81. this.isError = true;
  82. this.loading = false;
  83. }
  84. }
  85. },
  86. renderChart() {
  87. const { axes, data, analysisTypeCode } = this.chartData;
  88. // 从数据中提取 windSpeedRange 和动态生成 speedLabels 和 colorscale
  89. const windSpeedRanges = new Set();
  90. data.forEach((engine) => {
  91. engine.windRoseData.forEach((item) => {
  92. windSpeedRanges.add(item.windSpeedRange);
  93. });
  94. });
  95. const speedLabels = Array.from(windSpeedRanges).sort(); // 动态范围值
  96. const colors = [...this.color1]; // 可扩展颜色列表
  97. const colorscale = {};
  98. speedLabels.forEach((label, index) => {
  99. colorscale[label] = colors[index % colors.length];
  100. });
  101. // 定义风向的 16 等分
  102. const windDirections = Array.from({ length: 16 }, (_, i) => i * 22.5);
  103. // 数据聚合
  104. const counts = {};
  105. speedLabels.forEach((speedLabel) => {
  106. counts[speedLabel] = Array(windDirections.length).fill(0);
  107. });
  108. data.forEach((engine) => {
  109. engine.windRoseData.forEach((item) => {
  110. const { windDirection, windSpeedRange } = item;
  111. const index = windDirections.findIndex(
  112. (dir, i) =>
  113. windDirection >= dir && windDirection < windDirections[i + 1]
  114. );
  115. if (index !== -1 && counts[windSpeedRange]) {
  116. counts[windSpeedRange][index] += item.frequency;
  117. }
  118. });
  119. });
  120. // 构建 traces
  121. const traces = speedLabels.map((speedLabel) => {
  122. const percentage = counts[speedLabel];
  123. return {
  124. r: percentage,
  125. theta: windDirections,
  126. name: speedLabel,
  127. type: "barpolar",
  128. marker: {
  129. color: colorscale[speedLabel],
  130. line: {
  131. color: "white",
  132. width: 1,
  133. },
  134. },
  135. hovertemplate:
  136. `${axes.radial}:` +
  137. ` %{r} <br> ` +
  138. `${axes.angular}:` +
  139. "%{theta} <br> <extra></extra>",
  140. };
  141. });
  142. // 图表布局
  143. const layout = {
  144. title: `${analysisTypeCode} - ${data[0]?.enginName} `,
  145. plot_bgcolor: "#e5ecf6",
  146. polar: {
  147. bgcolor: "#e5ecf6",
  148. radialaxis: {
  149. title: { text: axes.radial },
  150. gridcolor: "rgb(255,255,255)",
  151. showgrid: true,
  152. linecolor: "rgb(255,255,255)",
  153. },
  154. angularaxis: {
  155. title: { text: axes.angular },
  156. tickvals: windDirections,
  157. gridcolor: "rgb(255,255,255)",
  158. tickcolor: "rgb(255,255,255)",
  159. linecolor: "rgb(255,255,255)",
  160. },
  161. },
  162. showlegend: true,
  163. legend: { title: { text: axes.levelname } },
  164. };
  165. Plotly.newPlot(`plotDiv-${this.inds}`, traces, layout);
  166. },
  167. },
  168. };
  169. </script>
  170. <style scoped></style>