This repository has been archived by the owner on Nov 30, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
array-sync.coffee
162 lines (145 loc) · 6.24 KB
/
array-sync.coffee
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
159
160
161
162
angular.module('uiGmapgoogle-maps').factory 'uiGmaparray-sync', [
'uiGmapadd-events', (mapEvents) ->
# pathChangedFn is an optional callback that is called whenever a change to the path
# is detected. The first parameter contains the internal array of Google LatLng objects.
(mapArray, scope, pathEval, pathChangedFn) ->
isSetFromScope = false
scopePath = scope.$eval(pathEval)
if !scope.static
#should pathChangedFn be called for changes made via the UI too? Currently not needed, and not implemented
legacyHandlers =
#listeners / handles to changes of the points from the map direction to update back to our scope (two way)
set_at: (index) ->
return if isSetFromScope #important to avoid cyclic forever change loop watch to map event change and back
value = mapArray.getAt(index)
return unless value
if not value.lng or not value.lat # LatLng object
scopePath[index] = value
else
scopePath[index].latitude = value.lat()
scopePath[index].longitude = value.lng()
insert_at: (index) ->
return if isSetFromScope #important to avoid cyclic forever change loop watch to map event change and back
value = mapArray.getAt(index)
return unless value
#check to make sure we are not inserting something that is already there
if not value.lng or not value.lat # LatLng object
scopePath.splice index, 0, value
else
scopePath.splice index, 0,
latitude: value.lat()
longitude: value.lng()
remove_at: (index) ->
return if isSetFromScope #important to avoid cyclic forever change loop watch to map event change and back
scopePath.splice index, 1
geojsonArray
if scopePath.type == 'Polygon'
#Note: we only support display of the outer Polygon ring, not internal holes
geojsonArray = scopePath.coordinates[0]
else if scopePath.type == 'LineString'
geojsonArray = scopePath.coordinates
geojsonHandlers =
set_at: (index) ->
return if isSetFromScope #important to avoid cyclic forever change loop watch to map event change and back
value = mapArray.getAt(index)
return unless value
return if not value.lng or not value.lat
geojsonArray[index][1] = value.lat()
geojsonArray[index][0] = value.lng()
insert_at: (index) ->
return if isSetFromScope #important to avoid cyclic forever change loop watch to map event change and back
value = mapArray.getAt(index)
return unless value
return if not value.lng or not value.lat
geojsonArray.splice index, 0, [ value.lng(), value.lat() ]
remove_at: (index) ->
return if isSetFromScope #important to avoid cyclic forever change loop watch to map event change and back
geojsonArray.splice index, 1
mapArrayListener = mapEvents mapArray,
if angular.isUndefined scopePath.type then legacyHandlers else geojsonHandlers
legacyWatcher = (newPath) ->
isSetFromScope = true
oldArray = mapArray
changed = false
if newPath
i = 0
oldLength = oldArray.getLength()
newLength = newPath.length
l = Math.min(oldLength, newLength)
newValue = undefined
#update existing points if different
while i < l
oldValue = oldArray.getAt(i)
newValue = newPath[i]
if typeof newValue.equals == 'function' #LatLng object
if not newValue.equals(oldValue)
oldArray.setAt i, newValue
changed = true
else # latitude/longitude object
if (oldValue.lat() isnt newValue.latitude) or (oldValue.lng() isnt newValue.longitude)
oldArray.setAt i, new google.maps.LatLng(newValue.latitude, newValue.longitude)
changed = true
i++
#add new points
while i < newLength
newValue = newPath[i]
if typeof newValue.lat == 'function' and typeof newValue.lng == 'function'
oldArray.push newValue
else
oldArray.push new google.maps.LatLng(newValue.latitude, newValue.longitude)
changed = true
i++
#remove old no longer there
while i < oldLength
oldArray.pop()
changed = true
i++
isSetFromScope = false
pathChangedFn oldArray if changed
geojsonWatcher = (newPath) ->
isSetFromScope = true
oldArray = mapArray
changed = false
if newPath
array
if scopePath.type == 'Polygon'
array = newPath.coordinates[0]
else if scopePath.type == 'LineString'
array = newPath.coordinates
i = 0
oldLength = oldArray.getLength()
newLength = array.length
l = Math.min(oldLength, newLength)
newValue = undefined
while i < l
oldValue = oldArray.getAt(i)
newValue = array[i]
if (oldValue.lat() isnt newValue[1]) or (oldValue.lng() isnt newValue[0])
oldArray.setAt i, new google.maps.LatLng(newValue[1], newValue[0])
changed = true
i++
while i < newLength
newValue = array[i]
oldArray.push new google.maps.LatLng(newValue[1], newValue[0])
changed = true
i++
while i < oldLength
oldArray.pop()
changed = true
i++
isSetFromScope = false
pathChangedFn oldArray if changed
watchListener
if !scope.static
if angular.isUndefined(scopePath.type)
watchListener = scope.$watchCollection pathEval, legacyWatcher
else
watchListener = scope.$watch pathEval, geojsonWatcher, true
->
if mapArrayListener
mapArrayListener()
mapArrayListener = null
if watchListener
watchListener() # call the watch deregistration function
watchListener = null
]