sleepCharts.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <view style="position: relative;">
  3. <canvas :style="{width: width + 'px',height:height + 'px'}" class="sleepcanvas" canvas-id="sleepCanvas" @click="handleSleepcharts"></canvas>
  4. <view class="timebox">
  5. <view class="timebox-start">
  6. <view>{{startSleepTime.substring(5,10)}}</view>
  7. <view>{{startSleepTime.substring(11,16)}}入睡</view>
  8. </view>
  9. <view class="timebox-end">
  10. <view>{{endSleepTime.substring(5,10)}}</view>
  11. <view>{{endSleepTime.substring(11,16)}}醒来</view>
  12. </view>
  13. </view>
  14. </view>
  15. </template>
  16. <script>
  17. export default {
  18. name: "sleepCharts",
  19. props: {
  20. sleepValue: {
  21. type: Array,
  22. default: []
  23. },
  24. // 1:默认样式,每个数据柱从最底部出发 ,2:悬浮样式,各个数据类型的起始高度不同
  25. type: {
  26. type: Number,
  27. default: 1
  28. },
  29. sleepData: {
  30. type: Object,
  31. default: {}
  32. },
  33. },
  34. data() {
  35. return {
  36. showLoading: false,
  37. width: uni.getSystemInfoSync().windowWidth - uni.upx2px(96),
  38. height: uni.upx2px(382),
  39. touchValue: {},
  40. startSleepTime: "",
  41. endSleepTime: "",
  42. style: "",
  43. ctx: null,
  44. dataList: []
  45. }
  46. },
  47. methods: {
  48. initData() {
  49. this.dataList = []
  50. if(this.sleepValue && this.sleepValue.length > 0) {
  51. let result = [];
  52. let previousObj = null;
  53. for (let i = 0; i < this.sleepValue.length; i++) {
  54. let currentObj = this.sleepValue[i];
  55. if (previousObj && currentObj.start !== previousObj.end) {
  56. let newObject = {
  57. end: currentObj.start,
  58. start: previousObj.end,
  59. type: -1
  60. };
  61. result.push(newObject);
  62. }
  63. result.push(currentObj);
  64. previousObj = currentObj;
  65. }
  66. this.dataList = result
  67. this.calculateSNTime();
  68. this.drawCharts();
  69. }
  70. },
  71. // 获睡眠的总秒数
  72. getAllTime() {
  73. const first = new Date(this.dataList[0].start).getTime();
  74. const last = new Date(this.dataList[this.dataList.length - 1].end).getTime();
  75. let allTime = Math.floor((last - first) / 1000);
  76. return allTime;
  77. },
  78. // 计算开始结束时间
  79. calculateSNTime() {
  80. this.startSleepTime = this.dataList[0].start;
  81. this.endSleepTime = this.dataList[this.dataList.length - 1].end;
  82. },
  83. // 绘制睡眠图
  84. drawCharts() {
  85. let ALLTIME = this.getAllTime();
  86. let {
  87. width, // x
  88. height // y
  89. } = this;
  90. let context = uni.createCanvasContext('sleepCanvas', this);
  91. this.ctx = context;
  92. context.setLineWidth(1);
  93. let xValue = 0;
  94. this.showLoading = true
  95. this.dataList.map((item, index) => {
  96. // ============== 计算矩形的颜色 ============== //
  97. // 3 深睡,4 浅睡,6 清醒,7 快速眼动
  98. switch (item.type) {
  99. case 3: // 深睡
  100. context.setFillStyle("#8C37E6");
  101. item.sleepStateText = "深睡";
  102. break;
  103. case 4: // 浅睡
  104. context.setFillStyle("#D138CF");
  105. item.sleepStateText = "浅睡";
  106. break;
  107. case 6: // 清醒
  108. context.setFillStyle("#FDBD27");
  109. item.sleepStateText = "清醒";
  110. break;
  111. case 7: // 快速眼动
  112. context.setFillStyle("#F88082");
  113. item.sleepStateText = "快速眼动";
  114. break;
  115. default:
  116. context.setFillStyle("#FFFFFF");
  117. item.sleepStateText = "其他";
  118. }
  119. // ========================================= //
  120. // ============== 计算矩形的高度 ============== //
  121. let yValue = uni.upx2px(80);
  122. if (item.type == 3) {
  123. yValue = yValue * 1;
  124. } else if (item.type == 4) {
  125. yValue = yValue * 2;
  126. } else if (item.type == 6) {
  127. yValue = yValue * 4;
  128. } else if (item.type == 7) {
  129. yValue = yValue * 3;
  130. } else {
  131. yValue = yValue * 5;
  132. }
  133. // ========================================= //
  134. // ============== 计算矩形的宽 =============== //
  135. let value = Math.floor((new Date(item.end).getTime() - new Date(item.start).getTime()) / 1000);
  136. // ========================================= //
  137. value = value / ALLTIME * width;
  138. // =============== 绘制数据柱 ================ //
  139. let spacingH = uni.upx2px(80)
  140. if (this.type === 1) {
  141. context.fillRect(xValue, height, value, -yValue);
  142. } else if (this.type === 2) {
  143. // 根据数据类型 更改这类柱子y轴起始位置
  144. if (item.type == 3) {
  145. context.fillRect(xValue, height- spacingH, value, spacingH);
  146. } else if (item.type == 4){
  147. context.fillRect(xValue, height - yValue, value, spacingH);
  148. } else if (item.type == 6){
  149. context.fillRect(xValue, height - yValue, value, spacingH);
  150. } else if (item.type == 7){
  151. context.fillRect(xValue, height - yValue, value, spacingH);
  152. } else {
  153. context.fillRect(xValue, height, value, -yValue);
  154. }
  155. }
  156. // ========================================= //
  157. xValue = xValue + value; // 计算下一次x轴开始画的位置
  158. context.stroke()
  159. })
  160. this.showLoading = false
  161. context.draw()
  162. this.touchValue = {
  163. startTime: this.dataList[0].start + ":00",
  164. endTime: this.dataList[this.dataList.length-1].end + ":00",
  165. type: '',
  166. sleepStateText: '总睡眠',
  167. hours: "",
  168. minutes: ""
  169. }
  170. const all = this.sleepData.deepSleep + this.sleepData.lightSleep + this.sleepData.weakSleep + this.sleepData.eyemoveSleep
  171. this.touchValue.hours = Math.floor(all / 60)
  172. this.touchValue.minutes = all % 60
  173. this.$emit("handleItem", this.touchValue,'init');
  174. },
  175. // 点击睡眠图表
  176. handleSleepcharts(e) {
  177. // 这段睡眠的总秒数
  178. const ALLTIME = this.getAllTime();
  179. // 点击的坐标
  180. const touchX = e.detail.x - e.currentTarget.offsetLeft-uni.upx2px(48);
  181. // 图表的总宽度
  182. const chartsWidth = this.width;
  183. // 获取点击位置在睡眠中从开始到点击这一刻的秒数
  184. const second = touchX / chartsWidth * ALLTIME;
  185. // 获取点击位置的时间戳
  186. const timeStamp = (new Date(this.dataList[0].start).getTime() / 1000) + second;
  187. let touchStartTime = null,
  188. touchEndTime = null;
  189. // 获取点击位置对应的数组项
  190. this.dataList.forEach((item,index) => {
  191. if (timeStamp > (new Date(item.start).getTime() / 1000) && timeStamp < (new Date(item.end).getTime() / 1000)) {
  192. this.touchValue = {
  193. startTime: item.start + ":00",
  194. endTime: item.end + ":00",
  195. type: item.type,
  196. sleepStateText: item.sleepStateText
  197. }
  198. }
  199. })
  200. this.$emit("handleItem", this.touchValue);
  201. },
  202. }
  203. }
  204. </script>
  205. <style scoped lang="scss">
  206. .timebox-touch {
  207. color: #fff;
  208. text-align:center;
  209. min-width:300rpx;
  210. padding: 6rpx 10rpx;
  211. box-sizing: border-box;
  212. // height:48rpx;
  213. border-radius:28rpx;
  214. font-size: 20rpx;
  215. // line-height:48rpx;
  216. }
  217. .type3 {
  218. background-color: rgba(140, 55, 230, 0.3);
  219. }
  220. .type4 {
  221. background-color: rgba(209, 56, 207, 0.3);
  222. }
  223. .type6 {
  224. background-color: rgba(248, 128, 130, 0.3);
  225. }
  226. .type7 {
  227. background-color: rgba(253, 189, 39, 0.3);
  228. }
  229. .sleepcanvas {
  230. border-bottom: 1rpx dashed #ECECEC;
  231. }
  232. .timebox {
  233. display: flex;
  234. align-items: center;
  235. justify-content: space-between;
  236. font-family: PingFang SC, PingFang SC;
  237. font-weight: 400;
  238. font-size: 20rpx;
  239. color: #999999;
  240. text-align: center;
  241. padding: 10rpx 0;
  242. }
  243. .timebox-start {
  244. }
  245. .timebox-end {
  246. }
  247. </style>