UNPKG

gantt-source_management

Version:

Gantt, Schedule,

25 lines 18.1 kB
/** * TimelinePointer plugin * * @copyright NEURONET - Rafal Pospiech * @author Rafal Pospiech <neuronet.io@gmail.com> * @module gantt-schedule-timeline-calendar * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar * @link https://gantt-schedule-timeline-calendar.neuronet.io * @version 3.37.5 * @released 2024-07-19 * @license SEE LICENSE IN LICENSE FILE */ const t="chart-timeline-items-row-item"; /** * ItemMovement plugin * * @copyright NEURONET - Rafal Pospiech * @author Rafal Pospiech <neuronet.io@gmail.com> * @module gantt-schedule-timeline-calendar * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar * @link https://gantt-schedule-timeline-calendar.neuronet.io * @version 3.37.5 * @released 2024-07-19 * @license SEE LICENSE IN LICENSE FILE */const e="config.plugin.ItemMovement";class i{constructor(t,e){this.onDestroy=[],this.scrollWaiting=0,this.vido=t,this.state=t.state,this.api=t.api,this.data=function(t={}){const e={onStart:({items:t})=>t.after,onMove:({items:t})=>t.after,onEnd:({items:t})=>t.after},i={start:({startTime:t,time:e,vido:i})=>i.api.time.findOrCreateMainDateAtTime(t.valueOf(),e).leftGlobalDate,end:({endTime:t})=>t},a={speed:{horizontal:1,vertical:1},edgeThreshold:{horizontal:60,vertical:0}},s=Object.assign({enabled:!0,dependant:!0,moveDependantVertically:!1,addedDependantIds:[],selectedIds:[],debug:!1,state:"",bodyClass:"gstc-items-moving",itemClass:"",movement:{x:0,y:0,time:0},threshold:{horizontal:10,vertical:10},initialItems:[],initialItemsData:{},clickedItem:null,clickedItemData:null,initialVerticalScroll:null,initialHorizontalScroll:null,initialPointerTime:null,isMoving:!1,events:Object.assign({},e),snapToTime:Object.assign({},i),autoScroll:Object.assign({},a),ignoreMissingDates:!0,allowItemsToGoOutsideTheArea:!0,thresholdReached:{horizontal:!1,vertical:!1},shouldMuteNotNeededMethods:!0},t);return t.snapToTime&&(s.snapToTime=Object.assign(Object.assign({},i),t.snapToTime)),t.events&&(s.events=Object.assign(Object.assign({},e),t.events)),t.autoScroll&&(s.autoScroll=Object.assign(Object.assign({},a),t.autoScroll),t.autoScroll.edgeThreshold&&(s.autoScroll.edgeThreshold=Object.assign(Object.assign({},a.edgeThreshold),t.autoScroll.edgeThreshold)),t.autoScroll.speed&&(s.autoScroll.speed=Object.assign(Object.assign({},a.speed),t.autoScroll.speed))),s}(e),this.data.itemClass||(this.data.itemClass=this.api.getClass("timeline-chart-items-row-item")+"--moving"),this.destroy=this.destroy.bind(this),this.itemUpdateAction=this.itemUpdateAction.bind(this),this.onDestroy.push(this.state.subscribe("$data.elements.chart-timeline",(t=>this.timelineElement=t))),this.updateData(),this.onDestroy.push(this.state.subscribe("config.plugin.ItemMovement",(t=>{t.enabled&&t.isMoving?document.body.classList.add(t.bodyClass):document.body.classList.remove(t.bodyClass),this.data=t}))),this.onPointerMove=this.onPointerMove.bind(this),this.onPointerUp=this.onPointerUp.bind(this),this.onTimelinePointerDown=this.onTimelinePointerDown.bind(this),this.onTimelinePointerMove=this.onTimelinePointerMove.bind(this),this.onTimelinePointerUp=this.onTimelinePointerUp.bind(this),this.api.plugins.TimelinePointer.addPointerListener("move",this.onTimelinePointerMove),this.api.plugins.TimelinePointer.addPointerListener("down",this.onTimelinePointerDown),this.api.plugins.TimelinePointer.addPointerListener("up",this.onTimelinePointerUp)}destroy(){this.onDestroy.forEach((t=>t())),this.api.plugins.TimelinePointer.removePointerListener("move",this.onTimelinePointerMove),this.api.plugins.TimelinePointer.removePointerListener("down",this.onTimelinePointerDown),this.api.plugins.TimelinePointer.removePointerListener("up",this.onTimelinePointerUp),this.api.pluginDestroyed("ItemMovement")}updateData(){this.state.update(e,this.data)}getSelectedItems(e=!1){return this.state.get(`config.plugin.Selection.selected.${t}`).map((t=>{let i=this.api.getItem(t);if(e)for(const e of this.data.initialItems)if(e.id===t){i=e;break}return this.api.mergeDeep({},i)}))}getSelectedItemsData(t){const e={};for(const i of t)e[i.id]=this.api.mergeDeep({},this.api.getItemData(i.id));return e}getEventArgument(t,e){const i=this.api.getAllItems(),a=[];for(const e of t)a.push(this.api.mergeDeep({},i[e.id]));return{items:{initial:this.data.initialItems,before:a,after:t,targetData:e.targetData},addedDependantIds:this.data.addedDependantIds,selectedIds:this.data.selectedIds,vido:this.vido,state:this.state,time:this.state.get("$data.chart.time")}}getDependantItems(t,e){const i=[],a=this.api.getItemsData();for(const e of t)for(const t of a[e.id].dependant)i.includes(t)||i.push(t);const s=this.state.get("config.chart.items");let o;return o=e?i.map((t=>this.data.initialItems.find((e=>e.id===t)))):i.map((t=>s[t])),o.map((t=>this.api.mergeDeep({},t)))}dispatchEvent(t,e,i,a=null){"onStart"===t&&this.data.shouldMuteNotNeededMethods&&(this.api.muteMethod("fixOverlapped"),this.api.muteMethod("fullReload"),this.api.muteMethod("measureRows"),this.api.muteMethod("getLastPageRowsHeight"),this.api.muteMethod("calculateVerticalScrollArea"),this.api.muteMethod("heightChange"),this.api.muteMethod("calculateRowsHeight"),this.api.muteMethod("calculateVisibleRowsHeights"),this.api.muteMethod("updateVisibleItemsListener"),this.api.muteMethod("prepareExpanded"),0===this.data.autoScroll.speed.horizontal&&0===this.data.autoScroll.speed.vertical&&(this.api.muteMethod("generateVisibleRowsAndItems"),this.api.muteMethod("prepareExpanded"))),"onEnd"===t&&this.data.shouldMuteNotNeededMethods&&(this.api.unmuteMethod("fixOverlapped"),this.api.unmuteMethod("heightChange"),this.api.unmuteMethod("calculateVerticalScrollArea"),this.api.unmuteMethod("getLastPageRowsHeight"),this.api.unmuteMethod("fullReload"),this.api.unmuteMethod("measureRows"),this.api.unmuteMethod("calculateRowsHeight"),this.api.unmuteMethod("calculateVisibleRowsHeights"),this.api.unmuteMethod("updateVisibleItemsListener"),this.api.unmuteMethod("prepareExpanded"),0===this.data.autoScroll.speed.horizontal&&0===this.data.autoScroll.speed.vertical&&(this.api.unmuteMethod("generateVisibleRowsAndItems"),this.api.unmuteMethod("prepareExpanded"))),e=e.map((t=>this.api.mergeDeep({},t)));const s=this.data.events[t](this.getEventArgument(e,i));let o=this.state.multi(!0);const l=this.state.get("config.chart.items");for(let t of s){t=this.api.mergeDeep({},t);const e=l[t.id];let i=!1;t.time.start===e.time.start&&t.time.end===e.time.end||(i=!0,o=o.update(`config.chart.items.${t.id}.time`,Object.assign({},t.time)));let s=!1;e.rowId!==t.rowId&&(s=!0,o=o.update(`config.chart.items.${t.id}.rowId`,t.rowId),this.api.updateItemRowMapForItem(t.id,t.rowId)),a&&(i||s)&&(o=o.update(`$data.chart.items.${t.id}`,this.api.mergeDeep({},a[t.id])))}o.done(),"onEnd"===t&&this.api.main.partialReload(!1)}getItemsForDiff(){const t=this.getSelectedItems()[0],e=this.data.initialItems.find((e=>e.id===t.id));return{modified:t,original:e}}onTimelinePointerDown(e){this.data.enabled&&(e.targetType!==t||this.api.plugins.TimelinePointer.isLocked("down")||this.onPointerDown(e))}onTimelinePointerMove(e){this.data.enabled&&e.targetType===t&&"item-movement"===this.api.plugins.TimelinePointer.isLocked("move")&&this.onPointerMove(e)}onTimelinePointerUp(e){this.data.enabled&&e.targetType===t&&"item-movement"===this.api.plugins.TimelinePointer.isLocked("up")&&this.onPointerUp(e)}onPointerDown(t){if(document.body.classList.add(this.data.bodyClass),this.api.plugins.TimelinePointer.lock("down","item-movement"),this.api.plugins.TimelinePointer.lock("move","item-movement"),this.api.plugins.TimelinePointer.lock("up","item-movement"),this.data.isMoving=!0,this.data.dependant){const t=this.getSelectedItems();this.data.selectedIds=t.map((t=>t.id));const e=this.getDependantItems(t,!1).filter((t=>!this.data.selectedIds.includes(t.id)));this.data.addedDependantIds=e.map((t=>t.id)),this.data.initialItems=[...t,...e]}else this.data.addedDependantIds=[],this.data.initialItems=this.getSelectedItems(),this.data.selectedIds=this.data.initialItems.map((t=>t.id));this.data.initialItemsData=this.getSelectedItemsData(this.data.initialItems),this.data.clickedItem=this.api.mergeDeep({},t.targetData),this.data.clickedItemData=this.api.mergeDeep({},this.api.getItemData(this.data.clickedItem.id)),this.data.initialVerticalScroll=this.api.mergeDeep({},this.state.get("$data.scroll.vertical")),this.data.initialHorizontalScroll=this.api.mergeDeep({},this.state.get("$data.scroll.horizontal")),this.data.initialPointerTime=this.api.time.date(this.api.time.getTimeFromOffsetPx(t.initialPosition.x,!0)),this.scrollWaiting=0,this.data.thresholdReached.horizontal=!1,this.data.thresholdReached.vertical=!1,""!==this.data.state&&"end"!==this.data.state||(this.data.state="move"),this.dispatchEvent("onStart",this.data.initialItems,t),this.updateData()}scrollLeft(){if(!this.data.autoScroll.speed.horizontal)return;if(this.state.get("config.chart.time.calculatedZoomMode"))return;this.scrollWaiting++;const t=this.state.get("config.scroll.horizontal");if(this.data.autoScroll.speed.horizontal<0){if(this.scrollWaiting-1<Math.abs(this.data.autoScroll.speed.horizontal))return;const e=this.api.getScrollLeft();t.byPixels?this.api.setScrollLeft(e.absolutePosPx-120*t.multiplier):this.api.setScrollLeft(e.dataIndex-1)}else if(this.data.autoScroll.speed.horizontal>0){const e=this.api.getScrollLeft();t.byPixels?this.api.setScrollLeft(e.absolutePosPx-120*this.data.autoScroll.speed.horizontal*t.multiplier):this.api.setScrollLeft(e.dataIndex-this.data.autoScroll.speed.horizontal)}this.scrollWaiting=0}scrollRight(){if(!this.data.autoScroll.speed.horizontal)return;if(this.state.get("config.chart.time.calculatedZoomMode"))return;this.scrollWaiting++;const t=this.state.get("config.scroll.horizontal");if(this.data.autoScroll.speed.horizontal<0){if(this.scrollWaiting-1<Math.abs(this.data.autoScroll.speed.horizontal))return;const e=this.api.getScrollLeft();t.byPixels?this.api.setScrollLeft(e.absolutePosPx+120*t.multiplier):this.api.setScrollLeft(e.dataIndex+1)}else if(this.data.autoScroll.speed.horizontal>0){const e=this.api.getScrollLeft();t.byPixels?this.api.setScrollLeft(e.absolutePosPx+120*this.data.autoScroll.speed.horizontal*t.multiplier):this.api.setScrollLeft(e.dataIndex+this.data.autoScroll.speed.horizontal)}this.scrollWaiting=0}scrollTop(){if(this.data.autoScroll.speed.vertical){if(this.scrollWaiting++,this.data.autoScroll.speed.vertical<0){if(this.scrollWaiting-1<Math.abs(this.data.autoScroll.speed.vertical))return;const t=this.api.getScrollTop(),e=this.state.get("config.scroll.vertical");e.byPixels?this.api.setScrollTop(t.absolutePosPx-120*e.multiplier):this.api.setScrollTop(t.dataIndex-1)}else if(this.data.autoScroll.speed.vertical>0){const t=this.api.getScrollTop(),e=this.state.get("config.scroll.vertical");e.byPixels?this.api.setScrollTop(t.absolutePosPx-120*this.data.autoScroll.speed.vertical*e.multiplier):this.api.setScrollTop(t.dataIndex-this.data.autoScroll.speed.vertical)}this.scrollWaiting=0}}scrollBottom(){if(this.data.autoScroll.speed.vertical){if(this.scrollWaiting++,this.data.autoScroll.speed.vertical<0){if(this.scrollWaiting-1<Math.abs(this.data.autoScroll.speed.vertical))return;const t=this.api.getScrollTop(),e=this.state.get("config.scroll.vertical");e.byPixels?this.api.setScrollTop(t.absolutePosPx-120*e.multiplier):this.api.setScrollTop(t.dataIndex+1)}else if(this.data.autoScroll.speed.vertical>0){const t=this.api.getScrollTop(),e=this.state.get("config.scroll.vertical");e.byPixels?this.api.setScrollTop(t.absolutePosPx+120*this.data.autoScroll.speed.vertical*e.multiplier):this.api.setScrollTop(t.dataIndex+this.data.autoScroll.speed.vertical)}this.scrollWaiting=0}}autoScroll(t){if(!this.timelineElement)return;const e=t.currentPosition.x,i=t.currentPosition.y,a=this.state.get("$data.chart.dimensions");e<this.data.autoScroll.edgeThreshold.horizontal?this.scrollLeft():e>a.widthWithoutScrollBar-this.data.autoScroll.edgeThreshold.horizontal?this.scrollRight():i<this.data.autoScroll.edgeThreshold.vertical?this.scrollTop():i>a.innerHeight-this.data.autoScroll.edgeThreshold.vertical&&this.scrollBottom()}moveItemVertically(t,e,i){if(this.data.addedDependantIds.includes(t.id)&&!this.data.moveDependantVertically)return;const a=this.state.get("$data.scroll.vertical").absolutePosPx-this.data.initialVerticalScroll.absolutePosPx,s=i.currentPosition.y-i.initialPosition.y,o=this.data.threshold.vertical;if(Math.abs(s)>=o&&(this.data.thresholdReached.vertical=!0),!this.data.thresholdReached.vertical)return;const l=this.data.clickedItemData.position.viewTop-i.initialPosition.y-this.data.clickedItemData.position.rowTop;let n=e.position.top+s+a-l;n<0&&(n=0);const d=this.api.getRowInfoFromTop(n);d.row.id!==t.rowId&&(t.rowId=d.row.id,e.position.viewTop=this.api.getRowViewTop(t.rowId),e.position.rowTop=0)}getItemsToMove(t=!1){let e,i=[];if(this.data.dependant){const a=this.getSelectedItems(t),s=a.map((t=>t.id)),o=this.getDependantItems(a,t).filter((t=>!s.includes(t.id)));i=o.map((t=>t.id)),e=[...a,...o]}else e=this.getSelectedItems(t);return{itemsToMove:e,dependantIds:i}}calculateFinalLeftGlobal({diffPx:t,initialItemData:e,initialItem:i,isDependant:a,movement:s,itemDataToSave:o,time:l}){const n=e.position.left+t;let d=this.api.time.getTimeFromOffsetPx(n,!0,l);if(a){const t=this.data.initialItems.find((t=>{var e;return null===(e=t.dependant)||void 0===e?void 0:e.includes(i.id)})),a=this.data.initialItemsData[t.id],s=o[a.id],n=this.api.time.getDatesDiffMs(a.time.endDate,s.time.endDate,l,!0);let h=-this.api.time.getDSTDiffForLevel(l.level,a.time.endDate.valueOf(),e.time.startDate.valueOf(),l);d=this.api.time.addTimeFromDates(e.time.startDate.valueOf(),n+h,l),h=this.api.time.getDSTDiffForLevel(l.level,s.time.endDate.valueOf(),d,l),d+=h}const h=this.api.time.date(d);let r=h;return a||(r=this.data.snapToTime.start({startTime:h,item:i,time:l,movement:s,vido:this.vido})),r}calculateFinalRightGlobal({finalLeftGlobalDate:t,initialItemData:e,initialItem:i,isDependant:a,movement:s,time:o}){const l=this.api.time.getViewOffsetPxFromDates(t,!1,o);let n=-this.api.time.getDSTDiffForLevel(o.level,i.time.start,i.time.end,o);const d=l+e.timeWidth;let h;const r=i.time.end-i.time.start;h=this.data.ignoreMissingDates?this.api.time.date(this.api.time.getTimeFromOffsetPx(d,!0,o)):this.api.time.date(t.valueOf()+r),n+=this.api.time.getDSTDiffForLevel(o.level,t.valueOf(),h.valueOf(),o),h=h.add(n,"ms");let m=h;return a||(m=this.data.snapToTime.end({endTime:h,item:i,time:o,movement:s,vido:this.vido})),m}onPointerMove(t){if(!this.data.enabled)return;if(!this.data.isMoving)return;const{original:e,modified:i}=this.getItemsForDiff();if(!e)return;const a=this.data.movement=Object.assign(Object.assign({},t.movement),{time:i.time.start-e.time.start}),s=this.data.threshold.horizontal,o=this.data.threshold.vertical;if(this.data.thresholdReached.horizontal=this.data.thresholdReached.horizontal||Math.abs(a.x)>=s,this.data.thresholdReached.vertical=this.data.thresholdReached.vertical||Math.abs(a.y)>=o,!this.data.thresholdReached.horizontal&&!this.data.thresholdReached.vertical)return;"move"!==this.data.state&&"start"!==this.data.state||(this.data.state="move");const{itemsToMove:l,dependantIds:n}=this.getItemsToMove(!0),d={},h=this.state.get("$data.chart.time"),r=[],m=this.data.snapToTime.start({startTime:this.data.initialPointerTime,item:null,time:h,movement:a,vido:this.vido}),c=this.state.get("$data.scroll.horizontal"),p=this.api.time.getDatesDiffPx(c.data.leftGlobalDate.subtract(c.preciseOffset*h.timePerPixel,"ms"),this.data.initialHorizontalScroll.data.leftGlobalDate.subtract(this.data.initialHorizontalScroll.preciseOffset*h.timePerPixel,"ms"),h,!0),u=this.api.time.date(this.api.time.getTimeFromOffsetPx(t.currentPosition.x+p,!0,h)),g=this.api.time.getDatesDiffPx(m,u,h,!0);for(let e=0,i=l.length;e<i;e++){const i=this.api.mergeDeep({},l[e]),s=this.api.mergeDeep({},this.data.initialItemsData[i.id]),o=n.includes(i.id);if(this.moveItemVertically(i,s,t),this.data.thresholdReached.horizontal){const t=this.calculateFinalLeftGlobal({diffPx:g,initialItemData:s,initialItem:i,isDependant:o,movement:a,itemDataToSave:d,time:h}),e=this.calculateFinalRightGlobal({finalLeftGlobalDate:t,initialItemData:s,initialItem:i,isDependant:o,movement:a,time:h});if(!(t.valueOf()<h.from||e.valueOf()>h.to)||"function"!=typeof h.format.periodIncrement&&this.data.allowItemsToGoOutsideTheArea)i.time.start=t.valueOf(),i.time.end=e.valueOf(),s.time.startDate=t,s.time.endDate=e;else{const t=this.api.getItem(i.id);i.time.start=t.time.start,i.time.end=t.time.end,s.time.startDate=this.api.time.date(i.time.start),s.time.endDate=this.api.time.date(i.time.end)}}d[i.id]=s,r.push(i)}(this.data.thresholdReached.horizontal||this.data.thresholdReached.vertical)&&this.dispatchEvent("onMove",r,t,d),g&&(this.data.thresholdReached.horizontal||this.data.thresholdReached.vertical)&&this.autoScroll(t),this.updateData()}onEnd(t){const{itemsToMove:e}=this.getItemsToMove(!1);this.dispatchEvent("onEnd",e,t)}onPointerUp(t){document.body.classList.remove(this.data.bodyClass),this.data.enabled&&this.data.isMoving&&("move"===this.data.state&&(this.data.state="end"),this.data.isMoving=!1,this.onEnd(t),this.updateData(),this.api.plugins.TimelinePointer.unlock("down"),this.api.plugins.TimelinePointer.unlock("move"),this.api.plugins.TimelinePointer.unlock("up"))}itemUpdateAction(t,e){this.data.initialItems.find((t=>t.id===e.item.id))&&this.data.isMoving?t.classList.add(this.data.itemClass):t.classList.remove(this.data.itemClass)}}function a(t={}){return function(a){const s=a.api;if(!s.isPluginInitialized("TimelinePointer"))throw new Error("TimelinePointer plugin must be initialized before ItemMovement plugin.");if(!s.isPluginInitialized("Selection"))throw new Error("Selection plugin must be initialized before ItemMovement plugin.");const o=a.state.get(e);o&&(t=a.api.mergeDeep({},t,o));const l=new i(a,t);return s.pluginInitialized("ItemMovement"),l.destroy}}export{a as Plugin};