-
Notifications
You must be signed in to change notification settings - Fork 1
/
PolylineAnimation.js
158 lines (143 loc) · 5.9 KB
/
PolylineAnimation.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
* 1. Create an instance for each graphic to animate; pass in graphic, graphicsLayer, and duration (ms) to the constructor.
* 2. Call animatePolyline()
* Example:
* var pla = new PolylineAnimation({
* graphic : gpcConnector, // The polyline graphic you want to animate from 0 - 100%
* graphicsLayer : glCityConnectors, // The graphics layer to display the graphic on (you haven't added the graphic yet)
* duration : 2500 // How long the animation should last, in milliseconds
* });
* pla.animatePolyline();
*/
define(
[
"dojo/_base/declare",
"dojo/_base/fx",
"dojo/_base/lang",
"esri/graphic",
"esri/geometry/Point",
"esri/geometry/Polyline"
],
function(
declare,
fx,
lang,
Graphic,
Point,
Polyline
) {
return declare(null, {
graphic : null,
graphicsLayer : null,
originalGeometry: null,
duration : null,
pathInfos : null,
constructor: function(parameters) {
/**
* graphic : the polyline graphic to animate
* graphicsLayer : the graphics layer to add the polyline to before and while animating
* duration : the duration of the animation, in milliseconds
*/
this.graphic = parameters.graphic;
this.originalGeometry = parameters.graphic.geometry;
this.graphicsLayer = parameters.graphicsLayer;
this.duration = parameters.duration;
this.pathInfos = [];
},
/* Calculate the geometry for a given (initialized graphic) and a given percentage */
percentOfPolyline: function( percent ) {
var nFraction = percent / 100.0;
var plGeom = new Polyline( this.originalGeometry.spatialReference );
for ( var iPath = 0; iPath < this.pathInfos.length; iPath++ ) {
var oPath = this.pathInfos[ iPath ];
var nRequestedPathLen = oPath.pathLength * ( nFraction );
var nCurrentPathLen = 0; // Length of path-being-constructed
var aryPathPts = [];
for ( var iSegment = 0; iSegment < oPath.segmentInfos.length; iSegment++ ) {
var oSegment = oPath.segmentInfos[ iSegment ];
var ptSegmentStart = oSegment.startPoint;
var ptSegmentEnd = oSegment.endPoint;
var nCurrentSegmentLen = oSegment.segmentLength;
if ( iSegment == 0 ) aryPathPts.push( oSegment.startPoint );
// If this segment won't complete the requested percentage of the total path,
// add the whole segment
if ( nCurrentPathLen + nCurrentSegmentLen < nRequestedPathLen ) {
aryPathPts.push( ptSegmentEnd );
nCurrentPathLen += nCurrentSegmentLen;
}
// If this segment will complete or surpass the requested percentage of the total line,
// it's the last segment; calculate the proper percentage to add
else {
var nPathLenStillNeeded = nRequestedPathLen - nCurrentPathLen;
var nPctOfThisPathNeeded = nPathLenStillNeeded / nCurrentSegmentLen;
var nDeltaX = (ptSegmentEnd.x - ptSegmentStart.x) * nPctOfThisPathNeeded;
var nDeltaY = (ptSegmentEnd.y - ptSegmentStart.y) * nPctOfThisPathNeeded;
var ptNewEnd = new Point(ptSegmentStart.x + nDeltaX, ptSegmentStart.y + nDeltaY, this.originalGeometry.spatialReference);
aryPathPts.push( ptNewEnd );
// And exit the loop
break;
}
}
plGeom.addPath( aryPathPts );
}
return plGeom;
},
// Do necessary, initial calculations about the polyline's paths and segments
initPolyline: function() {
this.graphic.visible = false;
this.graphicsLayer.add(this.graphic);
// Make a record of the original, full geometry
var pln = this.originalGeometry;
// Get info about the various paths and their lengths
for ( var iPath = 0; iPath < pln.paths.length; iPath++ ) {
var aryPath = pln.paths[ iPath ];
var arySegmentsForPath = [];
var nPathLen = 0;
// Store each pair of points in the path, plus the distance between them
for ( var iPathPt = 1; iPathPt < aryPath.length; iPathPt++ ) {
var ptStart = new Point( aryPath[ iPathPt - 1 ][ 0 ], aryPath[ iPathPt - 1 ][ 1 ], pln.spatialReference );
var ptEnd = new Point( aryPath[ iPathPt ][ 0 ], aryPath[ iPathPt ] [ 1 ], pln.spatialReference );
// Figure out distance between start/end point using pythagorean theorem (this needs improvement)
var nSegmentLen = Math.sqrt( Math.pow( ptEnd.x - ptStart.x, 2 ) + Math.pow( ptEnd.y - ptStart.y, 2 ) );
arySegmentsForPath.push( {
"startPoint" : ptStart,
"endPoint" : ptEnd,
"segmentLength" : nSegmentLen
} );
nPathLen += nSegmentLen;
}
this.pathInfos.push( {
"segmentInfos" : arySegmentsForPath,
"pathLength" : nPathLen
} );
}
},
updatePolyline: function(percent){
var geometry = this.percentOfPolyline(percent);
this.graphic.setGeometry(geometry);
},
animatePolyline: function(){
fx.animateProperty({
node: dojo.create('div'),
properties:{
along:{
start:0,
end:100
}
},
duration: this.duration,
beforeBegin: this.initPolyline(),
onAnimate: lang.hitch(this, function(values){
// values assumes to be in pixels so we need to remove px from the end...
var percent = parseFloat(values.along.replace(/px/,''));
this.updatePolyline(percent);
if (!this.graphic.visible) this.graphic.visible = true;
}),
onEnd: lang.hitch(this, function() {
this.graphic.setGeometry(this.originalGeometry);
})
}).play();
}
});
}
);