ela 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,163 +0,0 @@
1
- ELA.Views ?= {}
2
- class ELA.Views.CurveGraph extends ELA.Views.BaseGraph
3
- initialize: (options = {}) ->
4
- super
5
-
6
- @bindCalculatorEvents()
7
-
8
- @model.curves.on 'change:selected', =>
9
- @bindCalculatorEvents()
10
- @requestRepaint()
11
-
12
- @model.on 'change:calculators', =>
13
- @calculateRanges()
14
- @bindCalculatorEvents()
15
- @requestRepaint()
16
-
17
- @model.on 'change:valueAtRange', @requestRepaint
18
- @model.on 'change:axisLabelingForCurve', @requestRepaint
19
-
20
- bindCalculatorEvents: ->
21
- # Remove current callbacks, add new ones for each curve
22
- @stopListening(@model.previous('calculators'))
23
-
24
- for calc in @model.get('calculators')
25
- for curve in @model.curves.history
26
- @listenTo calc, "change:#{curve.get('function')}", @requestRepaint
27
-
28
- @listenTo calc, 'change:maxX change:maxY', @calculateRanges
29
- # TODO: Add dynamic dependencies to calculator, so that we can
30
- # actually only listen to maxY changes and recalculate ranges.
31
- oldestCurve = @model.curves.history[0]
32
- if oldestCurve?
33
- @listenTo calc, "change:#{oldestCurve.get('function')}", @calculateRanges
34
-
35
- calculateRanges: =>
36
- @params.set xRange: @maxRangeX()
37
-
38
- maxRangeX: =>
39
- max = _.chain(@model.get('calculators'))
40
- .map (c) -> c.maxX()
41
- .max()
42
- .value()
43
- min = _.chain(@model.get('calculators'))
44
- .map (c) -> c.minX()
45
- .min()
46
- .value()
47
- range = 0
48
- range += max if max > 0
49
- range -= min if min < 0
50
- (Math.abs(range) or 10000) * @params.get('xScale') * 1.1
51
-
52
- maxRangeY: (func) =>
53
- unless func?
54
- func = @model.get('axisLabelingForCurve')?.get('function')
55
- max = _.chain(@model.get('calculators'))
56
- .map (c) -> c.maxY(func, c.minX(), c.maxX(), 30)
57
- .max()
58
- .value()
59
- min = _.chain(@model.get('calculators'))
60
- .map (c) -> c.minY(func, c.minX(), c.maxX(), 30)
61
- .min()
62
- .value()
63
- range = 0
64
- range += max if max > 0
65
- range -= min if min < 0
66
- Math.abs(range) * @params.get('yScale') * 1.1
67
-
68
- xAxisValueLabel: (val, stepsize) ->
69
- @axisLabel(val, stepsize)
70
-
71
- yAxisValueLabel: (val, stepsize) ->
72
- curve = @model.get('axisLabelingForCurve')
73
- val = @Present(curve).unitValue(val) if curve?
74
- @axisLabel(val, stepsize)
75
-
76
- yAxisLabel: ->
77
- curve = @model.get('axisLabelingForCurve')
78
- @Present(curve).fullYAxisLabel()
79
-
80
- renderCurves: ->
81
- for calc, i in @model.get('calculators')
82
- for curve, j in @model.curves.history
83
- func = curve.get('function')
84
-
85
- @context.strokeStyle = curve.strokeStyle()
86
- @context.lineWidth = 3
87
- if i == 1
88
- @context.setLineDash [4,5]
89
- else
90
- @context.setLineDash []
91
- xPos = 0
92
- brokenLine = 1
93
- plotted = 0
94
- @context.beginPath()
95
- xPos = 0
96
- yRange = @maxRangeY(func)
97
- yMin = -(@height - @yOrigin) * yRange / @height
98
- yMax = @yOrigin * yRange / @height
99
- for xPos in [-2 .. (@width + 3)]
100
- x = @xMin + xPos * @xRange / @width
101
- val = calc[func](x)
102
- y = val
103
- if y?
104
- yPos = (yMax - y) * @height / yRange
105
- if brokenLine > 0
106
- @context.moveTo(xPos, yPos) if brokenLine == 1
107
- brokenLine -= 1
108
- else
109
- @context.lineTo(xPos, yPos)
110
- plotted += 1
111
-
112
- @context.stroke()
113
- @context.closePath()
114
-
115
- renderRangeIndicator: ->
116
- @context.setLineDash []
117
- @context.beginPath()
118
- @context.strokeStyle = '#999999'
119
- @context.lineWidth = 2
120
- @context.moveTo(0, 0)
121
- @context.lineTo(@width, 0)
122
- @context.stroke()
123
-
124
- @context.beginPath()
125
- @context.strokeStyle = '#999999'
126
- @context.lineWidth = 2
127
- @context.moveTo(0, @height)
128
- @context.lineTo(@width, @height)
129
- @context.stroke()
130
-
131
- if @model.get('valueAtRange')?
132
- valueAtPoint = @model.get('valueAtRange')
133
-
134
- @context.beginPath()
135
- @context.strokeStyle = '#999999'
136
- @context.lineWidth = 2
137
- xPos = @xOrigin + valueAtPoint * @width / @xRange
138
- @context.moveTo(xPos, 0)
139
- @context.lineTo(xPos, @height)
140
- @context.stroke()
141
- @context.closePath()
142
-
143
- @context.beginPath()
144
- @context.lineWidth = 1
145
-
146
- # The fillStyle of the triangle should match the color of the
147
- # legend background set in screen.styl:
148
- @context.fillStyle = "#f2f2f2"
149
-
150
- @context.moveTo(xPos + 8, 0)
151
- @context.lineTo(xPos, 8)
152
- @context.lineTo(xPos - 8, 0)
153
- @context.moveTo(xPos - 8, @height)
154
- @context.lineTo(xPos, @height - 8)
155
- @context.lineTo(xPos + 8, @height)
156
- @context.stroke()
157
- @context.fill()
158
- @context.closePath()
159
-
160
- render: =>
161
- super
162
- @renderRangeIndicator()
163
- this
@@ -1,294 +0,0 @@
1
- ELA.Views ?= {}
2
- class ELA.Views.InterpolatedGraph extends ELA.Views.BaseGraph
3
- initialize: (options = {}) ->
4
- super
5
-
6
- @bindCalculatorEvents()
7
-
8
- @model.curves.on 'change:selected', =>
9
- @bindCalculatorEvents()
10
- @requestRepaint()
11
-
12
- @model.on 'change:calculators', =>
13
- @calculateRanges()
14
- @bindCalculatorEvents()
15
- @requestRepaint()
16
-
17
- for guide in @params.get('guides')
18
- @listenTo(@model, "change:#{guide.attribute}", @requestRepaint)
19
-
20
- @listenTo(@params, 'change:axisLabelingForCurve', @requestRepaint)
21
-
22
- bindCalculatorEvents: ->
23
- # Remove current callbacks, add new ones for each curve
24
- @stopListening(@model.previous('calculators'))
25
-
26
- for calc in @model.get('calculators')
27
- filteredCurves = @_filteredCurves()
28
- for curve in filteredCurves
29
- @listenTo calc, "change:#{curve.get('function')}", @requestRepaint
30
-
31
- @listenTo calc, 'change:maxX change:xRange', @calculateRangeX
32
- @listenTo calc, 'change:maxY change:yRange', @calculateRangeY
33
- # TODO: Add dynamic dependencies to calculator, so that we can
34
- # actually only listen to maxY changes and recalculate ranges.
35
- oldestCurve = filteredCurves[0]
36
- if oldestCurve?
37
- @listenTo calc, "change:#{oldestCurve.get('function')}", @calculateRanges
38
-
39
- maxRangeX: (func, xScale = @params.get('xScale')) =>
40
- func = @params.get('axisLabelingForCurve')?.get('function') unless func?
41
- ranges = (calc.xRange(func) for calc in @model.get('calculators'))
42
- Math.max.apply(Math, _.compact(ranges)) * xScale
43
-
44
- maxRangeY: (func, yScale = @params.get('yScale')) =>
45
- func = @params.get('axisLabelingForCurve')?.get('function') unless func?
46
- ranges = (calc.yRange(func) for calc in @model.get('calculators'))
47
- Math.max.apply(Math, _.compact(ranges)) * yScale
48
-
49
- xAxisValueLabel: (val, stepsize) ->
50
- @axisLabel(val, stepsize)
51
-
52
- yAxisValueLabel: (val, stepsize) ->
53
- curve = @params.get('axisLabelingForCurve')
54
- if curve?
55
- curvePresenter = @Present(curve)
56
- val = curvePresenter.unitValue(val)
57
- stepsize = curvePresenter.unitValue(stepsize)
58
- @axisLabel(val - @params.get('yOffset'), stepsize)
59
-
60
- genericAxisLabel: (axis) ->
61
- axisLabel = @params.get("#{axis}AxisLabel")
62
- return axisLabel.call(this) if axisLabel? and _.isFunction(axisLabel)
63
- return axisLabel if axisLabel?
64
-
65
- axisLabelLocale = @params.get("#{axis}AxisLabelLocale")
66
- return @loadLocale(axisLabelLocale) if axisLabelLocale?
67
-
68
- curve = @params.get('axisLabelingForCurve')
69
- if curve?
70
- return @Present(curve).fullXAxisLabel() if axis is 'x'
71
- return @Present(curve).fullYAxisLabel() if axis is 'y'
72
-
73
- @loadLocale("graph.#{axis}AxisLabel", defaultValue: '')
74
-
75
- xAxisLabel: -> @genericAxisLabel('x')
76
- yAxisLabel: -> @genericAxisLabel('y')
77
-
78
- getControlPoints: (x0, y0, x1, y1, x2, y2, tension) ->
79
- d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2))
80
- d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
81
- fa = tension * d01 / (d01 + d12)
82
- fb = tension - fa
83
- p1x = x1 + fa * (x0 - x2)
84
- p1y = y1 + fa * (y0 - y2)
85
- p2x = x1 - fb * (x0 - x2)
86
- p2y = y1 - fb * (y0 - y2)
87
- [p1x, p1y, p2x, p2y]
88
-
89
- drawSpline: (points, t, closed, xPos = ((x) -> x), yPos = ((y) -> y)) ->
90
- if points.length <= 4
91
- @context.moveTo(xPos(points[0]), yPos(points[1]))
92
- @context.lineTo(xPos(points[2]), yPos(points[3]))
93
- else
94
- cp = []
95
- n = points.length
96
- points = _.clone(points)
97
- if closed
98
- points.push points[0], points[1], points[2], points[3]
99
- points.unshift points[n - 1]
100
- points.unshift points[n - 1]
101
- for i in [0..n] by 2
102
- cp = cp.concat(@getControlPoints(points[i], points[i+1], points[i+2], points[i+3], points[i+4], points[i+5], t))
103
- cp = cp.concat(cp[0], cp[1])
104
- for i in [0..n] by 2
105
- @context.moveTo(xPos(points[i]), yPos(points[i+1]))
106
- @context.bezierCurveTo(xPos(cp[2*i-2]), yPos(cp[2*i-1]), xPos(cp[2*i]), yPos(cp[2*i+1]), xPos(points[i+2]), yPos(points[i+3]))
107
- else
108
- for i in [0..(n-4)] by 2
109
- cp = cp.concat(@getControlPoints(points[i], points[i+1], points[i+2], points[i+3], points[i+4], points[i+5], t))
110
-
111
- @context.moveTo(xPos(points[0]), yPos(points[1]))
112
- @context.quadraticCurveTo(xPos(cp[0]), yPos(cp[1]), xPos(points[2]), yPos(points[3]))
113
- for i in [2..(n-3)] by 2
114
- @context.moveTo(xPos(points[i]), yPos(points[i+1]))
115
- @context.bezierCurveTo(xPos(cp[2*i-2]), yPos(cp[2*i-1]), xPos(cp[2*i]), yPos(cp[2*i+1]), xPos(points[i+2]), yPos(points[i+3]))
116
- @context.moveTo(xPos(points[n-2]), yPos(points[n-1]))
117
- @context.quadraticCurveTo(xPos(cp[2*n-10]), yPos(cp[2*n-9]), xPos(points[n-4]), yPos(points[n-3]))
118
-
119
- drawCurve: (points, tension = 0, closed = false, xPos = ((x) -> x), yPos = ((y) -> y)) ->
120
- if tension is 0
121
- beginning = true
122
- if points.length >= 2
123
- @context.moveTo(xPos(points[0]), yPos(points[1]))
124
- for i in [2...points.length] by 2
125
- @context.lineTo(xPos(points[i]), yPos(points[i+1]))
126
- else
127
- @drawSpline(points, tension, closed, xPos, yPos)
128
-
129
- _filteredCurves: ->
130
- curves = @model.curves.history
131
- if graphCurves = @params.get('curves')
132
- _.filter curves, (curve) ->
133
- graphCurves.indexOf(curve.get('function')) >= 0
134
- else
135
- curves
136
-
137
- _sortedCurves: ->
138
- _.sortBy @_filteredCurves(), (curve) ->
139
- curve.get('zIndex')
140
-
141
-
142
- beforeRenderCurves: (resultCurves) ->
143
- afterRenderCurves: (resultCurves) ->
144
-
145
- renderCurves: ->
146
- resultCurves = []
147
- for calc, i in @model.get('calculators')
148
- for curve, j in @_sortedCurves()
149
- func = curve.get('function')
150
- resultCurves.push
151
- curve: curve
152
- result: calc[func](@xMin, @xMax)
153
- yRange: @maxRangeY(func)
154
- xRange: @maxRangeX(func)
155
- calculatorIdx: i
156
-
157
- @beforeRenderCurves(resultCurves)
158
-
159
- for resultCurve in resultCurves
160
- curve = resultCurve.curve
161
- result = resultCurve.result
162
- yRange = resultCurve.yRange
163
- xRange = resultCurve.xRange
164
- if _.isObject(result)
165
- xPos = (x) => @xOrigin + x * @width / xRange
166
- yPos = (y) => @yOrigin - (y + @yOffset) * @height / yRange
167
-
168
- if curve.hasSubcurves()
169
- for name, subcurve of curve.subcurves()
170
- if result[name].points?
171
- @renderCurve(subcurve, result[name], xPos, yPos, resultCurve.calculatorIdx)
172
- else if result[name].radius?
173
- @renderCircle(subcurve, result[name], xPos, yPos, resultCurve.calculatorIdx)
174
- else
175
- if result.points?
176
- @renderCurve(curve, result, xPos, yPos, resultCurve.calculatorIdx)
177
- else if result.radius?
178
- @renderCircle(curve, result, xPos, yPos, resultCurve.calculatorIdx)
179
-
180
- @afterRenderCurves(resultCurves)
181
-
182
- renderCircle: (curve, result, xPos, yPos, calculatorIdx) ->
183
- func = curve.get('function')
184
- yRange = @maxRangeY(func)
185
- @context.beginPath()
186
- width = Math.abs(xPos(2*result.radius) - @xOrigin)
187
- height = Math.abs(yPos(2*result.radius) - @yOrigin)
188
- centerX = xPos(result.center[0])
189
- centerY = yPos(result.center[1])
190
-
191
- aX = centerX - width/2
192
- aY = centerY - height/2
193
- hB = (width / 2) * .5522848
194
- vB = (height / 2) * .5522848
195
- eX = aX + width
196
- eY = aY + height
197
- mX = aX + width / 2
198
- mY = aY + height / 2
199
- @context.moveTo(aX, mY);
200
- @context.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY);
201
- @context.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY);
202
- @context.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY);
203
- @context.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY);
204
-
205
- @context.setLineDash(curve.lineDash(calculatorIdx))
206
- if curve.strokeStyle()
207
- @context.lineWidth = curve.get('lineWidth')
208
- @context.strokeStyle = curve.strokeStyle()
209
- @context.stroke()
210
- if fillStyle = curve.get('fillStyle')
211
- @context.fillStyle = fillStyle
212
- @context.fill()
213
- @context.closePath()
214
-
215
- renderCurve: (curve, result, xPos, yPos, calculatorIdx) ->
216
- @context.beginPath()
217
- @context.setLineDash(curve.lineDash(calculatorIdx))
218
- if result.multiplePaths
219
- for setOfPoints, i in result.points
220
- @drawCurve(setOfPoints, result.tension, false, xPos, yPos)
221
- else
222
- @drawCurve(result.points, result.tension, false, xPos, yPos)
223
- if curve.strokeStyle()
224
- @context.lineWidth = curve.get('lineWidth')
225
- @context.strokeStyle = curve.strokeStyle()
226
- @context.stroke()
227
- if fillStyle = curve.get('fillStyle')
228
- @context.fillStyle = fillStyle
229
- @context.fill()
230
- @context.closePath()
231
-
232
- renderGuide: (guide) ->
233
- valueAtPoint = @model.get(guide.attribute)
234
-
235
- @context.beginPath()
236
- @context.setLineDash []
237
- @context.strokeStyle = '#999999'
238
- @context.lineWidth = 2
239
-
240
- # Border below legend
241
- @context.moveTo(@width, 0)
242
- @context.lineTo(0, 0)
243
-
244
- if guide.orientation is 'vertical'
245
- # Border next to range handler
246
- @context.moveTo(0, @height)
247
- @context.lineTo(@width, @height)
248
- @context.lineTo(@width, @height-10)
249
-
250
- # Range handler line
251
- xPos = @xOrigin + valueAtPoint * @width / @xRange
252
- @context.moveTo(xPos, 0)
253
- @context.lineTo(xPos, @height)
254
- else
255
- # Border next to range handler
256
- @context.lineTo(0, @height)
257
-
258
- # Range handler line
259
- yPos = - valueAtPoint * @height / @yRange + @yOrigin
260
- @context.moveTo(0, yPos)
261
- @context.lineTo(@width, yPos)
262
-
263
- @context.stroke()
264
- @context.closePath()
265
-
266
- @context.beginPath()
267
- # The fillStyle of the triangle should match the color of the
268
- # background set for the legend and range handler in screen.styl:
269
- @context.fillStyle = "#f2f2f2"
270
- @context.lineWidth = 1
271
-
272
- if guide.orientation is 'vertical'
273
- @context.moveTo(xPos + 8, 0)
274
- @context.lineTo(xPos, 8)
275
- @context.lineTo(xPos - 8, 0)
276
- @context.moveTo(xPos - 8, @height)
277
- @context.lineTo(xPos, @height - 8)
278
- @context.lineTo(xPos + 8, @height)
279
- else
280
- @context.moveTo(0, yPos - 8)
281
- @context.lineTo(8, yPos)
282
- @context.lineTo(0, yPos + 8)
283
- @context.moveTo(@width, yPos - 8)
284
- @context.lineTo(@width - 8, yPos)
285
- @context.lineTo(@width, yPos + 8)
286
- @context.stroke()
287
- @context.fill()
288
- @context.closePath()
289
-
290
- render: =>
291
- super
292
- for guide in @params.get('guides')
293
- @renderGuide(guide)
294
- this