zui53 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +9 -0
- data/LICENSE +20 -0
- data/README.markdown +25 -0
- data/Rakefile +25 -0
- data/build/zui53.js +4014 -0
- data/demos/css_surface.html +30 -0
- data/demos/svg_surface.html +33 -0
- data/lib/assets/javascripts/zui53/.DS_Store +0 -0
- data/lib/assets/javascripts/zui53/helper.js +43 -0
- data/lib/assets/javascripts/zui53/index.js +4 -0
- data/lib/assets/javascripts/zui53/surfaces/css_surface.js.coffee +27 -0
- data/lib/assets/javascripts/zui53/surfaces/svg_surface.js.coffee +16 -0
- data/lib/assets/javascripts/zui53/tools/pan_tool.js.coffee +76 -0
- data/lib/assets/javascripts/zui53/tools/toolset.js.coffee +84 -0
- data/lib/assets/javascripts/zui53/tools/zoom_tool.js.coffee +167 -0
- data/lib/assets/javascripts/zui53/zui53.js.coffee +257 -0
- data/lib/generators/zui53/install_generator.rb +21 -0
- data/lib/zui53.rb +7 -0
- data/vendor/assets/javascripts/jquery.mousewheel.js +78 -0
- data/vendor/assets/javascripts/jquery.transform.js +1961 -0
- data/vendor/assets/javascripts/sylvester.js +1254 -0
- data/zui53.gemspec +20 -0
- metadata +75 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
#= require ./helper
|
2
|
+
#= require ./tools/pan_tool
|
3
|
+
#= require ./tools/zoom_tool
|
4
|
+
#= require ./surfaces/svg_surface
|
5
|
+
#= require ./surfaces/css_surface
|
6
|
+
|
7
|
+
namespace 'ZUI53', (exports)->
|
8
|
+
class exports.Viewport
|
9
|
+
constructor: (vp)->
|
10
|
+
@min_scale = null
|
11
|
+
@max_scale = null
|
12
|
+
|
13
|
+
@viewport = @styleViewport(vp)
|
14
|
+
@surfaces = []
|
15
|
+
|
16
|
+
# Offset Matrix, this should change in future, if viewport HTML-Element changes position
|
17
|
+
@updateOffset()
|
18
|
+
|
19
|
+
@reset()
|
20
|
+
$(vp).scroll (e)=>
|
21
|
+
# If the browser automatically scrolls our viewport, we translate the scroll into a pan and
|
22
|
+
# reset the scroll. Otherwise MouseFocused Zooming and @clientToSurface is broken.
|
23
|
+
# This happens when the user types into a contenteditable element and the carat moves outside
|
24
|
+
# of the viewport.
|
25
|
+
jVP = $(@viewport)
|
26
|
+
@panBy( -jVP.scrollLeft(), -jVP.scrollTop() )
|
27
|
+
jVP.scrollTop(0).scrollLeft(0)
|
28
|
+
|
29
|
+
@toolset = new ZUI53.Tools.Set( new ZUI53.Tools.Zoom(@) )
|
30
|
+
|
31
|
+
styleViewport: (vp)->
|
32
|
+
$(vp).css({
|
33
|
+
'position': 'relative',
|
34
|
+
'overflow': 'hidden',
|
35
|
+
'width': '100%',
|
36
|
+
'height': '100%'
|
37
|
+
})
|
38
|
+
vp
|
39
|
+
|
40
|
+
updateOffset: ()=>
|
41
|
+
@vpOffset = $(@viewport).offset()
|
42
|
+
|
43
|
+
@vpOffset.left -= (Number) $(window.document).scrollLeft()
|
44
|
+
@vpOffset.top -= (Number) $(window.document).scrollTop()
|
45
|
+
|
46
|
+
@vpOffM = $M([
|
47
|
+
[1, 0, @vpOffset.left],
|
48
|
+
[0, 1, @vpOffset.top],
|
49
|
+
[0, 0, 1]
|
50
|
+
])
|
51
|
+
|
52
|
+
return @vpOffM
|
53
|
+
|
54
|
+
reset: ()=>
|
55
|
+
@zoomPos = 0
|
56
|
+
@scale = 1.0
|
57
|
+
# Base Transformation Matrix for Scale/Pan and Point-Calculation
|
58
|
+
@surfaceM = $M([
|
59
|
+
[1, 0, 0],
|
60
|
+
[0, 1, 0],
|
61
|
+
[0, 0, 1]
|
62
|
+
])
|
63
|
+
@updateSurface()
|
64
|
+
|
65
|
+
addSurface: (surface)=>
|
66
|
+
@surfaces.push surface
|
67
|
+
@addLimits(surface.limits())
|
68
|
+
|
69
|
+
removeSurface: (surface)=>
|
70
|
+
i = @surfaces.indexOf(surface)
|
71
|
+
@surfaces.splice(i, 1) if i >= 0
|
72
|
+
|
73
|
+
addLimits: (limits)=>
|
74
|
+
return unless limits
|
75
|
+
if @min_scale || @max_scale
|
76
|
+
@min_scale = Math.max(limits[0], @min_scale) if limits[0]
|
77
|
+
@max_scale = Math.min(limits[1], @max_scale) if limits[1]
|
78
|
+
else
|
79
|
+
@min_scale = limits[0]
|
80
|
+
@max_scale = limits[1]
|
81
|
+
# console.log "LIMITS: #{@min_scale}, #{@max_scale}"
|
82
|
+
|
83
|
+
clientToSurface: (x, y)=>
|
84
|
+
v = $V([x, y, 1])
|
85
|
+
sV = @surfaceM.inverse().multiply( @updateOffset().inverse().multiply(v) )
|
86
|
+
|
87
|
+
layerToSurface: (x, y)=>
|
88
|
+
v = $V([x, y, 1])
|
89
|
+
sV = @surfaceM.inverse().multiply( v )
|
90
|
+
|
91
|
+
surfaceToClient: (v)=>
|
92
|
+
@updateOffset().multiply( @surfaceM.multiply(v) )
|
93
|
+
|
94
|
+
surfaceToLayer: (v)=>
|
95
|
+
@surfaceM.multiply(v)
|
96
|
+
|
97
|
+
updateSurface: ()=>
|
98
|
+
v = @getPanAndScale()
|
99
|
+
for node in @surfaces
|
100
|
+
node.apply(v[0], v[1], v[2])
|
101
|
+
|
102
|
+
return true
|
103
|
+
|
104
|
+
panBy: (x, y)=>
|
105
|
+
@translateSurface(x, y)
|
106
|
+
@updateSurface()
|
107
|
+
|
108
|
+
zoomBy: (byF, clientX, clientY)=>
|
109
|
+
newScale = @_pos_to_scale(@zoomPos + byF)
|
110
|
+
@zoomSet(newScale, clientX, clientY)
|
111
|
+
|
112
|
+
zoomSet: (newScale, clientX, clientY)=>
|
113
|
+
newScale = @fitToLimits(newScale)
|
114
|
+
@zoomPos = @_scale_to_pos(newScale)
|
115
|
+
if newScale != @scale
|
116
|
+
sf = @clientToSurface(clientX, clientY)
|
117
|
+
scaleBy = newScale/@scale
|
118
|
+
|
119
|
+
@surfaceM = @_scaleMatrix(@surfaceM, scaleBy)
|
120
|
+
@scale = newScale
|
121
|
+
|
122
|
+
c = @surfaceToClient(sf)
|
123
|
+
dX = clientX - c.e(1)
|
124
|
+
dY = clientY - c.e(2)
|
125
|
+
@translateSurface(dX, dY)
|
126
|
+
|
127
|
+
@updateSurface()
|
128
|
+
|
129
|
+
# zoomByO: (byF, offsetX, offsetY)=>
|
130
|
+
# # @zoomPos += byF
|
131
|
+
# newScale = @_pos_to_scale(@zoomPos + byF)
|
132
|
+
# @zoomSetO(newScale, offsetX, offsetY)
|
133
|
+
#
|
134
|
+
# zoomSetO: (newScale, offsetX, offsetY)=>
|
135
|
+
# newScale = @fitToLimits(newScale)
|
136
|
+
# @zoomPos = @_scale_to_pos(newScale)
|
137
|
+
# if newScale != @scale
|
138
|
+
# sf = @layerToSurface(offsetX, offsetY)
|
139
|
+
# scaleBy = newScale/@scale
|
140
|
+
#
|
141
|
+
# @surfaceM = @_scaleMatrix(@surfaceM, scaleBy)
|
142
|
+
# @scale = newScale
|
143
|
+
#
|
144
|
+
# c = @surfaceToLayer(sf)
|
145
|
+
# dX = offsetX - c.e(1)
|
146
|
+
# dY = offsetY - c.e(2)
|
147
|
+
# @translateSurface(dX, dY)
|
148
|
+
#
|
149
|
+
# @updateSurface()
|
150
|
+
|
151
|
+
|
152
|
+
fitToLimits: (s)=>
|
153
|
+
# console.log "Try Scale: #{s}"
|
154
|
+
if @min_scale && s < @min_scale
|
155
|
+
s = @min_scale
|
156
|
+
else if @max_scale && s > @max_scale
|
157
|
+
s = @max_scale
|
158
|
+
return s
|
159
|
+
|
160
|
+
translateSurface: (x, y)=>
|
161
|
+
@surfaceM = @_translateMatrix(@surfaceM, x, y)
|
162
|
+
|
163
|
+
_translateMatrix: (m, x, y)->
|
164
|
+
m.add( $M([
|
165
|
+
[0, 0, x],
|
166
|
+
[0, 0, y],
|
167
|
+
[0, 0, 0]
|
168
|
+
]))
|
169
|
+
|
170
|
+
_scaleMatrix: (m, s)->
|
171
|
+
return m.multiply( $M([
|
172
|
+
[s, 0, 0],
|
173
|
+
[0, s, 0],
|
174
|
+
[0, 0, 1]
|
175
|
+
]))
|
176
|
+
|
177
|
+
_pos_to_scale: (pos)->
|
178
|
+
Math.exp(pos)
|
179
|
+
|
180
|
+
_scale_to_pos: (s)->
|
181
|
+
Math.log(s)
|
182
|
+
|
183
|
+
avp: ()=>
|
184
|
+
@updateOffset()
|
185
|
+
min = @clientToSurface(@vpOffset.left, @vpOffset.top)
|
186
|
+
max = @clientToSurface(@vpOffset.left + $(@viewport).width(), @vpOffset.top + $(@viewport).height())
|
187
|
+
|
188
|
+
del = max.subtract(min)
|
189
|
+
|
190
|
+
return {
|
191
|
+
x: min.e(1),
|
192
|
+
y: min.e(2),
|
193
|
+
width: del.e(1),
|
194
|
+
height: del.e(2)
|
195
|
+
}
|
196
|
+
|
197
|
+
_boundsCenter: (b)->
|
198
|
+
return {
|
199
|
+
x: (b.x + b.width/2),
|
200
|
+
y: (b.y + b.height/2)
|
201
|
+
}
|
202
|
+
|
203
|
+
showBounds: (evp)=>
|
204
|
+
if evp.width == 0 or evp.height == 0
|
205
|
+
return
|
206
|
+
|
207
|
+
avp = @avp()
|
208
|
+
s = Math.min(avp.width/evp.width, avp.height/evp.height)
|
209
|
+
|
210
|
+
# Expand
|
211
|
+
exp = 50/s #expand 50px, just a constant at the moment, should be variable
|
212
|
+
evp.x -= exp
|
213
|
+
evp.y -= exp
|
214
|
+
evp.width += 2*exp
|
215
|
+
evp.height += 2*exp
|
216
|
+
s = Math.min(avp.width/evp.width, avp.height/evp.height)
|
217
|
+
|
218
|
+
s = @fitToLimits(s)
|
219
|
+
eC = @_boundsCenter(evp)
|
220
|
+
aC = @_boundsCenter(avp)
|
221
|
+
|
222
|
+
@setPanAndScale(-eC.x*s, -eC.y*s, s)
|
223
|
+
@translateSurface( $(@viewport).width()/2, $(@viewport).height()/2) # Center
|
224
|
+
|
225
|
+
@updateSurface()
|
226
|
+
|
227
|
+
getPanAndScale: ()=>
|
228
|
+
[@surfaceM.e(1, 3), @surfaceM.e(2, 3), @surfaceM.e(1, 1)]
|
229
|
+
|
230
|
+
setPanAndScale: (panX, panY, scale)=>
|
231
|
+
@surfaceM = $M([
|
232
|
+
[1, 0, 0],
|
233
|
+
[0, 1, 0],
|
234
|
+
[0, 0, 1]
|
235
|
+
])
|
236
|
+
|
237
|
+
@translateSurface(panX, panY)
|
238
|
+
@surfaceM = @_scaleMatrix(@surfaceM, scale)
|
239
|
+
@scale = scale
|
240
|
+
@zoomPos = @_scale_to_pos(scale)
|
241
|
+
|
242
|
+
getTransformString: ()=>
|
243
|
+
@getPanAndScale().join(',')
|
244
|
+
|
245
|
+
setTransformString: (str)=>
|
246
|
+
return unless str
|
247
|
+
v = str.split(',')
|
248
|
+
# console.log v.length
|
249
|
+
# return unless v.length == 3
|
250
|
+
panX = (Number) v[0]
|
251
|
+
panY = (Number) v[1]
|
252
|
+
scale = (Number) v[2]
|
253
|
+
@setPanAndScale(panX, panY, scale)
|
254
|
+
@updateSurface()
|
255
|
+
|
256
|
+
|
257
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Zui53
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
desc "Copies zui53 assets"
|
4
|
+
source_root File.expand_path('../../../../build', __FILE__)
|
5
|
+
|
6
|
+
def copy_stylesheets_and_images
|
7
|
+
copy_file "zui53.js", "app/assets/javascripts/zui53.js"
|
8
|
+
|
9
|
+
# ["zui53.js.coffee"].each do |f|
|
10
|
+
# copy_file "javascripts/zui53/#{f}", "app/assets/javascripts/#{f}"
|
11
|
+
# end
|
12
|
+
# copy_file "images/css3buttons/css3-github-buttons-icons.png",
|
13
|
+
# "public/images/css3buttons/css3-github-buttons-icons.png"
|
14
|
+
# copy_file "stylesheets/css3buttons/css3-github-buttons.css",
|
15
|
+
# "public/stylesheets/css3buttons/css3-github-buttons.css"
|
16
|
+
# copy_file "stylesheets/css3buttons/reset.css",
|
17
|
+
# "public/stylesheets/css3buttons/reset.css"
|
18
|
+
# gsub_file "public/stylesheets/css3buttons/css3-github-buttons.css", /url\(css3buttons/, "url(/images/css3buttons"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/zui53.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
|
2
|
+
* Licensed under the MIT License (LICENSE.txt).
|
3
|
+
*
|
4
|
+
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
|
5
|
+
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
|
6
|
+
* Thanks to: Seamus Leahy for adding deltaX and deltaY
|
7
|
+
*
|
8
|
+
* Version: 3.0.4
|
9
|
+
*
|
10
|
+
* Requires: 1.2.2+
|
11
|
+
*/
|
12
|
+
|
13
|
+
(function($) {
|
14
|
+
|
15
|
+
var types = ['DOMMouseScroll', 'mousewheel'];
|
16
|
+
|
17
|
+
$.event.special.mousewheel = {
|
18
|
+
setup: function() {
|
19
|
+
if ( this.addEventListener ) {
|
20
|
+
for ( var i=types.length; i; ) {
|
21
|
+
this.addEventListener( types[--i], handler, false );
|
22
|
+
}
|
23
|
+
} else {
|
24
|
+
this.onmousewheel = handler;
|
25
|
+
}
|
26
|
+
},
|
27
|
+
|
28
|
+
teardown: function() {
|
29
|
+
if ( this.removeEventListener ) {
|
30
|
+
for ( var i=types.length; i; ) {
|
31
|
+
this.removeEventListener( types[--i], handler, false );
|
32
|
+
}
|
33
|
+
} else {
|
34
|
+
this.onmousewheel = null;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
};
|
38
|
+
|
39
|
+
$.fn.extend({
|
40
|
+
mousewheel: function(fn) {
|
41
|
+
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
|
42
|
+
},
|
43
|
+
|
44
|
+
unmousewheel: function(fn) {
|
45
|
+
return this.unbind("mousewheel", fn);
|
46
|
+
}
|
47
|
+
});
|
48
|
+
|
49
|
+
|
50
|
+
function handler(event) {
|
51
|
+
var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
|
52
|
+
event = $.event.fix(orgEvent);
|
53
|
+
event.type = "mousewheel";
|
54
|
+
|
55
|
+
// Old school scrollwheel delta
|
56
|
+
if ( event.wheelDelta ) { delta = event.wheelDelta/120; }
|
57
|
+
if ( event.detail ) { delta = -event.detail/3; }
|
58
|
+
|
59
|
+
// New school multidimensional scroll (touchpads) deltas
|
60
|
+
deltaY = delta;
|
61
|
+
|
62
|
+
// Gecko
|
63
|
+
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
|
64
|
+
deltaY = 0;
|
65
|
+
deltaX = -1*delta;
|
66
|
+
}
|
67
|
+
|
68
|
+
// Webkit
|
69
|
+
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
|
70
|
+
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
|
71
|
+
|
72
|
+
// Add event and delta to the front of the arguments
|
73
|
+
args.unshift(event, delta, deltaX, deltaY);
|
74
|
+
|
75
|
+
return $.event.handle.apply(this, args);
|
76
|
+
}
|
77
|
+
|
78
|
+
})(jQuery);
|