Schneimi’s Dev Weblog


VLC like volume control with ajax slider

Posted in CakePHP,JS by schneimi on March 13, 2008
Tags: , , , ,

I needed a volume control for my site, so I immediately thought of the Ajax slider and easily set up the control. But then I noticed, it looked too much like a timeline and came up with the idea of a VLC like control, where a bar fills up to the selected volume.

After some experiments, I finally managed to get it working, so here is how it works. The idea is to underlay the track and handle of the slider with a volume bar, that is increased and decreased via javascript on slide (on change). For the volume bar beeing visible through the track, the background of the track is set transparent. The handle will not be visible, so you can click everywhere on the track to set the volume, but you are still able to drag it once you clicked in the track.

This is how it looks like in two different states. vlc_volume.png

Here is the HTML/PHP code for the view and the needed CSS and Javascript. I only tested it with Firefox 2.00.12, Opera 9.25 and IE7.

HTML:

<div id="volume_control">
  <div id="vol_track">
    <div id="vol_handle"></div>
  </div>
  <div id="vol_bar"></div>
</div>

<?php echo $ajax->slider('vol_handle',
                         'vol_track',
                         array('range' => '$R(0, 100)',
                               'sliderValue' => 50,
                               'increment' => 1,
                               'onChange' => 'function(vol){setVolume(vol)}',
                               'onSlide' => 'function(vol){setVolume(vol)}'
                              )); ?>

CSS:

div#volume_control {
  width: 50px;
  height: 16px;
  position: relative;
  background-color: #cccccc;
}

div#vol_handle {
  width: 0px;
  height: 16px;
  cursor: pointer;
}

div#vol_track {
  width: 50px;
  height: 16px;
  position: absolute;
  border: 1px inset #fff;
  background-color: transparent;
  cursor: pointer;
  z-index: 2;
}

div#vol_bar {
  width: 25px;
  height: 16px;
  position: absolute;
  background-color: #1743A7;
  z-index: 1;
}

Javascript:

function setVolume(vol) {
  $('vol_bar').style.width = Math.round(vol/2) + 'px';
}
Advertisements

Multiple ajax requests problems and AjaxQueue as solution

Posted in Ajax,CakePHP by schneimi on March 10, 2008
Tags: , , , ,

For my app I had to load many import processes at once by Ajax requests, so I ran into some serious problems.

1. Session data was not available each second request
I used the database option for Sessions, and that seemed to be the problem in this case. Because I don’t worry much about how sessions are saved, I changed it to cake in core.php and it solved this problem, not a really good solution, but I’m fine with it.

2. Timed out Socket connections
During the import process I had to make some Socket Connections and however there suddenly was no connection possible anymore after 10-15 requests, so the following ran into timeout.

3. The solution: AjaxQueue
After some search and search and search, I finally found a script called AjaxQueue posted on a mailing list. There you can set the maximum amout of simultaneous Ajax requests, exactly what I was looking for. After some testing it turned out to do a really wonderful job and all my problems were solved without loosing much of performance.

The following code is for the Prototype framework, but it should be no problem to adapt it to other frameworks in replacing the “Ajax.”-statements to similar ones of another framework.

var AjaxQueue = {
batchSize: 1, //No.of simultaneous AJAX requests allowed, Default : 1
urlQueue: [], //Request URLs will be pushed into this array
elementsQueue: [], //Element IDs of elements to be updated on completion of a request ( as in Ajax.Updater )
optionsQueue: [], //Request options will be pushed into this array
setBatchSize: function(bSize){ //Method to set a different batch size. Recommended: Set batchSize before making requests
this.batchSize = bSize;
},
push: function(url, options, elementID){ //Push the request in the queue. elementID is optional and required only for Ajax.Updater calls
this.urlQueue.push(url);
this.optionsQueue.push(options);
if(elementID!=null){
this.elementsQueue.push(elementID);
} else {
this.elementsQueue.push(“NOTSPECIFIED”);
}

this._processNext();
},
_processNext: function() { // Method for processing the requests in the queue. Private method. Don’t call it explicitly
if(Ajax.activeRequestCount < AjaxQueue.batchSize) // Check if the currently processing request count is less than batch size { if(AjaxQueue.elementsQueue.first()=="NOTSPECIFIED") { //Check if an elementID was specified // Call Ajax.Request if no ElementID specified //Call Ajax.Request on the first item in the queue and remove it from the queue new Ajax.Request(AjaxQueue.urlQueue.shift(), AjaxQueue.optionsQueue.shift()); var junk = AjaxQueue.elementsQueue.shift(); } else { // Call Ajax.Updater if an ElementID was specified. //Call Ajax.Updater on the first item in the queue and remove it from the queue new Ajax.Updater(AjaxQueue.elementsQueue.shift(), AjaxQueue.urlQueue.shift(), AjaxQueue.optionsQueue.shift()); } } } }; Ajax.Responders.register({ //Call AjaxQueue._processNext on completion ( success / failure) of any AJAX call. onComplete: AjaxQueue._processNext }); /************* SYNTAX *************** AjaxQueue.setBatchSize(size); AjaxQueue.push(URL , OPTIONS, [ElementID]); ************** USAGE *************** AjaxQueue.setBatchSize(4); AjaxQueue.push("http://www.testingqueue.com/process/",{onSucess: funcSuccess, onfailure: funcFailure}); AjaxQueue.push("http://www.testingqueue.com/process1/",{onSucess: funcSuccess1, onfailure: funcFailure1}, "myDiv"); AjaxQueue.push("http://www.testingqueue.com/process2/",{onSucess: funcSuccess2, onfailure: funcFailure2}); AjaxQueue.push("http://www.testingqueue.com/process3/",{onSucess: funcSuccess3, onfailure: funcFailure3}); AjaxQueue.push("http://www.testingqueue.com/process4/",{onSucess: funcSuccess4, onfailure: funcFailure4}); AjaxQueue.push("http://www.testingqueue.com/process5/",{onSucess: funcSuccess5, onfailure: funcFailure5}); **********************************/[/sourcecode]