Renamed prefixes in angular.json
All checks were successful
FarmMaps.Develop/FarmMapsLib/develop This commit looks good
All checks were successful
FarmMaps.Develop/FarmMapsLib/develop This commit looks good
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
.timespan {
|
||||
width:100%;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
height:0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
position: relative;
|
||||
height: 6rem;
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeline canvas {
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.control-container {
|
||||
position: absolute;
|
||||
top:0px;
|
||||
width:100%;
|
||||
overflow: hidden;
|
||||
font-size: 0;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leftGrip,.rightGrip,.range {
|
||||
pointer-events: all;
|
||||
display: inline-block;
|
||||
height:100%;
|
||||
/* float: left; */
|
||||
font-size: 9pt;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.range {
|
||||
/* height:100%; */
|
||||
}
|
||||
|
||||
.leftGrip,.rightGrip {
|
||||
width:15px;
|
||||
background-color: rgb(204, 200, 200);
|
||||
border:1px solid black;
|
||||
}
|
||||
|
||||
.rightGrip {
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.leftGrip {
|
||||
left: -100px;
|
||||
cursor:w-resize;
|
||||
}
|
||||
|
||||
.range {
|
||||
/* background: linear-gradient( rgba(0, 140, 255, 0.856),transparent); */
|
||||
background-color:rgba(0, 140, 255, 0.856);
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.popover-anchor {
|
||||
position:absolute;
|
||||
top:2rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
<div class="timespan p-1" (window:resize)="handleResize($event)">
|
||||
<div (click)="handleClick()">{{caption}}</div>
|
||||
<ng-template #popoverContent let-caption="popoverCaption">{{caption}}</ng-template>
|
||||
<div class="popover-anchor" [style.left.px] = "startPopoverLeft" [ngbPopover]="popoverContent" #popoverStart="ngbPopover"> </div>
|
||||
<div class="popover-anchor" [style.left.px] = "endPopoverLeft" [ngbPopover]="popoverContent" #popoverEnd="ngbPopover"> </div>
|
||||
<div class="collapsed clearfix" [ngClass]="{'collapsed':collapsed}">
|
||||
<!-- <div class="clearfix">
|
||||
<select class="form-control float-right" [value]="unitScale">
|
||||
<option value="0">Millisecond</option>
|
||||
<option value="1">Second</option>
|
||||
<option value="2">Minute</option>
|
||||
<option value="3">Hour</option>
|
||||
<option value="4">Day</option>
|
||||
<option value="5">Week</option>
|
||||
<option value="6">Month</option>
|
||||
<option value="6">Quarter</option>
|
||||
<option value="8">Year</option>
|
||||
</select>
|
||||
</div> -->
|
||||
<div class="timeline" (window:mousemove)="handleMouseMove($event)" (window:touchmove)="handleMouseMove($event)" (window:mouseup)="handleMouseUp($event)" (window:touchend)="handleMouseUp($event)" (wheel)="handleMouseWheel($event)" [style.height.px]="height">
|
||||
<canvas #timeLine (mousedown)="handleViewPanMouseDown($event)" (touchstart)="handleViewPanMouseDown($event)" (mousemove)="handleCanvasMouseMove($event)" (mouseleave)="handleCanvasMouseLeave($event)">
|
||||
</canvas>
|
||||
<div class="control-container" [style.margin-left.px]="marginLeft" [style.height.px]="lineHeight" >
|
||||
<div class="leftGrip rounded-left" (mousedown)="handleLeftGripMouseDown($event)" (touchstart)="handleLeftGripMouseDown($event)" (mouseenter)="handleLeftGripMouseEnter($event)" (mouseleave)="handleLeftGripMouseLeave($event)"><i class="fa fa-ellipsis-v" aria-hidden="true"></i></div>
|
||||
<div class="range" [style.width.px]="rangeWidth" (mousedown)="handleRangeGripMouseDown($event)" (touchstart)="handleRangeGripMouseDown($event)" (mouseenter)="handleRangeGripMouseEnter($event)"></div>
|
||||
<div class="rightGrip rounded-right" (mousedown)="handleRightGripMouseDown($event)" (touchstart)="handleRightGripMouseDown($event)" (mouseenter)="handleRightGripMouseEnter($event)" (mouseleave)="handleRightGripMouseLeave($event)"><i class="fa fa-ellipsis-v" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div>
|
||||
<div class="btn btn-primary" (click)="handleZoomIn()">+</div>
|
||||
<div class="btn btn-primary" (click)="handleZoomOut()">-</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
583
projects/common/src/fm/components/timespan/timespan.component.ts
Normal file
583
projects/common/src/fm/components/timespan/timespan.component.ts
Normal file
@@ -0,0 +1,583 @@
|
||||
import { Component, OnInit,Input,ViewChild,OnChanges,ChangeDetectorRef,Output, EventEmitter,SimpleChanges } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
export interface TimeSpan {
|
||||
startDate:Date;
|
||||
endDate:Date;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'fm-timespan',
|
||||
templateUrl: './timespan.component.html',
|
||||
styleUrls: ['./timespan.component.css']
|
||||
})
|
||||
export class TimespanComponent implements OnInit, OnChanges {
|
||||
|
||||
scale:number = 1000 * 60 * 60 ; // milliseconds / pixel ( 1 hour )
|
||||
unitScales:number[] = [1,1000,1000*60,1000*60*60,1000*60*60*24,1000*60*60*24*7,1000*60*60*24*31,1000*60*60*24*31*3,1000*60*60*24*365.25];
|
||||
units:string[] = [ 'millisecond','second','minute','hour','day','week','month','quarter','year'];
|
||||
quarters:string[] = ['KW1','KW2','KW3','KW4'];
|
||||
unitScale:number = 3;
|
||||
viewMinDate:Date;
|
||||
viewMaxDate:Date;
|
||||
extentMinDate:Date;
|
||||
extentMaxDate:Date;
|
||||
cursorDate:Date;
|
||||
leftGripMove:boolean = false;
|
||||
rightGripMove:boolean = false;
|
||||
rangeGripMove:boolean = false;
|
||||
viewPan:boolean = false;
|
||||
downX:number = -1;
|
||||
mouseX: number = -1;
|
||||
mouseY: number = -1;
|
||||
elementWidth:number;
|
||||
elementHeight:number;
|
||||
lastOffsetInPixels:number=0;
|
||||
@ViewChild('timeLine') canvasRef;
|
||||
@ViewChild('popoverStart') public popoverStart:NgbPopover;
|
||||
@ViewChild('popoverEnd') public popoverEnd:NgbPopover;
|
||||
@Input() collapsed: boolean = true;
|
||||
@Input() startDate: Date = new Date(2018,1,3);
|
||||
@Input() endDate: Date = new Date(2018,1,5);
|
||||
@Input() unit:string;
|
||||
@Input() color:string = '#000000';
|
||||
@Input() background:string = '#ffffff';
|
||||
@Input() hoverColor:string ='#ffffff';
|
||||
@Input() hoverBackground:string ='#0000ff';
|
||||
@Input() lineColor:string='#000000';
|
||||
@Input() lineWidth:number=1;
|
||||
@Input() padding:number = 4;
|
||||
@Output() change:EventEmitter<TimeSpan> = new EventEmitter();
|
||||
public caption:string = "2016/2017";
|
||||
public marginLeft:number = 100;
|
||||
public startPopoverLeft:number=110;
|
||||
public endPopoverLeft:number=120;
|
||||
public rangeWidth:number =75;
|
||||
public startCaption={};
|
||||
public endCaption={};
|
||||
private ratio:number=1;
|
||||
private initialized:boolean=false;
|
||||
private ctx:CanvasRenderingContext2D;
|
||||
public posibleUnits:number[] = [];
|
||||
public height:number = 0;
|
||||
public lineHeight:number = 0;
|
||||
|
||||
constructor(private changeDetectorRef: ChangeDetectorRef,private datePipe: DatePipe) { }
|
||||
|
||||
setCanvasSize() {
|
||||
let canvas = this.canvasRef.nativeElement;
|
||||
this.elementWidth = canvas.offsetWidth;
|
||||
this.elementHeight = canvas.offsetHeight;
|
||||
canvas.height = this.elementHeight * this.ratio;
|
||||
canvas.width = this.elementWidth * this.ratio;
|
||||
}
|
||||
|
||||
getPosibleUnits(scale:number):number[] {
|
||||
let posibleUnits = [];
|
||||
for(let u of [3,4,6,8]) {
|
||||
if((this.unitScale <=u) )
|
||||
posibleUnits.push(u);
|
||||
}
|
||||
return posibleUnits;
|
||||
}
|
||||
|
||||
getLineHeight():number {
|
||||
return (parseInt(this.ctx.font.match(/\d+/)[0], 10)/ this.ratio) + (2*this.padding) ;
|
||||
}
|
||||
|
||||
getHeight():number {
|
||||
|
||||
return (this.posibleUnits.length * this.getLineHeight());
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.ratio = 2;
|
||||
this.unitScale = this.getUnitScale(this.unit);
|
||||
let canvas:HTMLCanvasElement = this.canvasRef.nativeElement;
|
||||
this.ctx = canvas.getContext('2d');
|
||||
this.elementWidth = canvas.offsetWidth;
|
||||
this.elementHeight = canvas.offsetHeight;
|
||||
this.ctx.font=`normal ${this.ratio*10}pt Sans-serif`;
|
||||
this.startDate = new Date(this.startDate.getTime() + this.getUnitDateOffset(this.startDate,this.unitScale,0));
|
||||
this.endDate = new Date(this.endDate.getTime() + this.getUnitDateOffset(this.endDate,this.unitScale,1));
|
||||
this.change.emit({startDate:this.startDate,endDate:this.endDate});
|
||||
let rangeInMilliseconds = this.endDate.getTime() - this.startDate.getTime();
|
||||
this.scale = this.getFitScale(rangeInMilliseconds,this.elementWidth);
|
||||
this.posibleUnits=this.getPosibleUnits(this.scale);
|
||||
this.height=this.getHeight();
|
||||
this.lineHeight= this.getLineHeight();
|
||||
this.setCanvasSize();
|
||||
let center = (this.startDate.getTime()+this.endDate.getTime())/2;
|
||||
this.viewMinDate = new Date(center - (this.elementWidth/2* this.scale));
|
||||
this.viewMaxDate = new Date(center + (this.elementWidth/2* this.scale));
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
this.startCaption={popoverCaption:this.getStartCaption(this.startDate,this.unitScale,true)};
|
||||
this.endCaption={popoverCaption:this.getEndCaption(this.endDate,this.unitScale,true)};
|
||||
this.redraw();
|
||||
this.initialized=true;
|
||||
}
|
||||
|
||||
getStartEndCaption(date:Date,otherDate:Date,unitScale:number,suffix:boolean = false,extended:boolean=true):string {
|
||||
let showSuffix = false;
|
||||
otherDate=new Date(otherDate.getTime()-1); // fix year edge case
|
||||
if(unitScale == 3) {
|
||||
let format="HH:00";
|
||||
if(extended) {
|
||||
if(suffix || date.getFullYear() != otherDate.getFullYear())
|
||||
format="d MMM yyyy:HH:00";
|
||||
else if(date.getMonth() !== otherDate.getMonth())
|
||||
format="d MMM HH:00";
|
||||
}
|
||||
return this.datePipe.transform(date,format);
|
||||
|
||||
}
|
||||
if(unitScale == 4) {
|
||||
let format="d";
|
||||
if(extended) {
|
||||
if(suffix || date.getFullYear() != otherDate.getFullYear())
|
||||
format="d MMM yyyy";
|
||||
else if(date.getMonth() !== otherDate.getMonth())
|
||||
format="d MMM"
|
||||
}
|
||||
return this.datePipe.transform(date,format);
|
||||
|
||||
}
|
||||
if(unitScale == 6) {
|
||||
let format = "MMM";
|
||||
if(extended) {
|
||||
if(suffix || date.getFullYear() != otherDate.getFullYear())
|
||||
format="MMM yyyy";
|
||||
}
|
||||
return this.datePipe.transform(date,format);
|
||||
}
|
||||
if(unitScale == 7) {
|
||||
let q = Math.trunc(date.getMonth() /3 );
|
||||
return this.quarters[q];
|
||||
}
|
||||
if(unitScale == 8) {
|
||||
return this.datePipe.transform(date,"yyyy");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
getStartCaption(startDate:Date,unitScale:number,suffix:boolean=false,extended:boolean=true):string {
|
||||
return this.getStartEndCaption(new Date(startDate.getTime() + (this.unitScales[unitScale]/2)), this.endDate,unitScale,suffix,extended);
|
||||
}
|
||||
|
||||
getEndCaption(endDate:Date,unitScale:number,suffix:boolean=true):string {
|
||||
return this.getStartEndCaption(new Date(endDate.getTime() - (this.unitScales[unitScale]/2)),this.startDate, unitScale,suffix);
|
||||
}
|
||||
|
||||
getCaption(startDate:Date,endDate:Date,unitScale:number):string {
|
||||
let startCaption=this.getStartCaption(startDate,unitScale);
|
||||
let endCaption=this.getEndCaption(endDate,unitScale);
|
||||
if((endDate.getTime() - startDate.getTime()) < (1.5*this.unitScales[this.unitScale]))
|
||||
return endCaption;
|
||||
return `${startCaption}-${endCaption}`;
|
||||
}
|
||||
|
||||
public updatePopoverText(popover:NgbPopover, text:string): void {
|
||||
const isOpen = popover.isOpen();
|
||||
if (isOpen) {
|
||||
popover.close();
|
||||
popover.open({popoverCaption:text});
|
||||
}
|
||||
}
|
||||
|
||||
getFitScale(rangeInMilliSeconds:number,elementWidth:number):number {
|
||||
let width = elementWidth*0.33;
|
||||
return rangeInMilliSeconds/width;
|
||||
}
|
||||
|
||||
getUnitScale(unit:string):number {
|
||||
if(!unit) return 3; // hour
|
||||
for(var _i=0;_i<this.units.length;_i++) {
|
||||
if(this.units[_i]==unit.toLowerCase()) return _i;
|
||||
}
|
||||
throw new Error(`Invalid unit : {{unit}} `);
|
||||
}
|
||||
|
||||
getUnitDateOffset(date:Date, unitScale:number,tick:number):number {
|
||||
var offsetDate:Date;
|
||||
if(unitScale==0)
|
||||
offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours() ,date.getMinutes(),date.getSeconds(),date.getMilliseconds()+ tick);
|
||||
if(unitScale==1)
|
||||
offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours() ,date.getMinutes(),date.getSeconds() + tick,0);
|
||||
if(unitScale==2)
|
||||
offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours() ,date.getMinutes() + tick,0,0);
|
||||
if(unitScale==3)
|
||||
offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours()+ tick ,0,0,0);
|
||||
if(unitScale==4)
|
||||
offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() + tick ,0,0,0,0);
|
||||
if(unitScale==6)
|
||||
offsetDate = new Date(date.getFullYear(),date.getMonth()+tick,1,0,0,0,0);
|
||||
if(unitScale==7) {
|
||||
var month = (tick * 3);
|
||||
offsetDate = new Date(date.getFullYear(),month,1,0,0,0,0);
|
||||
}
|
||||
if(unitScale==8)
|
||||
offsetDate = new Date(date.getFullYear()+tick,0,1,0,0,0,0);
|
||||
return offsetDate.getTime()-date.getTime();
|
||||
}
|
||||
|
||||
getUnitTextWidth(unitScale:number):number {
|
||||
switch(unitScale) {
|
||||
case 3:return this.ctx.measureText("88:88").width/this.ratio;
|
||||
case 4:return this.ctx.measureText("88").width/this.ratio;
|
||||
case 5:return this.ctx.measureText("WWW").width/this.ratio;
|
||||
case 6:return this.ctx.measureText("WW").width/this.ratio;
|
||||
case 7:return this.ctx.measureText("WW").width/this.ratio;
|
||||
case 8:return this.ctx.measureText("8888").width/this.ratio;
|
||||
default: return this.ctx.measureText("WW").width/this.ratio;
|
||||
}
|
||||
}
|
||||
|
||||
getNextTick(viewStartDate:Date, tick:number,step:number,unitScale:number):number {
|
||||
let unitTextWidth = this.getUnitTextWidth(unitScale);
|
||||
let dateOffset =this.getUnitDateOffset(viewStartDate,unitScale,tick);
|
||||
let date = new Date(viewStartDate.getTime() + dateOffset);
|
||||
let nextTick=tick+step+Math.trunc(step/2);
|
||||
let nextDateOffset =this.getUnitDateOffset(viewStartDate,unitScale,nextTick);
|
||||
let nextDate = new Date(viewStartDate.getTime() + nextDateOffset);
|
||||
let n=1;
|
||||
switch(unitScale) {
|
||||
case 4:n=nextDate.getDate()-1;break;
|
||||
case 6:n=nextDate.getMonth();break;
|
||||
case 8:n=nextDate.getFullYear();break;
|
||||
default: n = 1;break;
|
||||
}
|
||||
let a = Math.trunc(n / step)*step;
|
||||
nextTick=nextTick-n+a;
|
||||
if(nextTick<=tick) return tick+step;
|
||||
return nextTick;
|
||||
}
|
||||
|
||||
getSteps(unitScale:number):number[] {
|
||||
if(unitScale==4)
|
||||
return [1,14];
|
||||
if(unitScale==6)
|
||||
return [1,3,6];
|
||||
return [1,2,3,4,5];
|
||||
}
|
||||
|
||||
drawUnits(yOffset:number,width:number,viewStartDate:Date,unitScale:number):number {
|
||||
let oneUnit = (this.getUnitDateOffset(viewStartDate,unitScale,1)- this.getUnitDateOffset(viewStartDate,unitScale,0)) / this.scale;
|
||||
this.ctx.font=`normal ${this.ratio*10}pt Sans-serif`;
|
||||
let lineHeight = this.getLineHeight();
|
||||
let dateOffset = this.getUnitDateOffset(viewStartDate,unitScale,0);
|
||||
let pixelOffset = (dateOffset / this.scale);
|
||||
let caption = this.getStartCaption(new Date(viewStartDate.getTime()+dateOffset),unitScale,false,false);
|
||||
let unitTextWidth=this.getUnitTextWidth(unitScale);
|
||||
this.ctx.beginPath();
|
||||
this.ctx.strokeStyle=this.lineColor;
|
||||
let steps=this.getSteps(unitScale);
|
||||
let s=0;
|
||||
let step=steps[s];
|
||||
let steppedOneUnit=oneUnit*step;
|
||||
while(unitTextWidth > (steppedOneUnit-(2*this.padding)) && s < steps.length -1) {
|
||||
step=steps[++s];
|
||||
steppedOneUnit=oneUnit*step;
|
||||
}
|
||||
if(steppedOneUnit - (2*this.padding) < unitTextWidth) return yOffset;
|
||||
this.ctx.moveTo(0,yOffset*this.ratio);
|
||||
this.ctx.lineTo(width*this.ratio,yOffset*this.ratio);
|
||||
this.ctx.stroke();
|
||||
var x:number = pixelOffset;
|
||||
var nextDateOffset = this.getUnitDateOffset(viewStartDate,unitScale,1);
|
||||
var nextX:number = (nextDateOffset / this.scale);
|
||||
var n=0;
|
||||
while(x < width) {
|
||||
this.ctx.fillStyle=this.color;
|
||||
//mouseover
|
||||
if(this.mouseX> x && this.mouseX <nextX && this.mouseY > yOffset && this.mouseY <( yOffset + lineHeight) && !this.leftGripMove && !this.rightGripMove && !this.rangeGripMove&& !this.viewPan) {
|
||||
this.ctx.fillStyle=this.hoverBackground;
|
||||
this.ctx.fillRect((x+0.5)*this.ratio,(yOffset+0.5)*this.ratio,(nextX-x)*this.ratio,lineHeight*this.ratio);
|
||||
this.ctx.fillStyle=this.hoverColor;
|
||||
}
|
||||
|
||||
this.ctx.moveTo((x+0.5)*this.ratio,(yOffset+0.5)*this.ratio);
|
||||
this.ctx.lineTo((x+0.5)*this.ratio,(yOffset+lineHeight+0.5)*this.ratio);
|
||||
this.ctx.stroke();
|
||||
|
||||
if(unitTextWidth < steppedOneUnit - (2*this.padding) && x > 0) {
|
||||
this.ctx.fillText(caption,(x+this.padding)*this.ratio,(yOffset+lineHeight-this.padding)*this.ratio);
|
||||
} else if((unitTextWidth < (steppedOneUnit - (2*this.padding) +pixelOffset)) && (unitTextWidth < (steppedOneUnit-(2*this.padding)))) {
|
||||
this.ctx.fillText(caption, (this.padding*this.ratio),(yOffset+lineHeight-this.padding)*this.ratio);
|
||||
} else if(x < 0 && (unitTextWidth <steppedOneUnit - (2*this.padding))) {
|
||||
this.ctx.fillText(caption, ((x+steppedOneUnit-this.padding-unitTextWidth) *this.ratio),(yOffset+ lineHeight-this.padding)*this.ratio);
|
||||
}
|
||||
n=this.getNextTick(viewStartDate,n,step,unitScale);
|
||||
dateOffset = this.getUnitDateOffset(viewStartDate,unitScale,n);
|
||||
nextDateOffset = this.getUnitDateOffset(viewStartDate,unitScale,this.getNextTick(viewStartDate,n,step,unitScale));
|
||||
nextX = (nextDateOffset / this.scale);
|
||||
pixelOffset = (dateOffset / this.scale);
|
||||
caption= this.getStartCaption(new Date(viewStartDate.getTime()+dateOffset),unitScale,false,false);
|
||||
x=pixelOffset;
|
||||
}
|
||||
return lineHeight;
|
||||
}
|
||||
|
||||
redraw() {
|
||||
let yOffset=0;
|
||||
let canvas = this.canvasRef.nativeElement;
|
||||
let height = canvas.offsetHeight;
|
||||
let width = canvas.offsetWidth;
|
||||
this.ctx.lineWidth = this.lineWidth;// *this.ratio;
|
||||
this.ctx.clearRect(0,0,width *this.ratio,height*this.ratio);
|
||||
for(let unit of this.posibleUnits) {
|
||||
if(this.unitScale <=unit) yOffset+=this.drawUnits(yOffset,width,this.viewMinDate,unit);
|
||||
}
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
this.collapsed = !this.collapsed;
|
||||
}
|
||||
|
||||
updateStyle(startDate:Date,endDate:Date) {
|
||||
let rangeInMilliseconds = endDate.getTime() - startDate.getTime();
|
||||
let range = rangeInMilliseconds / this.scale;
|
||||
let left = (startDate.getTime() - this.viewMinDate.getTime()) / this.scale;
|
||||
this.startPopoverLeft=(left-10);
|
||||
this.endPopoverLeft=(left+range+10);
|
||||
this.marginLeft = (left - 15);
|
||||
this.rangeWidth = range;
|
||||
this.updatePopoverText(this.popoverStart,this.getStartCaption(startDate,this.unitScale,true));
|
||||
this.updatePopoverText(this.popoverEnd,this.getEndCaption(endDate,this.unitScale,true));
|
||||
this.caption=this.getCaption(startDate,endDate,this.unitScale);
|
||||
}
|
||||
|
||||
snapToUnit(date:Date,unitScale:number):Date {
|
||||
var d = new Date(date.getTime() + (this.unitScales[this.unitScale]/2));
|
||||
var offsetInMilliseconds =this.getUnitDateOffset(d,this.unitScale,0)
|
||||
return new Date(d.getTime()+offsetInMilliseconds);
|
||||
}
|
||||
|
||||
getEndDate(offsetInPixels:number):Date {
|
||||
let oneUnit = this.unitScales[this.unitScale];
|
||||
let offsetInMilliseconds = offsetInPixels * this.scale;
|
||||
if(this.leftGripMove) {
|
||||
if(this.startDate.getTime() + offsetInMilliseconds > this.endDate.getTime() - oneUnit) {
|
||||
return this.snapToUnit(new Date(this.startDate.getTime() + offsetInMilliseconds + oneUnit),this.unitScale);
|
||||
}
|
||||
} else if(this.rightGripMove || this.rangeGripMove) {
|
||||
return this.snapToUnit(new Date(this.endDate.getTime() + offsetInMilliseconds),this.unitScale);
|
||||
}
|
||||
return this.endDate;
|
||||
}
|
||||
|
||||
getStartDate(offsetInPixels:number):Date {
|
||||
let oneUnit = this.unitScales[this.unitScale];
|
||||
let offsetInMilliseconds = offsetInPixels * this.scale;
|
||||
if(this.leftGripMove || this.rangeGripMove) {
|
||||
return this.snapToUnit(new Date(this.startDate.getTime() + offsetInMilliseconds),this.unitScale);
|
||||
} else if(this.rightGripMove) {
|
||||
if(this.endDate.getTime() + offsetInMilliseconds < this.startDate.getTime() + oneUnit) {
|
||||
return this.snapToUnit(new Date(this.endDate.getTime() + offsetInMilliseconds - oneUnit),this.unitScale);
|
||||
}
|
||||
}
|
||||
return this.startDate;
|
||||
}
|
||||
|
||||
updateControl(event:MouseEvent|TouchEvent) {
|
||||
let offsetInPixels = this.getClientX(event) - this.downX;
|
||||
if(this.leftGripMove || this.rightGripMove || this.rangeGripMove) {
|
||||
let startDate = this.getStartDate(offsetInPixels);
|
||||
let endDate = this.getEndDate(offsetInPixels);
|
||||
this.updateStyle(startDate,endDate)
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} else if(this.viewPan) {
|
||||
let offsetInMilliseconds = offsetInPixels*this.scale;
|
||||
this.viewMinDate = new Date(this.viewMinDate.getTime()-offsetInMilliseconds);
|
||||
this.viewMaxDate = new Date(this.viewMaxDate.getTime()-offsetInMilliseconds);
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
this.redraw();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
this.downX=this.getClientX(event);
|
||||
}
|
||||
this.lastOffsetInPixels=offsetInPixels
|
||||
}
|
||||
|
||||
isMouseEvent(arg: any): arg is MouseEvent {
|
||||
return arg.clientX !== undefined;
|
||||
}
|
||||
|
||||
getClientX(event:MouseEvent|TouchEvent) {
|
||||
if(this.isMouseEvent(event)) {
|
||||
return (event as MouseEvent).clientX;
|
||||
} else {
|
||||
return (event as TouchEvent).touches[0].clientX;
|
||||
}
|
||||
}
|
||||
|
||||
handleRightGripMouseDown(event:MouseEvent) {
|
||||
this.rightGripMove=true;
|
||||
this.downX = this.getClientX(event);
|
||||
this.popoverEnd.open(this.endCaption);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
handleRightGripMouseEnter(event:MouseEvent) {
|
||||
this.mouseX=-1;
|
||||
this.mouseY=-1;
|
||||
this.redraw();
|
||||
if(!this.rangeGripMove && !this.leftGripMove && !this.rightGripMove) this.popoverEnd.open(this.endCaption);
|
||||
}
|
||||
|
||||
handleRightGripMouseLeave(event:MouseEvent) {
|
||||
if(!this.rightGripMove) this.popoverEnd.close();
|
||||
}
|
||||
|
||||
handleLeftGripMouseDown(event:MouseEvent|TouchEvent) {
|
||||
this.leftGripMove=true;
|
||||
this.downX = this.getClientX(event);
|
||||
this.popoverStart.open(this.startCaption);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
handleLeftGripMouseEnter(event:MouseEvent|TouchEvent) {
|
||||
this.mouseX=-1;
|
||||
this.mouseY=-1;
|
||||
this.redraw();
|
||||
if(!this.rangeGripMove && !this.leftGripMove && !this.rightGripMove) this.popoverStart.open(this.startCaption);
|
||||
}
|
||||
|
||||
handleLeftGripMouseLeave(event:MouseEvent) {
|
||||
if(!this.leftGripMove) this.popoverStart.close();
|
||||
}
|
||||
|
||||
handleRangeGripMouseEnter(event:MouseEvent) {
|
||||
this.mouseX=-1;
|
||||
this.mouseY=-1;
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
handleRangeGripMouseDown(event:MouseEvent|TouchEvent) {
|
||||
this.rangeGripMove=true;
|
||||
this.downX = this.getClientX(event);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
handleViewPanMouseDown(event:MouseEvent|TouchEvent) {
|
||||
this.viewPan=true;
|
||||
this.downX =this.getClientX(event);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
handleMouseUp(event:MouseEvent|TouchEvent) {
|
||||
//this.updateControl(event);
|
||||
this.startDate = this.getStartDate(this.lastOffsetInPixels);
|
||||
this.endDate = this.getEndDate(this.lastOffsetInPixels);
|
||||
this.popoverStart.close();
|
||||
this.popoverEnd.close();
|
||||
this.startCaption={popoverCaption:this.getStartCaption(this.startDate,this.unitScale,true)};
|
||||
this.endCaption={popoverCaption:this.getEndCaption(this.endDate,this.unitScale,true)};
|
||||
if(this.leftGripMove || this.rightGripMove || this.rangeGripMove) {
|
||||
this.change.emit({ startDate:this.startDate,endDate:this.endDate});
|
||||
}
|
||||
this.rightGripMove=false;
|
||||
this.leftGripMove=false;
|
||||
this.rangeGripMove=false;
|
||||
this.viewPan = false;
|
||||
this.lastOffsetInPixels=0;
|
||||
}
|
||||
|
||||
handleMouseMove(event:MouseEvent) {
|
||||
this.mouseX = -1;
|
||||
this.mouseY = -1;
|
||||
if(!this.leftGripMove && ! this.rightGripMove && !this.rangeGripMove && !this.viewPan) {
|
||||
return;
|
||||
} else {
|
||||
this.updateControl(event);
|
||||
}
|
||||
}
|
||||
|
||||
handleCanvasMouseMove(event:MouseEvent) {
|
||||
this.mouseX = event.offsetX;
|
||||
this.mouseY = event.offsetY;
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
handleCanvasMouseLeave(event:MouseEvent) {
|
||||
this.mouseX = -1;
|
||||
this.mouseY = -1;
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
canZoom(currentScale:number, direction:number):boolean {
|
||||
let nextScale=currentScale;
|
||||
if(direction<0 ) {
|
||||
return true;
|
||||
} else {
|
||||
nextScale*=1.1;
|
||||
let canZoom=false;
|
||||
let oneUnit = (this.getUnitDateOffset(this.viewMinDate,8,1)- this.getUnitDateOffset(this.viewMinDate,8,0)) / nextScale;
|
||||
let unitTextWidth=this.getUnitTextWidth(8);
|
||||
let steps=this.getSteps(8);
|
||||
let s=0;
|
||||
let step=steps[s];
|
||||
let steppedOneUnit=oneUnit*step;
|
||||
while(unitTextWidth > (steppedOneUnit-(2*this.padding)) && s < steps.length -1) {
|
||||
step=steps[++s];
|
||||
steppedOneUnit=oneUnit*step;
|
||||
}
|
||||
return unitTextWidth < (steppedOneUnit-(2*this.padding)) && s < steps.length;
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseWheel(event:WheelEvent) {
|
||||
if(!this.canZoom(this.scale,event.deltaY)) return;
|
||||
let oldOffsetInMilliseconds = event.clientX * this.scale;
|
||||
if(event.deltaY>=0)
|
||||
this.scale*=1.1;
|
||||
else
|
||||
this.scale/=1.1;
|
||||
this.posibleUnits=this.getPosibleUnits(this.scale);
|
||||
this.height=this.getHeight();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
this.setCanvasSize();
|
||||
let newOffsetInMilliseconds = event.clientX * this.scale;
|
||||
let offsetInMilliseconds = newOffsetInMilliseconds-oldOffsetInMilliseconds;
|
||||
this.viewMinDate = new Date(this.viewMinDate.getTime()-offsetInMilliseconds);
|
||||
this.viewMaxDate = new Date(this.viewMaxDate.getTime()-offsetInMilliseconds);
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
this.redraw();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
handleZoomOut() {
|
||||
if(!this.canZoom(this.scale,1)) return;
|
||||
this.scale*=1.1;
|
||||
this.posibleUnits=this.getPosibleUnits(this.scale);
|
||||
this.height=this.getHeight();
|
||||
this.setCanvasSize();
|
||||
this.redraw();
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
}
|
||||
|
||||
handleZoomIn() {
|
||||
if(!this.canZoom(this.scale,-1)) return;
|
||||
this.scale/=1.1;
|
||||
this.posibleUnits=this.getPosibleUnits(this.scale);
|
||||
this.height=this.getHeight();
|
||||
this.setCanvasSize();
|
||||
this.redraw();
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
}
|
||||
|
||||
handleResize(event:any) {
|
||||
if(this.initialized) {
|
||||
this.setCanvasSize();
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
this.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges (changes: SimpleChanges) {
|
||||
if(this.initialized) {
|
||||
this.setCanvasSize();
|
||||
this.updateStyle(this.startDate,this.endDate);
|
||||
this.redraw();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user