GanttChart_month.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. import moment from 'moment'
  2. window._moment = moment
  3. /**
  4. * 甘特图
  5. * @param {} options
  6. */
  7. export function GanttChartMonth(options) {
  8. // 任务列表
  9. this.tasks = options.tasks || []
  10. // AntVG Canvas
  11. this.gCanvas = null
  12. // 视口宽度 800,可视区域
  13. this.viewWidth = options['viewWidth'] || 800
  14. // 物理画布宽度 800
  15. this.cWidth = options['cWidth'] || 2400
  16. this.cHeight = options['cHeight'] || 1600
  17. // 画布偏移位置
  18. this.startPos = 0
  19. // 是否拖动中
  20. this.draging = false
  21. // 开始拖动事件
  22. this.startEvent = null
  23. // 结束拖动事件
  24. this.endEvent = null
  25. // 拖动过程事件
  26. this.dragingEvent = null
  27. // 拖动偏移量
  28. this.offsetDis = options['viewWidth'] / 2 || 800
  29. // 拖动定时器
  30. this.dragTimer = null
  31. // 分组标题高度
  32. this.groupTitleHeight = 18
  33. // 任务矩形高度
  34. this.taskRowHeight = 16
  35. // 每行任务的纵向间距
  36. this.rowSpanDis = 22
  37. // 总天数
  38. this.daysCount = options['daysCount'] || 365 * 1.5
  39. // 任务图距离顶部高度
  40. this.graphTopDis = 60
  41. // 任务矩形最小宽度
  42. this.minTaskRectWidth = 5
  43. // console.log('daysCount:', this.daysCount)
  44. // 每秒数代表的像素
  45. this.timePerPix = this.cWidth / (this.daysCount * 24 * 3600)
  46. // 每天的间隔宽度
  47. this.dayStep = this.timePerPix * 3600 * 24
  48. // 当前视图开始时间,向前推N天
  49. this.startAt = moment().startOf('year')
  50. this.endAt = moment()
  51. .endOf('year')
  52. .add(6, 'months')
  53. this.graphDiv = document.getElementById(options['chartParentContainer'])
  54. this.chartContainer = options['chartContainer']
  55. // 图形容器组
  56. this.graphGroup = null
  57. // 上一次拖动的事件
  58. this.lastDragEv = null
  59. // 当日刻度线
  60. this.todayTimeLineEl = null
  61. // 点击回调事件
  62. this.callback = options.callback || null
  63. // 翻页时间回调
  64. this.pageToCallback = options.pageToCallback || null
  65. // hover背景条
  66. this.hoverEl = null
  67. }
  68. /**
  69. * 设置数据
  70. * @param {*} _tasks
  71. */
  72. GanttChartMonth.prototype.changeTasks = function(_tasks) {
  73. this.tasks = _tasks
  74. console.error('change tasks data here....', this.tasks)
  75. this.forceRefreshGraph()
  76. }
  77. /**
  78. * 打开关闭分组
  79. */
  80. GanttChartMonth.prototype.toggle = function(index) {
  81. if (this.tasks[index].open) {
  82. this.tasks[index].open = false
  83. } else {
  84. this.tasks[index].open = true
  85. }
  86. this.gCanvas.destroy()
  87. this.initDrawingReady()
  88. // this.processData()
  89. // this.drawTasks()
  90. }
  91. /**
  92. * 预处理数据
  93. */
  94. GanttChartMonth.prototype.processData = function() {
  95. for (let i = 0; i < this.tasks.length; i++) {
  96. let currentTopTask = this.tasks[i]
  97. let lastTopTask = null
  98. currentTopTask.renderOptions = {}
  99. // 设置StartY
  100. if (i != 0) {
  101. // 非0个,要补上前面的数据
  102. lastTopTask = this.tasks[i - 1]
  103. currentTopTask.renderOptions.startY = lastTopTask.renderOptions.endY + 20
  104. } else {
  105. // 第一个
  106. currentTopTask.renderOptions.startY = this.graphTopDis
  107. }
  108. // 设置EndY
  109. // 当有数据 且 打开时,
  110. // EndY = StartY + 标题上间距 + 标题 高度 + 任务个数 * (任务高度)
  111. if (currentTopTask.dataList.length > 0 && currentTopTask.open) {
  112. currentTopTask.renderOptions.endY = currentTopTask.renderOptions.startY + this.groupTitleHeight + currentTopTask.dataList.length * 38
  113. } else {
  114. currentTopTask.renderOptions.endY = currentTopTask.renderOptions.startY + this.groupTitleHeight
  115. }
  116. }
  117. }
  118. /**
  119. * 强制清空图像,重绘
  120. */
  121. GanttChartMonth.prototype.forceRefreshGraph = function() {
  122. this.tasks.forEach((topTask) => {
  123. topTask.gGroup = null
  124. })
  125. this.todayTimeLineEl = null
  126. this.gCanvas.destroy()
  127. this.hoverEl = null;
  128. this.initDrawingReady()
  129. }
  130. GanttChartMonth.prototype.initHoverElHandler = function(){
  131. let that = this
  132. this.gCanvas.on('mousemove', (ev)=>{
  133. if(that.hoverEl){
  134. that.hoverEl.attr({
  135. y: ev.y
  136. })
  137. that.hoverEl.setZIndex(-1)
  138. }
  139. })
  140. }
  141. /**
  142. * 准备绘制,用于初始化和强制刷新
  143. */
  144. GanttChartMonth.prototype.initDrawingReady = function() {
  145. this.initCanvas()
  146. setTimeout(() => {
  147. this.initDragHandler()
  148. this.drawTimeZone()
  149. this.processData()
  150. this.drawTasks()
  151. // this.drawTimeZone()
  152. this.initHoverElHandler()
  153. this.graphGroup = null
  154. }, 200)
  155. }
  156. /**
  157. * 翻页
  158. */
  159. GanttChartMonth.prototype.pageTo = function(dir = 'next') {
  160. this.draging = false
  161. this.endEvent = null
  162. if (dir == 'next') {
  163. // 向后翻页`
  164. this.startAt = this.startAt.add(366, 'days')
  165. this.offsetDis = 0
  166. } else {
  167. // 向前翻页
  168. this.startAt = this.startAt.subtract(365, 'days')
  169. this.offsetDis = 2380 //2*this.viewWidth
  170. }
  171. this.endAt = moment(this.startAt).add(this.daysCount, 'days')
  172. this.pageToCallback({ dir: dir, startAt: this.startAt.format('YYYY-MM-DD'), endAt: this.endAt.format('YYYY-MM-DD') })
  173. // console.log('已翻页', this.startAt.format('YYYY-MM-DD'), this.endAt.format('YYYY-MM-DD'), this.offsetDis)
  174. // offsetDis = viewWidth;
  175. // this.forceRefreshGraph();
  176. }
  177. // 上次点击时间,用于滚动时误触停止
  178. let lastClickAt = null
  179. /**
  180. * 执行拖动
  181. * 改变graphDiv 滚动距离
  182. * 到达边界距离后,刷新页面
  183. */
  184. GanttChartMonth.prototype.doDrag = function(sEvent, eEvent) {
  185. if (sEvent == null) {
  186. sEvent = this.startEvent
  187. }
  188. let sPos = sEvent.clientX
  189. let cPos = eEvent.clientX
  190. // 滚动距离
  191. let dis = cPos - sPos
  192. let tempDis = this.offsetDis
  193. // console.log('offsetDis before:', this.offsetDis, dis)
  194. this.offsetDis = this.offsetDis - dis / 2
  195. // console.log('draging...',tempDis, this.offsetDis, dis)
  196. if (this.offsetDis <= -20) {
  197. // 向前滑动,向前翻页
  198. // console.log('此处应该向前翻页', this.startAt.format('YYYY-MM-DD'), this.endAt.format('YYYY-MM-DD'), this.offsetDis)
  199. this.offsetDis = this.viewWidth
  200. this.pageTo('prev')
  201. }
  202. if (this.offsetDis - 20 >= this.viewWidth * 2.2) {
  203. //cWidth - viewWidth) {
  204. // 向后滑动,向后翻页
  205. // console.log('此处应该向后翻页', this.startAt.format('YYYY-MM-DD'), this.endAt.format('YYYY-MM-DD'), this.offsetDis)
  206. this.offsetDis = this.viewWidth
  207. this.pageTo('next')
  208. }
  209. this.graphDiv.scrollLeft = this.offsetDis
  210. }
  211. /**
  212. * 初始化抓取拖动事件
  213. */
  214. GanttChartMonth.prototype.initDragHandler = function() {
  215. this.graphDiv.scrollLeft = this.offsetDis
  216. let _canvas = this._canvas
  217. _canvas.addEventListener('mousedown', (ev) => {
  218. this.draging = true
  219. this.startEvent = ev
  220. this.dragingEvent = null
  221. this.endEvent = null
  222. this.lastClickAt = new Date()
  223. this.lastClickAt = ev
  224. this.lastDragEv = ev
  225. })
  226. _canvas.addEventListener('mouseleave', (ev) => {
  227. // console.log('leave...恢复')
  228. this.draging = false
  229. this.endEvent = ev
  230. })
  231. _canvas.addEventListener('mouseup', (ev) => {
  232. this.draging = false
  233. this.endEvent = ev
  234. })
  235. _canvas.addEventListener('mousemove', (ev) => {
  236. // console.log('this over', this)
  237. if (this.draging) {
  238. if (new Date() - this.lastClickAt < 20) {
  239. return false
  240. }
  241. this.dragingEvent = ev
  242. this.doDrag(this.lastDragEv, ev)
  243. this.lastDragEv = ev
  244. }
  245. })
  246. }
  247. /**
  248. * 初始化画布
  249. *
  250. */
  251. GanttChartMonth.prototype.initCanvas = function() {
  252. console.error('初始化画布...')
  253. this.gCanvas = new G.Canvas({
  254. container: this.chartContainer,
  255. width: this.cWidth,
  256. height: this.cHeight,
  257. })
  258. this._canvas = document.querySelector('#ganttContainer>canvas')
  259. }
  260. /**
  261. * 绘制时间区域
  262. */
  263. GanttChartMonth.prototype.drawTimeZone = function() {
  264. // console.log('时间段', this.startAt.format('YYYY-MM-DD'), this.endAt.format('YYYY-MM-DD'))
  265. let start = moment(this.startAt)
  266. let timeGroup = this.gCanvas.addGroup()
  267. this.timeGroupEl = timeGroup
  268. timeGroup._tname = 'TimeGroup'
  269. // 顶部底部边框
  270. timeGroup.addShape('rect', {
  271. attrs: {
  272. x: 0,
  273. y: 0,
  274. width: this.cWidth,
  275. height: 52,
  276. fill: '#F8F9FA',
  277. radius: [2, 4],
  278. },
  279. })
  280. // 绘制第二级
  281. let nowAtStr = moment().format('YYYY-MM-DD')
  282. let year = this.startAt.format('YYYY')
  283. this.timeZoneLineEls = []
  284. for (let i = 1; i < 19; i++) {
  285. let tempAt = moment(this.startAt)
  286. tempAt.add(i - 1, 'months')
  287. // console.log('tempAt:', tempAt.format('YYYY-MM-DD'))
  288. // 当月天数
  289. let daysCount = tempAt.dayOfYear()
  290. if (tempAt.format('YYYY') != year) {
  291. daysCount = parseInt(daysCount) + 365
  292. }
  293. let timeText = tempAt.format('MM')
  294. if (timeText == '01') {
  295. // 第一天,顶部需要绘制年月
  296. timeGroup.addShape('text', {
  297. attrs: {
  298. x: this.dayStep * daysCount + 100,
  299. y: 20,
  300. fontSize: 12,
  301. text: tempAt.format('YYYY'),
  302. lineDash: [10, 10],
  303. fill: '#8D9399',
  304. },
  305. })
  306. }
  307. let isToday = nowAtStr == tempAt.format('YYYY-MM-DD')
  308. if (isToday) {
  309. //是今日,需要画线
  310. // console.log('绘制 当日刻度线')
  311. this.todayTimeLineOffsetPos = this.dayStep * i
  312. timeGroup.addShape('rect', {
  313. attrs: {
  314. x: this.dayStep * i - 10,
  315. y: 25,
  316. width: 30,
  317. height: 16,
  318. fill: '#0091FF',
  319. radius: [2, 4],
  320. },
  321. })
  322. this.todayTimeLineEl = this.gCanvas.addShape('rect', {
  323. attrs: {
  324. x: this.todayTimeLineOffsetPos,
  325. y: 40,
  326. width: 4,
  327. height: this.cHeight,
  328. fill: '#CDE9FF',
  329. radius: [2, 4],
  330. },
  331. })
  332. // this.todayTimeLineEl.setZIndex(3)
  333. }
  334. // console.error('time:',tempAt.format('YYYY-MM'),', dayscount:', daysCount)
  335. // debugger
  336. timeGroup.addShape('text', {
  337. attrs: {
  338. x: this.dayStep * daysCount + 180 - 70,
  339. y: 40,
  340. fontSize: 10,
  341. text: timeText,
  342. lineDash: [10, 10],
  343. fill: '#8D9399',
  344. },
  345. })
  346. }
  347. }
  348. /**
  349. * 处理点击
  350. */
  351. GanttChartMonth.prototype.handleClick = function(task, flag, ev) {
  352. // let detailDiv = document.getElementById('detailDiv')
  353. if (flag == 'enter') {
  354. // detailDiv.style.display = 'block'
  355. // detailDiv.style.left = ev.clientX+'px';
  356. // detailDiv.style.top = ev.clientY+'px';
  357. // document.getElementById('detailTaskName').textContent = task._pdata.description
  358. // document.getElementById('detailTaskStatus').textContent = task._pdata.status
  359. // document.getElementById('detailTaskStartDate').textContent = task._pdata.startDate
  360. // document.getElementById('detailTaskEndDate').textContent = task._pdata.endDate
  361. // console.log('show:', task)
  362. } else if (flag === 'leave') {
  363. // detailDiv.style.display = 'none'
  364. // console.log('hide:', task)
  365. } else {
  366. this.callback(task)
  367. console.log('click:', task)
  368. }
  369. }
  370. /**
  371. * 根据任务状态区分颜色
  372. *
  373. */
  374. GanttChartMonth.prototype.statusColor = function(task) {
  375. switch (task.statusType) {
  376. case 1:
  377. return ['#E7E9EA', '#C3C7CB']
  378. case 2:
  379. return ['#FBCE99', '#F58300']
  380. case 3:
  381. return ['#FBB8B5', '#F54E45']
  382. default:
  383. return ['#FBB8B5', '#F54E45']
  384. }
  385. }
  386. /**
  387. * 判断任务是否在视图内
  388. *
  389. */
  390. GanttChartMonth.prototype.isInView = function(task) {
  391. let isLessThanEndAt = task.endDate <= this.startAt.format('YYYY-MM-DD')
  392. let isGreaterThanStartAt = task.startDate >= this.endAt.format('YYYY-MM-DD')
  393. if (task.startDate == task.endDate) {
  394. // console.error('任务宽度为0',task)
  395. return true
  396. }
  397. // console.log('isInView', `${task.startDate} -- ${task.endDate}`, this.startAt.format('YYYY-MM-DD'), this.endAt.format('YYYY-MM-DD'), (!(isLessThanEndAt || isGreaterThanStartAt)))
  398. return !(isLessThanEndAt || isGreaterThanStartAt)
  399. }
  400. /**
  401. * 绘制完成之后的回调,用于某些工具缺陷的hack写法
  402. */
  403. GanttChartMonth.prototype.postDrawTasksCallBack = function() {
  404. // 画当前线条 TODO,放前面不行
  405. if (true) {
  406. let todayAt = new Date()
  407. if (this.startAt < todayAt && this.endAt > todayAt) {
  408. let duraStartAt = new Date() - new Date(this.startAt.format('YYYY-MM-DD'))
  409. let secondsStartAt = duraStartAt / 1000
  410. this.todayTimeLineOffsetPos = secondsStartAt * this.timePerPix
  411. this.todayTimeLineEl = this.gCanvas.addShape('rect', {
  412. attrs: {
  413. x: this.todayTimeLineOffsetPos,
  414. y: 50,
  415. width: 4,
  416. height: this.cHeight,
  417. fill: '#CDE9FF',
  418. radius: [2, 4],
  419. },
  420. })
  421. this.todayTimeLineEl.setZIndex(30)
  422. }
  423. }
  424. if (true) {
  425. let year = this.startAt.format('YYYY')
  426. for (let i = 1; i < 19; i++) {
  427. let tempAt = moment(this.startAt)
  428. tempAt.add(i - 1, 'months')
  429. // 当月天数
  430. let daysCount = tempAt.dayOfYear()
  431. if (tempAt.format('YYYY') != year) {
  432. daysCount = parseInt(daysCount) + 365
  433. }
  434. daysCount = daysCount - 1
  435. // 当月天数
  436. // let daysCount = moment(`${year}-${i}`).dayOfYear()
  437. // console.log('timeline X:', this.dayStep * daysCount, daysCount, tempAt.format('YYYY-MM-DD'))
  438. let lineEl = this.timeGroupEl.addShape('rect', {
  439. attrs: {
  440. x: this.dayStep * daysCount,
  441. y: 20,
  442. width: 1,
  443. height: this.cHeight,
  444. fill: '#deebeb',
  445. radius: [2, 4],
  446. },
  447. })
  448. lineEl.setZIndex(30)
  449. }
  450. }
  451. }
  452. /**
  453. * 分组绘制任务块
  454. *
  455. */
  456. GanttChartMonth.prototype.drawTasks = function() {
  457. this.graphGroup = this.gCanvas.addGroup()
  458. this.graphGroup._tname = 'graphGroup'
  459. // 第一层循环,用于分组,例如,维保--xxxx
  460. this.tasks.forEach((topTask, topIndex) => {
  461. try {
  462. if (topTask.open) {
  463. let taskGroup = null
  464. taskGroup = this.graphGroup.addGroup()
  465. taskGroup._tname = 'TaskGroup_' + topTask.id
  466. topTask.gGroup = taskGroup
  467. if (false) {
  468. // 组名背景矩形
  469. let TopGroupRectEl = taskGroup.addShape('rect', {
  470. attrs: {
  471. x: 0,
  472. y: topTask.renderOptions.startY,
  473. width: this.cWidth,
  474. height: this.taskRowHeight,
  475. fill: '#F5F6F7',
  476. radius: [2, 4],
  477. },
  478. })
  479. TopGroupRectEl.setZIndex(-1)
  480. }
  481. // 第二层循环,用于 区分具体多少任务,例如,维保-商管1/商管2...
  482. topTask.dataList.forEach((taskP, index) => {
  483. let taskPGroup = taskGroup.addGroup()
  484. taskGroup.addGroup(taskPGroup)
  485. // 任务背景矩形,主要用于Hover效果变更颜色
  486. if (false) {
  487. let tempTaskContainerEl = taskPGroup.addShape('rect', {
  488. attrs: {
  489. x: 0,
  490. y: topTask.renderOptions.startY + (index + 1) * (this.taskRowHeight + this.rowSpanDis) - 5,
  491. width: this.cWidth,
  492. height: this.taskRowHeight + 10,
  493. fill: '#fff',
  494. // stroke: 'black',
  495. radius: [2, 4],
  496. },
  497. })
  498. tempTaskContainerEl.setZIndex(1)
  499. tempTaskContainerEl._pdata = taskP
  500. tempTaskContainerEl.on('mouseenter', (ev) => {
  501. if (taskP.parentNode.open) {
  502. tempTaskContainerEl.attr({ fill: '#F5F6F7' })
  503. tempTaskContainerEl._pdata.tasks.forEach((_tempTask) => {
  504. if (_tempTask._rectEl) {
  505. _tempTask._rectEl.setZIndex(5)
  506. }
  507. })
  508. }
  509. })
  510. tempTaskContainerEl.on('mouseleave', (ev) => {
  511. if (taskP.parentNode.open) {
  512. tempTaskContainerEl.attr({ fill: '#fff' })
  513. tempTaskContainerEl._pdata.tasks.forEach((_tempTask) => {
  514. if (_tempTask._rectEl) {
  515. _tempTask._rectEl.setZIndex(5)
  516. }
  517. })
  518. }
  519. })
  520. taskP._containerEl = tempTaskContainerEl
  521. }
  522. // 第三层循环,用户区分每个子任务的执行时间段,例如:维保-商管1-2020.05-2020.06 / 2020.08- 2020.09
  523. taskP.tasks.forEach((_taskItem, _index) => {
  524. let _isInView = this.isInView(_taskItem)
  525. // 在视图中才显示
  526. if (_isInView) {
  527. let pos = this.calRectPos(_taskItem)
  528. // console.log('render rect:', _taskItem, pos, topTask.renderOptions.startY + index * taskRowHeight);
  529. let rectEl = taskPGroup.addShape('rect', {
  530. attrs: {
  531. x: pos.x,
  532. y: topTask.renderOptions.startY + (index + 1) * (this.taskRowHeight + this.rowSpanDis),
  533. width: pos.width,
  534. height: this.taskRowHeight,
  535. fill: this.statusColor(_taskItem)[0],
  536. stroke: this.statusColor(_taskItem)[1],
  537. radius: [2, 4],
  538. },
  539. })
  540. rectEl.setZIndex(300)
  541. rectEl._pdata = _taskItem
  542. _taskItem._rectEl = rectEl
  543. rectEl.on('mouseover', (ev) => {
  544. document.querySelector('#ganttContainer>canvas').style.cursor = 'pointer';
  545. // this.handleClick(ev.target, 'enter', ev)
  546. })
  547. rectEl.on('mouseleave', (ev) => {
  548. document.querySelector('#ganttContainer>canvas').style.cursor = 'default';
  549. // this.handleClick(ev.target, 'leave', ev)
  550. })
  551. rectEl.on('click', (ev) => {
  552. this.handleClick(ev.target, 'click', ev)
  553. })
  554. }
  555. })
  556. })
  557. taskGroup.show()
  558. } else {
  559. if (topTask.gGroup) {
  560. // topTask.gGroup.hide()
  561. topTask.gGroup = null
  562. }
  563. }
  564. } catch (error) {
  565. console.error('drawTasks error:', error)
  566. }
  567. })
  568. this.postDrawTasksCallBack()
  569. if(true){
  570. if(this.hoverEl==null){
  571. let hoverEl = this.gCanvas.addShape('rect', {
  572. attrs: {
  573. x: 0,
  574. y: 0,
  575. width: this.cWidth,
  576. height: this.taskRowHeight + 10,
  577. fill: '#F5F6F7',
  578. // stroke: 'black',
  579. radius: [2, 4],
  580. },
  581. })
  582. hoverEl.setZIndex(-5)
  583. this.hoverEl = hoverEl
  584. }
  585. }
  586. }
  587. /**
  588. * 根据 Task 计算矩形位置
  589. *
  590. */
  591. GanttChartMonth.prototype.calRectPos = function(taskItem) {
  592. // if(taskItem.id == 2833812){
  593. // taskItem.startDate = '2020-09-01 00:00:00'
  594. // taskItem.endDate = '2020-09-30 00:00:00'
  595. // }
  596. // console.log('start=====', _moment(taskItem.startDate).format('YYYY-MM-DD HH:mm:ss'), '---', _moment(taskItem.endDate).format('YYYY-MM-DD HH:mm:ss') )
  597. // debugger
  598. let s1 = new Date(taskItem.startDate)
  599. let s2 = new Date(this.startAt.format('YYYY-MM-DD 00:00:00'))
  600. let duraStartAt = new Date(taskItem.startDate) - new Date(this.startAt.format('YYYY-MM-DD 00:00:00'))
  601. // duraStartAt=duraStartAt-3600*24*1000
  602. // console.log('s1:', s1, ',s2:',s2, ',s1-s2:',s1-s2,',days:', (duraStartAt/(24*3600*1000)), ',offset:', duraStartAt / 1000 * this.timePerPix)
  603. // duraStartAt = duraStartAt - (24*3600*3)
  604. let secondsStartAt = duraStartAt / 1000
  605. let duraEndAt = new Date(taskItem.endDate) - new Date(taskItem.startDate)
  606. let secondsEndAt = duraEndAt / 1000
  607. // let secondsEndAt = (duraEndAt - 3600*24*1000) / 1000
  608. // console.log('secondsEndAt', secondsEndAt)
  609. let width = secondsEndAt * this.timePerPix
  610. if (width < this.minTaskRectWidth) {
  611. width = this.minTaskRectWidth
  612. }
  613. // console.error('task rect width:', width)
  614. return {
  615. x: secondsStartAt * this.timePerPix,
  616. y: 0,
  617. width: width,
  618. height: 0,
  619. }
  620. }
  621. /**
  622. * 主函数
  623. *
  624. */
  625. GanttChartMonth.prototype.main = function() {
  626. this.initDrawingReady()
  627. }