-
Notifications
You must be signed in to change notification settings - Fork 2
/
snaptut-create-slider-knob.html
222 lines (171 loc) · 8.63 KB
/
snaptut-create-slider-knob.html
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<!DOCTYPE html>
<html>
<head>
<title>Snap.svg Tutorial</title>
<script src="analytics.js" async></script>
</head>
<body>
<link href="/snapstyle.css" rel="stylesheet">
<div id="container"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script src="snap.svg.js"></script>
<a href="http://snapsvg.io/docs/">Snap Docs</a> <a href="/">More SVG Dabbles</a> <a href="/">Contact Me</a>
<article>
<h1 class="heading">Playing with sliders and knobs</h1>
<div class="intro">Just as an experiment, I thought sliders may work well with SVG & Snap. Graphics are just using existing clipart to test.</div>
<div class="intro">Note, there is a bug on knobs if zoomed/scrolled in browser, so this is currently only a work in progress</div>
<pre class="codestuff"><code contenteditable="true">
(function() {
Snap.plugin( function( Snap, Element, Paper, global ) {
var startDragTarget, startDragElement, startBBox, startScreenCTM;
// Initialise our slider with its basic transform and drag funcs
Element.prototype.initSlider = function( params ) {
var emptyFunc = function() {};
this.data('origTransform', this.transform().local );
this.data('onDragEndFunc', params.onDragEndFunc || emptyFunc );
this.data('onDragFunc', params.onDragFunc || emptyFunc );
this.data('onDragStartFunc', params.onDragStartFunc || emptyFunc );
}
// initialise the params, and set up our max and min. Check if its a slider or knob to see how we deal
Element.prototype.sliderAnyAngle = function( params ) {
this.initSlider( params );
this.data("maxPosX", params.max); this.data("minPosX", params.min);
this.data("centerOffsetX", params.centerOffsetX); this.data("centerOffsetY", params.centerOffsetY)
this.data("posX", params.min);
if( params.type == 'knob' ) {
this.drag( moveDragKnob, startDrag, endDrag );
} else {
this.drag( moveDragSlider, startDrag, endDrag );
}
}
// load in the slider svg file, and transform the group element according to our params earlier.
// Also choose which id is the cap
Paper.prototype.slider = function( params ) {
var myPaper = this, myGroup;
var loaded = Snap.load( params.filename, function( frag ) {
myGroup = myPaper.group().add( frag );
myGroup.transform("t" + params.x + "," + params.y);
var myCap = myGroup.select( params.capSelector );
myCap.data("sliderId", params.sliderId);
myCap.sliderAnyAngle( params );
sliderSetAttributes( myGroup, params.attr );
sliderSetAttributes( myCap, params.capattr );
} );
return myGroup;
}
// Extra func, to pass through extra attributes passed when creating the slider
function sliderSetAttributes ( myGroup, attr, data ) {
var myObj = {};
if( typeof attr != 'undefined' ) {
for( var prop in attr ) {
myObj[ prop ] = attr[prop];
myGroup.attr( myObj );
myObj = {};
};
};
};
// Our main slider startDrag, store our initial matrix settings.
var startDrag = function( x, y, ev ) {
startDragTarget = ev.target;
if( ! ( this.data("startBBox") ) ) {
this.data("startBBox", this.getBBox());
this.data("startScreenCTM",startDragTarget.getScreenCTM());
}
this.data('origPosX', this.data("posX") ); this.data('origPosY', this.data("posY") );
this.data("onDragStartFunc")();
}
// move the cap, our dx/dy will need to be transformed to element matrx. Test for min/max
// set a value 'fracX' which is a fraction of amount moved 0-1 we can use later.
function updateMovement( el, dx, dy ) {
// Below relies on parent being the file svg element, 9
var snapInvMatrix = el.parent().transform().globalMatrix.invert();
snapInvMatrix.e = snapInvMatrix.f = 0;
var tdx = snapInvMatrix.x( dx,dy ), tdy = snapInvMatrix.y( dx,dy );
el.data("posX", +el.data("origPosX") + tdx) ; el.data("posY", +el.data("origPosY") + tdy);
var posX = +el.data("posX"); //var posY = +el.data("posY");
var maxPosX = +el.data("maxPosX");
var minPosX = +el.data("minPosX");
if( posX > maxPosX ) { el.data("posX", maxPosX ); };
if( posX < minPosX ) { el.data("posX", minPosX ); };
el.data("fracX", 1/ ( (maxPosX - minPosX) / el.data("posX") ) );
}
// Call the matrix checks above, and set any transformation
function moveDragSlider( dx,dy ) {
var posX;
updateMovement( this, dx, dy );
posX = this.data("posX");
this.attr({ transform: this.data("origTransform") + (posX ? "T" : "t") + [posX,0] });
this.data("onDragFunc")(this);
};
// drag our knob. Currently there is no min/max working, need to add a case for testing rotating anticlockwise beyond 0
function moveDragKnob( dx,dy,x,y, ev ) {
var pnt = startDragTarget.ownerSVGElement.createSVGPoint();
pnt.x = ev.clientX; pnt.y = ev.clientY;
var vPnt = pnt.matrixTransform(this.data("startScreenCTM").inverse());
var transformRequestObj = startDragTarget.ownerSVGElement.createSVGTransform();
var deg = Math.atan2(vPnt.x - this.data("startBBox").cx, vPnt.y - this.data("startBBox").cy) * 180 / Math.PI ;
deg = deg + 180;
// this.transform('r' + -deg + "," + ( this.data("startBBox").cx - 4 ) + "," + parseInt(this.data("startBBox").cy - -8) );
this.transform('r' + -deg + "," + ( this.data("startBBox").cx - this.data("centerOffsetX") ) + "," + parseInt(this.data("startBBox").cy - -this.data("centerOffsetY") ) );
this.data("fracX", deg/360);
this.data("onDragFunc")(this);
}
function endDrag() {
this.data('onDragEndFunc')();
};
});
})();
//// Test code using the above funcs...
//http://jsfiddle.net/Ge8Eu/
var s = Snap("#svgout");
var myDragEndFunc = function( el ) {
}
var myDragStartFunc = function() {
}
// what we want to do when the slider changes. They could have separate funcs as the call back or just pick the right element
var myDragFunc = function( el ) {
if( el.data("sliderId") == "slider1" ) { meter1.attr({ height: el.data("fracX") * 200 }); }
if( el.data("sliderId") == "slider2" ) { meter2.attr({ height: el.data("fracX") * 200 }); }
if( el.data("sliderId") == "slider3" ) { meter3.attr({ height: el.data("fracX") * 200 }); }
if( el.data("sliderId") == "slider4" ) { meter4.attr({ height: el.data("fracX") * 200 }); }
if( el.data("sliderId") == "knob1" ) { meter5.attr({ height: el.data("fracX") * 200 }); }
}
// just some shapes/data we will move when the knob or slider moves
var meter1 = s.rect( 300,300,50,5 ).attr({ fill: "yellow", stroke: "black", strokeWidth: 2 }).transform('r180');
var meter2 = s.rect( 250,300,50,5 ).attr({ fill: "blue", stroke: "black", strokeWidth: 2 }).transform('r180');
var meter3 = s.rect( 350,300,50,5 ).attr({ fill: "green", stroke: "black", strokeWidth: 2 }).transform('r180');
var meter4 = s.rect( 400,300,50,5 ).attr({ fill: "red", stroke: "black", strokeWidth: 2 }).transform('r180');
var meter5 = s.rect( 450,300,50,5 ).attr({ fill: "silver", stroke: "black", strokeWidth: 2 }).transform('r180');
//create our sliders
var slider1 = s.slider({ sliderId: "slider1", capSelector: "#cap", filename: "paw.svg",
x: "40", y:"240", min: "0", max: "800",
onDragEndFunc: myDragEndFunc, onDragStartFunc: myDragStartFunc, onDragFunc: myDragFunc,
attr: { transform: 's0.4t-100,-300' } } );
var slider2 = s.slider({ sliderId: "slider2", capSelector: "#cap", filename: "slider2.svg",
x: "40", y:"200", min: "0", max: "400",
onDragEndFunc: myDragEndFunc, onDragStartFunc: myDragStartFunc, onDragFunc: myDragFunc } );
var sliderOnAngle = s.slider({ sliderId: "slider3", capSelector: "#cap", filename: "slider2.svg",
x: "140", y:"150", min: "0", max: "400",
onDragEndFunc: myDragEndFunc, onDragStartFunc: myDragStartFunc, onDragFunc: myDragFunc,
attr: { transform: 't150,150r45' } });
var sliderInverted = s.slider({ sliderId: "slider4", capSelector: "#cap", filename: "slider2.svg",
x: "200", y:"200", min: "0", max: "400",
onDragEndFunc: myDragEndFunc, onDragStartFunc: myDragStartFunc, onDragFunc: myDragFunc,
attr: { transform: 't50,150r180' } });
var knob = s.slider({ sliderId: "knob1", type: "knob", capSelector: "#cap", filename: "knob1.svg",
x: "140", y:"50", min: "30", max: "340", centerOffsetX: "4", centerOffsetY: "8",
onDragEndFunc: myDragEndFunc, onDragStartFunc: myDragStartFunc, onDragFunc: myDragFunc,
attr: { transform: 's0.3' } });// , capattr: { transform: 't0,0' } });
</code>
<button class="run">Edit/Run</button>
</pre>
</article>
<div class="intro">SVGout area...</div>
<div class="output">
<svg id="svgout" width="400" height="400"></svg>
</div>
<div class="intro">The actual svg markup looks like this (when you've clicked on run)....</div>
<div id="htmlraw"></div>
<script src="snaptut.js"></script></script>
<script src="hijs.js"></script>
</body>