This article shows how to create an image gallery by using JavaScript and Platform Services in a Web Runtime widget. Since it uses Platform Services, this code works with Web Runtime version 1.1.
Contents
|
In order to use the ImageGallery component in a Web Runtime widget, the following steps are necessary:
<script language="javascript" type="text/javascript" src="ImageGallery.js"></script>
<body>
[...]
<div id="gallery_holder">
</div>
[...]
</body>
The paths of these images are defined in the implementation part of this article, and can be customized as well. Sample images, used in this article, are shown below, and can be downloaded from this link: Media:Wrt_imagegallery_sampleimages.zip
function myImageHandler(imagePath)
{
alert(imagePath);
}
Then, set the previously defined image handler, by setting the imagePickHandler property, and then call the load() method on the ImageGallery instance:
var gallery = new ImageGallery(document.getElementById('gallery_holder'), 300, 400);
gallery.imagePickHandler = myImageHandler;
gallery.load('FileDate', false);
The load() method accepts 2 arguments:
The ImageGallery costructor just defines some properties, and then call an initialization method, init(), that will be defined below.
function ImageGallery(parentElement, galleryWidth, galleryHeight)
{
/* max image size */
this.maxImageHeight = 0;
this.maxImageWidth = 0;
/* DOM elements */
this.imageElement = null;
this.imageLoader = null;
/* library images */
this.libraryImages = null;
this.currentPhotoIndex = -1;
/* image pick handler */
this.imagePickHandler = null;
this.init(parentElement, galleryWidth, galleryHeight);
}
Before proceeding, it's useful to define some properties that will be used for the DOM structure of this component. So, let's define:
ImageGallery.ICONS_HEIGHT = 64;
ImageGallery.PREV_IMAGE_SRC = 'images/arrow_left.png';
ImageGallery.NEXT_IMAGE_SRC = 'images/arrow_right.png';
ImageGallery.PICK_IMAGE_SRC = 'images/pick_image.png';
ImageGallery.IMAGE_LOADER = 'images/ajax-loader.gif';
Done this, it's time to build the DOM structure of the ImageGallery component. The following init() method will do this:
ImageGallery.prototype.init = function(parentElement, galleryWidth, galleryHeight)
{
var self = this;
/* maximum size of gallery images */
this.maxImageHeight = galleryHeight - ImageGallery.ICONS_HEIGHT;
this.maxImageWidth = galleryWidth;
/* main gallery element */
var el = document.createElement('div');
el.style.height = galleryHeight + 'px';
el.style.width = galleryWidth + 'px';
el.className = 'image_gallery';
parentElement.appendChild(el);
/* image element */
var imgContainer = document.createElement('div');
imgContainer.style.textAlign = 'center';
imgContainer.style.overflow = 'hidden';
imgContainer.style.width = this.maxImageWidth + 'px';
imgContainer.style.height = this.maxImageHeight + 'px';
el.appendChild(imgContainer);
/* image loader, to be shown while loading a new image */
var loader = document.createElement('img');
loader.src = ImageGallery.IMAGE_LOADER;
loader.style.display = 'none';
imgContainer.appendChild(loader);
this.imageLoader = loader;
/* image element, will contain the current shown image */
var img = document.createElement('img');
img.style.margin = 'auto';
imgContainer.appendChild(img);
this.imageElement = img;
/* buttonsContainer will contain the buttons used to perform gallery actions */
var buttonsContainer = document.createElement('div');
buttonsContainer.style.textAlign = 'center';
buttonsContainer.className = 'image_gallery_buttons';
el.appendChild(buttonsContainer);
/* button to go to the previous gallery image */
var prevImageButton = document.createElement('img');
prevImageButton.src = ImageGallery.PREV_IMAGE_SRC;
buttonsContainer.appendChild(prevImageButton);
/* button to go to the pick the current gallery image */
var pickImageButton = document.createElement('img');
pickImageButton.src = ImageGallery.PICK_IMAGE_SRC;
buttonsContainer.appendChild(pickImageButton);
/* button to go to the next gallery image */
var nextImageButton = document.createElement('img');
nextImageButton.src = ImageGallery.NEXT_IMAGE_SRC;
buttonsContainer.appendChild(nextImageButton);
}
As seen in the DOM structure, an image loader will be shown while the next (or previous) image is loading from the device gallery. So, let's define 2 methods that will be used to show and hide the image loader:
ImageGallery.prototype.showLoader = function()
{
this.imageLoader.style.display = '';
}
ImageGallery.prototype.hideLoader = function()
{
this.imageLoader.style.display = 'none';
}
WRT 1.1 offers access to device media through the Media Management Service API. The following load() method uses this API to retrieve the images stored in the device's gallery:
ImageGallery.prototype.load = function(sortBy, ascending)
{
if(sortBy == undefined || sortBy == null)
sortBy = 'FileName';
var sortType = ascending ? 'Ascending' : 'Descending';
this.showLoader();
var so = device.getServiceObject("Service.MediaManagement", "IDataSource");
var criteria =
{
'Type': 'FileInfo',
'Filter':
{
'FileType': 'Image'
}
};
var self = this;
var result = so.IDataSource.GetList(
criteria,
function(transId, eventCode, result)
{
self.libraryImagesCallback(transId, eventCode, result);
}
);
if(result.ErrorCode != 0)
{
this.showError(result.ErrorMessage);
}
}
The above code, after having initialized the Service Object, and created the criteria object to be used to retrieve the Image files, call the GetList() method in asynchronous mode, using the libraryImagesCallback() instance method as callback function.
The libraryImagesCallback() will perform these operations:
ImageGallery.prototype.libraryImagesCallback = function(transId, eventCode, result)
{
if(eventCode != 4 && result.ErrorCode == 0)
{
this.libraryImages = new Array();
var iterator = result.ReturnValue;
var item = null;
while((item = iterator.getNext()) != undefined)
{
var imagePath = item.FileNameAndPath.replace(/\\/g, "/");
imagePath = 'file:///' + imagePath;
this.libraryImages.push(imagePath);
}
if(this.libraryImages.length > 0)
{
this.showLibraryImage(0);
}
else
{
this.showError('No images found in device Gallery.');
}
}
else
{
this.showError('Cannot load images from Gallery');
}
}
Error management, for the purposes of this article, is performed by the showError() method, that will uniquely alert the error message passed as argument:
ImageGallery.prototype.showError = function(txt)
{
alert(txt);
}
If the GetList() method of MediaManagement Service API returns at least an image, then the first image is shown, by calling the showLibraryImage() method. This method:
ImageGallery.prototype.showLibraryImage = function(imageIndex)
{
this.imageElement.style.display = 'none';
this.showLoader();
this.currentPhotoIndex = imageIndex;
this.imageElement.style.width = 'auto';
this.imageElement.style.height = 'auto';
this.imageElement.src = this.libraryImages[this.currentPhotoIndex];
}
When the current image has been loaded, it's necessary to show it (because the image element was hidden by the showLibraryImage() method), and to hide the image loader. Also, we want to adjust the image size to fit the available size reserved to the gallery. To do this, it's necessary to be notified when the image has been completely loaded, and this can be done by using the onload event. So, let's take back the init() method and define this event handler:
ImageGallery.prototype.init = function(parentElement, galleryWidth, galleryHeight)
{
[...]
img.onload = function()
{
self.imageLoaded();
};
}
The imageLoaded() is the instance method that will handle the operations defined above, and is implemented as follows:
ImageGallery.prototype.imageLoaded = function()
{
this.hideLoader();
this.imageElement.style.display = '';
var imageWidth = this.imageElement.offsetWidth;
var imageHeight = this.imageElement.offsetHeight;
var widthProp = imageWidth / this.maxImageWidth;
var heightProp = imageHeight / this.maxImageHeight;
var resizeProp = Math.max(widthProp, heightProp);
if(resizeProp > 1)
{
this.imageElement.style.width = (imageWidth / resizeProp) + 'px';
this.imageElement.style.height = (imageHeight / resizeProp) + 'px';
}
}
This method:
Now that the first image is displayed, the user has to be able to navigate to the next ones. To do this, we have to add some behavior to the nextImageButton and prevImageButton defined by the init() method:
ImageGallery.prototype.init = function(parentElement, galleryWidth, galleryHeight)
{
[...]
prevImageButton.onclick = function()
{
self.viewLibraryImage(-1);
};
nextImageButton.onclick = function()
{
self.viewLibraryImage(1);
};
}
Both methods will call the same instance method, viewLibraryImage(), that accepts as argument the index delta of the next photo to be shown. The viewLibraryImage() method can be implemented as follows:
ImageGallery.prototype.viewLibraryImage = function(indexDelta)
{
var newIndex = this.currentPhotoIndex + indexDelta;
if(newIndex >= 0 && newIndex < this.libraryImages.length)
{
this.showLibraryImage(newIndex);
}
}
Finally, the user has to be able to select the current image, and your widget has to be notified of this, in order to perform further operations on it. So, we have previously defined the imagePickHandler property, that holds a reference to a custom handler function that can be freely defined in your code. To call this function, let's add a behavior to the pickImageButton defined in the init() method:
ImageGallery.prototype.init = function(parentElement, galleryWidth, galleryHeight)
{
[...]
pickImageButton.onclick = function()
{
self.chooseLibraryImage();
};
So, on the click event, the pickImageButton will call the chooseLibraryImage() defined as follows:
ImageGallery.prototype.chooseLibraryImage = function()
{
if(this.imagePickHandler != null && this.currentPhotoIndex >= 0)
{
this.imagePickHandler(this.libraryImages[this.currentPhotoIndex]);
}
}
The following resources, related to this article, can be downloaded:
No related wiki articles found