Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-calendars-jquery-13-php-using-jquery-week-calendar-plugin-part-2
Packt
19 Nov 2009
9 min read
Save for later

Calendars in jQuery 1.3 with PHP using jQuery Week Calendar Plugin: Part 2

Packt
19 Nov 2009
9 min read
Deleting events After creating, moving, and editing events, we might come across a case where the edit form is different from the create form. There is no reason why you would want to delete an event that has not yet been created, so there is no reason to add a delete button to the "Create Event" form. We have a choice—add the delete button to the section at the bottom of the modal dialog, next to Save and Cancel, or add it to the body of the form itself. I always try to add delete buttons and links where I think they cannot be hit by accident. Therefore in this case, I chose not to add it to the row of buttons at the bottom. Instead, I placed it in the form itself where there's little chance it will be clicked by accident while saving or closing the form. And even then, if the link is clicked, there is always a secondary "Are you sure?" confirmation box. Client-side code In the calendar_edit_entry function in calender.js, change the beginning of the $.getJSON call to this: $.getJSON('./calendar.php?action=get_event&id='+calEvent.id, function(eventdata){ var controls='<a href="javascript:calendar_delete_entry' +'('+eventdata.id+');">[delete]</a>'; $('<div id="calendar_edit_entry_form" title="Edit Calendar Entry">' +'<div style="float:right;text-align:right">'+controls+'</div>' +'event name<br />' +'<input id="calendar_edit_entry_form_title" value="'+eventdata.title+'" /><br />' +'body text<br />' +'<textarea style="width:400px;height:200px" id="calendar_edit_entry_form_body">' '+eventdata.body+'</textarea></div>' ).appendTo($('body')); $("#calendar_edit_entry_form").dialog({ The only real change is to add the controls variable, which lets us create more buttons if necessary, and add that variable's contained HTML to the form. The only control there at the moment is a delete link, which calls the calendar_delete_entry function when clicked. Add this function now: function calendar_delete_entry(id){ if(confirm('are you sure you want to delete this entry?')){ $('#calendar_edit_entry_form').remove(); $.getJSON('./calendar.php?action=delete_event&id='+id, function(ret){ $('#calendar_wrapper').weekCalendar('refresh'); } ); } } Server-side code On the server side, we add a case to handle deletes: case 'delete_event': // { $id=(int)$_REQUEST['id']; unset($_SESSION['calendar'][$id]); echo 1; exit; // } All it needs to do is to unset the session variable. With that completed, you now have the finished basics of a calendar, where you can create events, move them around, edit them, and delete them. Walk-through of the calendar so far We've built the basics of a weekly calendar, and before we go on to discuss recurring events, let's take the time to walk through the calendar so far with a simple example. Let's say you have an appointment on Tuesday at 2 pm with a business partner. You add that by clicking on that time, as follows: You think that the meeting will go on for about two hours, so you resize it: Now Bob calls up early on Tuesday to say that he's not going to be able to make it, and suggests moving it to Wednesday at 1 pm. You drag the event over: He also says that he won't be able to make it, but Sally would be there. So, you click on the event and edit the form accordingly: Wednesday comes, and of course, something has come up on your end. You call Sally and explain that you won't be able to make it, and delete the event by clicking on the event, and then clicking on the delete link. Simple and quick. What more would you want? Let's do some recurring events. Recurring events Sometimes you will want to have the same event automatically populated in the calendar on a recurrent basis. For example, you go to lunch every day at 1 pm, or there might be a weekly office meeting every Monday morning. In this case, we need to come up with a way of having events recur. This can be simple or very complex. The simplest method is what we'll demonstrate in this article. The simple method involves entering a frequency (daily, monthly, and so on) and a final date, where the events stop recurring. On the server side, when it is asked to create that recurring event, the server actually iterates over the entire requested period and adds each individual event. This is not extremely efficient, but it's simple to write, and it's not likely that anyone would be placing years-long recurrent events on a very regular basis, so it's justifiable. The more complex method is to only create events that are actually visible in the week you are viewing, and whenever you change the week, you check to see if there are any events that are supposed to recur that week but are not visible. This is arguably even less efficient than the simple method, but it would allow us to be a little more flexible—for example, to leave out the final date so that the events just keep recurring. Anyway, given that there are no major drawbacks to either method, we will choose the simpler method. Client-side code On the client side, recurrences are created at the same time as the recurrence of the first event. So, we edit the "Create Event" form. In calendar.js , adapt the calendar_new_entry function by replacing the form-creation line with this: var recurbox='<select id="calendar_new_entry_form_recurring">' +'<option value="0">non-recurring</option>' +'<option value="1">Daily</option>' +'<option value="7">Weekly</option>' +'</select>';$('<div id="calendar_new_entry_form" title="New Calendar Entry">event name<br />' +'<input value="new event" id="calendar_new_entry_form_title" /><br />' +'body text<br />' +'<textarea style="width:400px;height:200px" id="calendar_new_entry_form_body">' event description</textarea>' +recurbox+'</div>') .appendTo($('body')); $('#calendar_new_entry_form_recurring') .change(calendar_new_get_recurring_end); This adds a select box below the body text area, requesting the user to choose a recurring frequency (defaulting to non-recurring). When the select box is changed, the function calendar_new_get_recurring_end is called. This function is used to request the final recurring date. We could use a plain old text field, but jQuery UI includes a really cool date widget, which allows us to request the date and have it stored in our own choice of format. I've chosen yyyy-mm-dd format, as it is easy to manipulate. Add this to calendar.js: function calendar_new_get_recurring_end(){ if(document.getElementById('calendar_new_recurring_end')) return; var year = new Date().getFullYear(); var month = new Date().getMonth(); var day = new Date().getDate(); $('<span> until <input id="calendar_new_recurring_end" value="'+year+'-'+(month+1)+'-'+day+'" style="font-size:14px" class="date" />' +' </span>' ).insertAfter('#calendar_new_entry_form_recurring'); $('.date').datepicker({ 'dateFormat':'yy-mm-dd', 'yearRange':'-10:+50', 'changeYear':true }); } That creates an input field after the dropdown box, and when it is clicked, a calendar pops up: Whoops! What's happened here is that the date pop up's z-index is lower than the modal dialog. That can be corrected by adding this CSS line to the  < head > section of calendar.html: <style type="text/css"> #ui-datepicker-div{ z-index: 2000; }</style> When reloaded, the calendar now looks correct: Great! Now, we just need to send the data to the server. To do that, change the Save button's $.getJSON parameters in the calendar_new_entry function in calendar.js to these (new parameters are highlighted): 'body':$('#calendar_new_entry_form_body').val(), 'title':$('#calendar_new_entry_form_title').val(), 'recurring':$('#calendar_new_entry_form_recurring').val(), 'recurring_end':$('#calendar_new_recurring_end').val() And we're done on the client side. Server-side code On the server side, the save switch case is going to change considerably, so I'll provide the entire section: case 'save': // { $start_date=(int)$_REQUEST['start']; $data=array( 'title'=>$_REQUEST['title'], 'body' =>$_REQUEST['body'], 'start'=>date('c',$start_date), 'end' =>date('c',(int)$_REQUEST['end']) ); $id=(int)$_REQUEST['id']; if($id && isset($_SESSION['calendar'][$id])){ if(isset($_SESSION['calendar'][$id]['recurring'])) $data['recurring']=$_SESSION['calendar'][$id]['recurring']; $_SESSION['calendar'][$id]=$data; } else{ $id=++$_SESSION['calendar']['ids']; $rec=(int)$_REQUEST['recurring']; if($rec) $data['recurring']=$id; $_SESSION['calendar'][$id]=$data; if($rec && $rec==1 || $rec==7){ list($y,$m,$d)=explode('-',$_REQUEST['recurring_end']); $length=(int)$_REQUEST['end']-$start_date; $end_date=mktime(23,59,59,$m,$d,$y); $step=3600*24*$rec; for($j=1,$i=$start_date+$step;$i<$end_date;$j++,$i+=$step){ $data['start']=date('c',$i); $data['end']=date('c',$i+$length); $nextid=++$_SESSION['calendar']['ids']; $_SESSION['calendar'][$nextid]=$data; } } } echo 1; exit; // } OK. From the data point of view, we've added a single field, recurring, which records the first event in the series. This is needed when deleting recurring events that are not needed anymore. When editing an existing event, all that's changed is that the recurring field (if it exists) is copied from the original before the event is overwritten with fresh data (shown highlighted). The real action happens when creating a new event. If a recurring period is required, then the event is copied and pasted at the requested frequency from the event's first creation until the expiry date. This is figured out by counting the seconds, and incrementing as needed. We can immediately see that recurring events work. Here's an example of a week's lunch hours created from the new recurring method: You can shift individual events around, and even delete them, without affecting the rest.
Read more
  • 0
  • 0
  • 15424

article-image-managing-images-and-videos-joomla-15-part-1
Packt
19 Nov 2009
9 min read
Save for later

Managing Images and Videos in Joomla! 1.5: Part 1

Packt
19 Nov 2009
9 min read
Media Manager As its name suggests, the Media Manager is the place to keep track of and organize all your media files within folders and subfolders. You can use it to upload files, delete old material, or create new folders. Accessing and using the Media Manager The interface within the Media Manager is graphical and similar to other file explorer programs you will have definitely used within a Windows environment. Like any of the sections of the administration control panel, you can access the Media Manager either by: Clicking Site | Media Manager from the top menu Clicking the Media Manager icon on the Control Panel You can switch your view of the files within the Media Manager to suit your preference, as both provide the same level of functionality: Click Thumbnail View to see small graphic versions of your files, handy when you want to find an image Click Detail View to see the names of your files along with the dimensions and sizes The following screenshot illustrates the use of the thumbnail view: The Folders section to the left of the Media Manager interface displays the site folders. Click one to open and reveal any subfolders within it. Within your site there will most likely be a subfolder within the images folder called stories, that is, images | stories. This is generally where the site images will have been placed and is where the Image Upload button defaults to when you add an image to an Article. You can also create new folders in here to store additional media. Using the Party People website, we have created a new article and now need to add an image that doesn't fit in with the established folder structure. Creating a new subfolder It may be that after adding a new Section and/or Category, none of the existing image folder structures apply. Here we'll create a new subfolder called glassware to accommodate the new material: Navigate to the Media Manager through the top menu or by clicking the Media Manager icon on the home page of the Control Panel. Click on the stories folder in the Media Manager. Note that the Media Manager opens directly into the images folder (this is set in the Global Configuration area and can be changed if necessary). Type in glassware as the name of the new folder and click the Create Folder button. The new subfolder will appear instantly. Now that we have the new glassware subfolder we can upload a new image to store in it using the Upload File tool. A note on copyright While you may have your own images and videos to use on your website, if you are considering using another artist's material and content, always ensure you have copyright permission or the license to do so in order to avoid breach of any copyright laws. You should refer to your local authority for full details. Many website developers and owners regularly purchase and use stock photography, illustrations, and videos. If you choose to purchase any material for your site, ensure you are purchasing it with the right license, as there may be restrictions on its use even after paying for the material. This may, in fact, be a license fee and not a transfer of complete ownership. Sites such as http://www.istockphoto.com/license.php have a page dedicated to licensing agreements around purchasing their material. What you should know about image and video files Have you ever visited a website where a large image takes forever to download? Or the video takes forever to start playing? Chances are that you gave up and left the site. While it doesn't happen quite so much now, take care to avoid this wherever possible. As a general rule, the larger the file size, the longer it takes to download into the browser, and not all users of your website may have fast download speeds. To ensure your images are downloaded as quickly as possible, ensure your files are formatted and compressed into as low a resolution version as possible (without losing the quality) and the dimensions of the videos displayed kept to minimum viewing sizes. There is a trade-off between quality of the image and download speed; compromise is the key here. Audio, video, and animation files can be referred to collectively as multimedia, especially when they are combined within a project. Choosing the best image file format Images come in a variety of file formats and some are smaller in size than others. There are other image file formats, but the following are often used within websites: .jpg files are great for highly detailed images such as photographs. As a result, their file size is generally bigger due to the amount of information they require to present the detail. .gif files are suited to images requiring less detail, such as drawings or diagrams, and are smaller in file size as a result. .png files are similar to .gif files, as they are also low resolution images. They often have a transparent background so you can place them over a colored background and the color will appear behind the image. Remember the following when applying images to your website: Use images with a purpose—to enhance or illustrate your content. Keep file sizes as small as possible. Consider a .gif rather than a .jpg if the image isn't a particularly detailed one. Use photo editing software to reduce the resolution of your image to 72dpi for fastest download time. Anything higher is pointless, as computer monitors only present a certain number of colors and drop the excess. If you don't have access to software such as Photoshop, there are a number of free possibilities. One is a program called GIMP (http://www.gimp.org). It's a free program that allows you to retouch photos and create and edit images. The website has tutorials as well. Adding and managing images Having covered editing and adding text to an article, updating and/or adding new images or other media to your articles is easy too. In this section, we'll work on adding and deleting images and cover some general information on how they can work best for your site. Uploading a new image The File Upload tool within the Media Manager makes it easy to move your images from your computer into your website folders. Select the new glassware subfolder within the Folders structure. This places us in that folder. Click the Browse button under the Upload File section. Navigate to the image file in the pop-up window and click Open. Click the Start Upload button back in the Media Manager. Now we have an image within the glassware folder, it's ready to be used within anarticle. Note that the following screenshot presents the Details View. Deleting an image You might find that as your website consumes more space on the server, you may have to delete some image files. However, be careful doing this, as you don't get a warning! Ensure your site does not require the image anymore, as you will end up with a blank area with a red square in it where the image should be, and that looks unprofessional. Using Thumbnail View within the Media Manager, select the checkbox under the image thumbnail or next to the filename. Click the red "x" icon next to it in order to immediately delete that file, as shown in the following screenshot. You can also use the Delete button in the contextual toolbar at the top right. Updating a Simple Image Gallery Rather than a single image, you might have an article with a Simple Image Gallery embedded within it that presents a selection of thumbnail images to the browser through the article. The gallery plugin parameters can be accessed through the Extensions | Plugins menu along the top of the administration interface. The following screenshot is an example of how one looks on the Party People website. Using the Party People website, we'll update this New Balloons in Stock Now! gallery applying the Balloons folder we made earlier. However, remember that the authors of this plugin recommend only 16 to 20 images per gallery. Navigate to the Media Manager and to the balloons folder. Upload the additional images to the balloons folder using the File Upload tool as outlined in the Uploading a file section of this article. Delete any outdated images, if necessary, by selecting them and clicking the Delete button, as outlined in the Deleting a File section of this article. To display the new images from a different folder in the article, we will need to access the article through which the gallery is presented: Navigate to the Article Manager and open the article containing the gallery of images. You will see something like the following code within the Article's text editor: {gallery}galleryNameIsHere{/gallery} Change this to balloons as in the folder where the balloon images are kept. The following screenshot illustrates the code snippet where you should change the folder name. Apply your changes and review them before going live. Changing the Simple Image Gallery's dimensions If the dimensions of the image gallery, such as the height and width, need to be changed, there are the following steps: Navigate to the Extensions menu using the global menu at the top of the screen. Select Plugin Manager from the drop-down list and navigate through the list until you see the Simple Image Gallery Plugin link in the list. To make this quicker, use the Select Type filter and choose Content. Ensure this plugin is enabled in the Plugin Manager. Click the link to view the parameters for this plug-in; change them as you like. Note that your developer may have changed the name of the module when it was installed. >> Continue Reading Managing Images and Videos in Joomla! 1.5: Part 2 [ 1 | 2 ]  
Read more
  • 0
  • 0
  • 1687

article-image-how-get-incoming-links-joomla-15-seo-part-1
Packt
19 Nov 2009
6 min read
Save for later

How to get Incoming Links in Joomla! 1.5 SEO: Part 1

Packt
19 Nov 2009
6 min read
Do you want to use paid incoming links? Paying for incoming links can be a tricky business if you do it the wrong way. Google doesn't like web sites that use this link building technique and their representative master anti-spam spokesman, Matt Cutts is very clear on this subject. Buy links and get penalized… sell links and get penalized as well The major penalty is a very likely drop in Page Rank. Although Page Rank is becoming less important as compared to your rankings on the search engine result pages, people still see it as a quality making if you do have a high Page Rank. Of course using AdWords to do a "Pay Per Click" campaign is also a form of paid links. If you want to use the sponsored link options to get your site started, that is fine, but the ultimate goal of this article is to get higher rankings in the organic results of the search engines. Studies support the idea of using sponsored links to bring in more traffic from the organic searchers even after the campaign has stopped. It depends on how hard you need the traffic to your site for business, or if you want to go for organic results. Helping people helps you with link building If you have a topic that you are passionate about and you build a web site about it, then this option is one for you. Find a forum that matches the topic of your web site and start helping other people with your knowledge. On most forums there is a possibility to have your own "Signature", where you can have one or more lines of text with a link that people can click on. For instance, the site http://forums.digitalpoint.com has a lot of requests for information on Joomla! where you can help people to solve their problems. After a number of replies to questions, you can put in your own signature such as:   The links you put in there will not only bring traffic from your posts, but they also count as incoming links for Google. Not all forums have the same rules—for example, some of them have a rule that you can put a link to your site, but it should be the URL only without your main keywords in the link. So, be sure to go to the best forums you can find on your topic and start helping others with your knowledge. In the meantime, work on your incoming links as well. Commenting done the right way Another option you have is to look for blogs about your web site's topic. You will already probably know the most useful ones in your field of expertise. Go to those blogs and read some of the posts they have published. If you are lucky, there will be some kind of widget that shows you how many readers they have on that blog for their RSS Feed or email system. Large numbers are a good sign as that means a lot of people will read the blog and it probably has a good ranking in Google. Read the posts that are relevant to your topic and if you can, write a comment which shows that you know more about the topic. Also, if possible, make a new suggestion or correct an error in the article. Don't write comments such as "I really liked this post", "Thank you for this information", or even "I really like your blog". If you write comments such as those you won't get any interaction with the blogger in question and you don't add value to the discussion. Such comments will get deleted or labeled as spam. When I get comment links such as these, I remove them as they add null to zero information for other visitors and they are clearly there just for link building. It won't work that way, and if you are outsourcing or want to outsource this kind of link building, here is a warning, make sure you state in your contract with these people that blog and comment spamming is not allowed! If you don't add that clause, they may start commenting in your name, linking to your site (well, you paid them to do that…) with the same remarks over and over again. What happens next is that bloggers will ban you from commenting on their blogs, and in the worst case scenario you will loose a lot of credibility in your community. People are sometimes better informed than you think and a mistake like the one mentioned above will cost you more than money alone. So, if you start commenting, ask yourself: Do I have something of value to add to the conversation? Will people read that comment? How effective will this blog be in sending me traffic? Keep those in mind, with more emphasis on the first point, and you will do fine. Finding places to comment As I said before, commenting is a great way to create your own incoming links. But how do you find more relevant blogs to read and comment on? First of all, do a search for blogs about your web site's topic. You can use http://blogsearch.google.com/ to find the most recent blog posts and see if the blogs it finds fit your web site's topic.   Technorati is of course the best place to look for blogs.   Go ahead and use the option search the blogosphere.... From the results of this initial search, you can filter based on several options. In the first selection list you will find options such as Search Posts, Search Blogs, Search Photos, and Seach Videos. The second selection list allows you to filter based on entire post or just tags. The third option is the one you really need to set and there you can choose to filter on a lot of authority.   This option means a lot of people are linking to that web site/blog and it will probably get lots of traffic and do well in the search engines. Those blogs are the ones you want your voice to be heard on and remember if you are going to comment, make sure it is a useful one. What you need to do after finding the blog, is to really check out the site. In some cases there might just be one post about your web site's topic on that blog. And you really want it to be on topic all the way!   Two other blog search services you can use are: http://www.icerocket.com http://www.blogpulse.com Both are set up to bring to you the most recent results like Google does but they have something extra. You can learn about trends as Icerocket has a trend tool and Blogpulse has its trend search option. Using those trend tools will give you more insight on which terms are "hot" at the moment and growing. If you combine that with the blogs you just found, for your keywords, you could have a winning team.
Read more
  • 0
  • 0
  • 1849

article-image-advanced-matplotlib-part-2
Packt
19 Nov 2009
10 min read
Save for later

Advanced Matplotlib: Part 2

Packt
19 Nov 2009
10 min read
Plotting dates Sooner or later, we all have had the need to plot some information over time, be it for the bank account balance each month, the total web site accesses for each day of the year, or one of many other reasons. Matplotlib has a plotting function ad hoc for dates, plot_date() that considers data on X, Y, or both axes, as dates, labeling the axis accordingly. As usual, we now present an example, and we will discuss it later: In [1]: import matplotlib as mplIn [2]: import matplotlib.pyplot as pltIn [3]: import numpy as npIn [4]: import datetime as dtIn [5]: dates = [dt.datetime.today() + dt.timedelta(days=i) ...: for i in range(10)]In [6]: values = np.random.rand(len(dates))In [7]: plt.plot_date(mpl.dates.date2num(dates), values, linestyle='-');In [8]: plt.show() First, a note about linestyle keyword argument: without it, there's no line connecting the markers that are displayed alone. We  created  the dates array using timedelta(), a datetime function that helps us define a date interval—10 days in this case. Note how we had to convert our date values using the date2num() function. This is because Matplotlib represents dates as float values corresponding to the number of days since 0001-01-01 UTC. Also note how the X-axis labels, the ones that have data values, are badly rendered. Matplotlib provides ways to address the previous two points—date formatting and conversion, and axes formatting. Date formatting Commonly, in Python programs, dates are represented as datetime objects, so we have to first convert other data values into datetime objects, sometimes by using the dateutil companion module, for example: import datetimedate = datetime.datetime(2009, 03, 28, 11, 34, 59, 12345) or import dateutil.parserdatestrings = ['2008-07-18 14:36:53.494013','2008-07-20 14:37:01.508990', '2008-07-28 14:49:26.183256']dates = [dateutil.parser.parse(s) for s in datestrings] Once we have the datetime objects, in order to let Matplotlib use them, we have to convert them into floating point numbers that represent the number of days since 0001-01-01 00:00:00 UTC. To do that, Matplotlib itself provides several helper functions contained in the matplotlib.dates module: date2num():  This function converts one or a sequence of datetime objects to float values representing days since 0001-01-01 00:00:00 UTC (the fractional parts represent hours, minutes, and seconds) num2date():  This function converts one or a sequence of float values representing days since 0001-01-01 00:00:00 UTC to datetime objects (or a sequence, if the input is a sequence) drange(dstart, dend, delta): This function returns a date range (a sequence) of float values in Matplotlib date format; dstart and dend are datetime objects while delta is a datetime.timedelta instance Usually, what we will end up doing is converting a sequence of datetime objects into a Matplotlib representation, such as: dates = list of datetime objectsmpl_dates = matplotlib.dates.date2num(dates) drange() can be useful in situations like this one: import matplotlib as mplfrom matplotlib import datesimport datetime as dtdate1 = dt.datetime(2008, 9, 23)date2 = dt.datetime(2009, 4, 12)delta = dt.timedelta(days=10)dates = mpl.dates.drange(date1, date2, delta) where dates will be a sequence of floats starting from date1 and ending at date2 with a delta timestamp between each item of the list. Axes formatting with axes tick locators and formatters As we have already seen, the X labels on the first image are not that nice looking. We would expect Matplotlib to allow a better way to label the axis, and indeed, there is. The solution is to change the two parts that form the axis   ticks—locators and formatters. Locators control the tick's position, while formatters control the formatting of labels. Both have a major and minor mode: the major locator and formatter are active by default and are the ones we commonly see, while minor mode can be turned on by passing a relative locator or formatter function (because minors are turned off by default by assigning NullLocator and NullFormatter to them). While this is a general tuning operation and can be applied to all Matplotlib plots, there are some specific locators and formatters for date plotting, provided by matplotlib.dates: MinuteLocator, HourLocator,DayLocator, WeekdayLocator,MonthLocator, YearLocator are all the  locators available that place a tick at the time specified by the name, for example, DayLocator will draw a tick at each day. Of course, a minimum knowledge of the date interval that we are about to draw is needed to select the best locator. DateFormatter is the tick formatter that uses strftime() to format strings.   The default locator and formatter are matplotlib.ticker.AutoDateLocator and matplotlib.ticker.AutoDateFormatter, respectively. Both are set by the plot_date() function when called. So, if you wish to set a different locator and/or formatter, then we suggest to do that after the plot_date() call in order to avoid the plot_date() function resetting them to the default values. Let's group all this up in an example: In [1]: import matplotlib as mplIn [2]: import matplotlib.pyplot as pltIn [3]: import numpy as npIn [4]: import datetime as dtIn [5]: fig = plt.figure()In [6]: ax2 = fig.add_subplot(212)In [7]: date2_1 = dt.datetime(2008, 9, 23)In [8]: date2_2 = dt.datetime(2008, 10, 3)In [9]: delta2 = dt.timedelta(days=1)In [10]: dates2 = mpl.dates.drange(date2_1, date2_2, delta2)In [11]: y2 = np.random.rand(len(dates2))In [12]: ax2.plot_date(dates2, y2, linestyle='-');In [13]: dateFmt = mpl.dates.DateFormatter('%Y-%m-%d')In [14]: ax2.xaxis.set_major_formatter(dateFmt)In [15]: daysLoc = mpl.dates.DayLocator()In [16]: hoursLoc = mpl.dates.HourLocator(interval=6)In [17]: ax2.xaxis.set_major_locator(daysLoc)In [18]: ax2.xaxis.set_minor_locator(hoursLoc)In [19]: fig.autofmt_xdate(bottom=0.18) # adjust for date labels displayIn [20]: fig.subplots_adjust(left=0.18)In [21]: ax1 = fig.add_subplot(211)In [22]: date1_1 = dt.datetime(2008, 9, 23)In [23]: date1_2 = dt.datetime(2009, 2, 16)In [24]: delta1 = dt.timedelta(days=10)In [25]: dates1 = mpl.dates.drange(date1_1, date1_2, delta1)In [26]: y1 = np.random.rand(len(dates1))In [27]: ax1.plot_date(dates1, y1, linestyle='-');In [28]: monthsLoc = mpl.dates.MonthLocator()In [29]: weeksLoc = mpl.dates.WeekdayLocator()In [30]: ax1.xaxis.set_major_locator(monthsLoc)In [31]: ax1.xaxis.set_minor_locator(weeksLoc)In [32]: monthsFmt = mpl.dates.DateFormatter('%b')In [33]: ax1.xaxis.set_major_formatter(monthsFmt)In [34]: plt.show() The result of executing the previous code snippet is as shown: We drew the subplots in reverse order to avoid some minor overlapping problems. fig.autofmt_xdate() is used to nicely format date tick labels. In particular, this function rotates the labels (by using rotation keyword argument, with a default value of 30°) and gives them  more room (by using bottom keyword argument, with a default value of 0.2). We can achieve the same result, at least for the additional spacing, with: fig = plt.figure()fig.subplots_adjust(bottom=0.2)ax = fig.add_subplot(111) This can also be done by creating the Axes instance directly with: ax = fig.add_axes([left, bottom, width, height]) while specifying the explicit dimensions. The subplots_adjust() function allows us to control the spacing around the subplots by using the following keyword arguments: bottom, top, left, right: Controls the spacing at the bottom, top, left, and right of the subplot(s)     wspace, hspace: Controls the horizontal and vertical spacing between subplots We can also control the spacing by using these parameters in the Matplotlib configuration file: figure.subplot.<position> = <value> Custom formatters and locators Even if it's not strictly related to date plotting, tick formatters allow for custom formatters too: ...import matplotlib.ticker as ticker...def format_func(x, pos): return <a transformation on x>...formatter = ticker.FuncFormatter(format_func)ax.xaxis.set_major_formatter(formatter)... The  function format_func will be called for each label to draw, passing its value and position on the axis. With those two arguments, we can apply a transformation (for example, divide x by 10) and then return a value that will be used to actually draw the tick label. Here's a general note on NullLocator: it can be used to remove axis ticks by simply issuing: ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator()) Text properties, fonts, and LaTeX Matplotlib has excellent text support, including mathematical expressions, TrueType font support for raster and vector outputs, newline separated text with arbitrary rotations, and Unicode. We have total control over every text property (font size, font weight, text location, color, and so on) with sensible defaults set in the rc configuration file. Specifically for those interested in mathematical or scientific figures, Matplotlib implements a large number of TeX math symbols and commands to support mathematical expressions anywhere in the figure. We already saw some text functions, but the following list contains all the functions which can be used to insert text with the pyplot interface, presented along with the corresponding API method and a description: Pyplot function API method Description text() mpl.axes.Axes.text() Adds text at an arbitrary location to the Axes xlabel() mpl.axes.Axes.set_xlabel() Adds an axis label to the X-axis ylabel() mpl.axes.Axes.set_ylabel() Adds an axis label to the Y-axis title() mpl.axes.Axes.set_title() Adds a title to the Axes figtext() mpl.figure.Figure.text() Adds text at an arbitrary location to the Figure suptitle() mpl.figure.Figure.suptitle() Adds a centered title to the Figure annotate() mpl.axes.Axes.annotate() Adds an annotation with an optional arrow to the Axes     All of these commands return a matplotlib.text.Text instance. We can customize the text properties by passing keyword arguments to the functions or by using matplotlib.artist.setp(): t = plt.xlabel('some text', fontsize=16, color='green') We can do it as: t = plt.xlabel('some text')plt.setp(t, fontsize=16, color='green') Handling objects allows for several new possibilities; such as setting the same property to all the objects in a specific group. Matplotlib has several convenience functions to return the objects of a plot. Let's take the example of the tick labels: ax.get_xticklabels() This line of code returns a sequence of object instances (the labels for the X-axis ticks) that we can tune: for t in ax.get_xticklabels(): t.set_fontsize(5.) or else, still using setp(): setp(ax.get_xticklabels(), fontsize=5.) It can take a sequence of objects, and apply the same property to all of them. To recap, all of the properties such as color, fontsize, position, rotation, and so on, can be set either: At function call using keyword arguments Using setp() referencing the Text instance Using the modification function Fonts Where there is text, there are also fonts to draw it. Matplotlib allows for several font customizations. The most complete documentation on this is currently available in the Matplotlib configuration file, /etc/matplotlibrc. We are now reporting that information here. There are six font properties available for modification. Property name Values and description font.family It has five values: serif (example, Times) sans-serif (example, Helvetica) cursive (example, Zapf-Chancery) fantasy (example, Western) monospace (example, Courier) Each of these font families has a default list of font names in decreasing order of priority associated with them (next table). In addition to these generic font names, font.family may also be an explicit name of a font available on the system. font.style Three values: normal (or roman), italic, or oblique. The oblique style will be used for italic, if it is not present. font.variant Two values: normal or small-caps. For TrueType fonts, which are scalable fonts, small-caps is equivalent to using a font size of smaller, or about 83% of the current font size. font.weight Effectively has 13 values-normal, bold, bolder, lighter, 100, 200, 300, ..., 900. normal is the same as 400, and bold is 700. bolder and lighter are relative values with respect to the current weight. font.stretch 11 values-ultra-condensed, extra-condensed, condensed, semi-condensed, normal, semi-expanded, expanded, extra-expanded, ultra-expanded, wider, and narrower. This property is not currently implemented. It works if the font supports it, but only few do. font.size The default font size for text, given in points. 12pt is the standard value.
Read more
  • 0
  • 1
  • 6144

article-image-plotting-data-using-matplotlib-part-2
Packt
19 Nov 2009
15 min read
Save for later

Plotting data using Matplotlib: Part 2

Packt
19 Nov 2009
15 min read
Plotting data from a CSV file A common format to export and distribute datasets is the Comma-Separated Values (CSV) format. For example, spreadsheet applications allow us to export a CSV from a working sheet, and some databases also allow for CSV data export. Additionally, it's a common format to distribute datasets on the Web. In this example, we'll be plotting the evolution of the world's population divided by continents, between 1950 and 2050 (of course they are predictions), using a new type of graph: bars stacked. Using the data available at http://www.xist.org/earth/pop_continent.aspx (that fetches data from the official UN data at http://esa.un.org/unpp/index.asp), we have prepared the following CSV file: Continent,1950,1975,2000,2010,2025,2050Africa,227270,418765,819462,1033043,1400184,1998466Asia,1402887,2379374,3698296,4166741,4772523,5231485Europe,547460,676207,726568,732759,729264,691048Latin America,167307,323323,521228,588649,669533,729184Northern America,171615,242360,318654,351659,397522,448464Oceania,12807,21286,31160,35838,42507,51338 In the first line, we can find the header with a description of what the data in the columns represent. The other lines contain the continent's name and its population (in thousands) for the given years. In the first line, we can find the header with a description of what the data in the columns represent. The other lines contain the continent's name and its population (in thousands) for the given years. There are several ways to parse a CSV file, for example: NumPy's loadtxt() (what we are going to use here) Matplotlib's mlab.csv2rec() The csv module (in the standard library) but we decided to go with loadtxt() because it's very powerful (and it's what Matplotlib is standardizing on). Let's look at how we can plot it then: # for file opening made easierfrom __future__ import with_statement We need this because we will use the with statement to read the file. # numpyimport numpy as np NumPy is used to load the CSV and for its useful array data type. # matplotlib plotting moduleimport matplotlib.pyplot as plt# matplotlib colormap moduleimport matplotlib.cm as cm# needed for formatting Y axisfrom matplotlib.ticker import FuncFormatter# Matplotlib font managerimport matplotlib.font_manager as font_manager In addition to the classic pyplot module, we need other Matplotlib submodules: cm (color map): Considering the way we're going to prepare the plot, we need to specify the color map of the graphical elements FuncFormatter: We will use this to change the way the Y-axis labels are displayed font_manager: We want to have a legend with a smaller font, and font_manager allows us to do that def billions(x, pos): """Formatter for Y axis, values are in billions""" return '%1.fbn' % (x*1e-6) This is the function that we will use to format the Y-axis labels. Our data is in thousands. Therefore, by dividing it by one million, we obtain values in the order of billions. The function is called at every label to draw, passing the label value and the position. # bar widthwidth = .8 As said earlier, we will plot bars, and here we defi ne their width. The following is the parsing code. We know that it's a bit hard to follow (the data preparation code is usually the hardest one) but we will show how powerful it is. # open CSV filewith open('population.csv') as f: The function we're going to use, NumPy loadtxt(), is able to receive either a filename or a file descriptor, as in this case. We have to open the file here because we have to strip the header line from the rest of the file and set up the data parsing structures. # read the first line, splitting the yearsyears = map(int, f.readline().split(',')[1:]) Here we read the first line, the header, and extract the years. We do that by calling the split() function and then mapping the int() function to the resulting list, from the second element onwards (as the first one is a string). # we prepare the dtype for exacting data; it's made of:# <1 string field> <len(years) integers fields>dtype = [('continents', 'S16')] + [('', np.int32)]*len(years) NumPy is flexible enough to allow us to define new data types. Here, we are creating one ad hoc for our data lines: a string (of maximum 16 characters) and as many integers as the length of years list. Also note how the fi rst element has a name, continents, while the last integers have none: we will need this in a bit. # we load the file, setting the delimiter and the dtype abovey = np.loadtxt(f, delimiter=',', dtype=dtype) With the new data type, we can actually call loadtxt(). Here is the description of the parameters: f: This is the file descriptor. Please note that it now contains all the lines except the first one (we've read above) which contains the headers, so no data is lost. delimiter: By default, loadtxt() expects the delimiter to be spaces, but since we are parsing a CSV file, the separator is comma. dtype: This is the data type that is used to apply to the text we read. By default, loadtxt() tries to match against float values # "map" the resulting structure to be easily accessible:# the first column (made of string) is called 'continents'# the remaining values are added to 'data' sub-matrix# where the real data arey = y.view(np.dtype([('continents', 'S16'), ('data', np.int32, len(years))])) Here we're using a trick: we view the resulting data structure as made up of two parts, continents and data. It's similar to the dtype that we defined earlier, but with an important difference. Now, the integer's values are mapped to a field name, data. This results in the column continents with all the continents names,and the matrix data that contains the year's values for each row of the file. data = y['data']continents = y['continents'] We can separate the data and the continents part into two variables for easier usage in the code. # prepare the bottom arraybottom = np.zeros(len(years)) We prepare an array of zeros of the same length as years. As said earlier, we plot stacked bars, so each dataset is plot over the previous ones, thus we need to know where the bars below finish. The bottom array keeps track of this, containing the height of bars already plotted. # for each line in datafor i in range(len(data)): Now that we have our information in data, we can loop over it. # create the bars for each element, on top of the previous barsbt = plt.bar(range(len(data[i])), data[i], width=width, color=cm.hsv(32*i), label=continents[i], bottom=bottom) and create the stacked bars. Some important notes: We select the the i-th row of data, and plot a bar according to its element's size (data[i]) with the chosen width. As the bars are generated in different loops, their colors would be all the same. To avoid this, we use a color map (in this case hsv), selecting a different color at each iteration, so the sub-bars will have different colors. We label each bar set with the relative continent's name (useful for the legend) As we have said, they are stacked bars. In fact, every iteration adds a piece of the global bars. To do so, we need to know where to start drawing the bar from (the lower limit) and bottom does this. It contains the value where to start drowing the current bar. # update the bottom arraybottom += data[i] We update the bottom array. By adding the current data line, we know what the bottom line will be to plot the next bars on top of it. # label the X ticks with yearsplt.xticks(np.arange(len(years))+width/2, [int(year) for year in years]) We then add the tick's labels, the years elements, right in the middle of the bar. # some information on the plotplt.xlabel('Years')plt.ylabel('Population (in billions)')plt.title('World Population: 1950 - 2050 (predictions)') Add some information to the graph. # draw a legend, with a smaller fontplt.legend(loc='upper left', prop=font_manager.FontProperties(size=7)) We now draw a legend in the upper-left position with a small font (to better fit the empty space). # apply the custom function as Y axis formatterplt.gca().yaxis.set_major_formatter(FuncFormatter(billions) Finally, we change the Y-axis label formatter, to use the custom formatting function that we defined earlier. The result is the next screenshot where we can see the composition of the world population divided by continents: In the preceding screenshot, the whole bar represents the total world population, and the sections in each bar tell us about how much a continent contributes to it. Also observe how the custom color map works: from bottom to top, we have represented Africa in red, Asia in orange, Europe in light green, Latin America in green, Northern America in light blue, and Oceania in blue (barely visible as the top of the bars). Plotting extrapolated data using curve fitting While plotting the CSV values, we have seen that there were some columns representing predictions of the world population in the coming years. We'd like to show how to obtain such predictions using the mathematical process of extrapolation with the help of curve fitting. Curve fitting is the process of constructing a curve (a mathematical function) that better fits to a series of data points. This process is related to other two concepts: interpolation: A method of constructing new data points within the range of a known set of points extrapolation: A method of constructing new data points outside a known set of points The results of extrapolation are subject to a greater degree of uncertainty and are influenced a lot by the fitting function that is used. So it works this way: First, a known set of measures is passed to the curve fitting procedure that computes a function to approximate these values With this function, we can compute additional values that are not present in the original dataset Let's first approach curve fitting with a simple example: # Numpy and Matplotlibimport numpy as npimport matplotlib.pyplot as plt These are the classic imports. # the known points setdata = [[2,2],[5,0],[9,5],[11,4],[12,7],[13,11],[17,12]] This is the data we will use for curve fitting. They are the points on a plane (so each has a X and a Y component) # we extract the X and Y components from previous pointsx, y = zip(*data) We aggregate the X and Y components in two distinct lists. # plot the data points with a black crossplt.plot(x, y, 'kx') Then plot the original dataset as a black cross on the Matplotlib image. # we want a bit more data and more fine grained for# the fitting functionsx2 = np.arange(min(x)-1, max(x)+1, .01) We prepare a new array for the X values because we wish to have a wider set of values (one unit on the right and one on to the left of the original list) and a fine grain to plot the fitting function nicely. # lines styles for the polynomialsstyles = [':', '-.', '--'] To differentiate better between the polynomial lines, we now define their styles list. # getting style and count one at timefor d, style in enumerate(styles): Then we loop over that list by also considering the item count. # degree of the polynomialdeg = d + 1 We define the actual polynomial degree. # calculate the coefficients of the fitting polynomialc = np.polyfit(x, y, deg) Then compute the coefficients of the fitting polynomial whose general format is: c[0]*x**deg + c[1]*x**(deg – 1) + ... + c[deg]# we evaluate the fitting function against x2y2 = np.polyval(c, x2) Here, we generate the new values by evaluating the fitting polynomial against the x2 array. # and then we plot itplt.plot(x2, y2, label="deg=%d" % deg, linestyle=style) Then we plot the resulting function, adding a label that indicates the degree of the polynomial and using a different style for each line. # show the legendplt.legend(loc='upper left') We then show the legend, and the final result is shown in the next screenshot: Here, the polynomial with degree=1 is drawn as a dotted blue line, the one with degree=2 is a dash-dot green line, and the one with degree=3 is a dashed red line. We can see that the higher the degree, the better is the fit of the function against the data. Let's now revert to our main intention, trying to provide an extrapolation for population data. First a note: we take the values for 2010 as real data and not predictions (well, we are quite near to that year) else we have very few values to create a realistic extrapolation. Let's see the code: # for file opening made easierfrom __future__ import with_statement# numpyimport numpy as np# matplotlib plotting moduleimport matplotlib.pyplot as plt# matplotlib colormap moduleimport matplotlib.cm as cm# Matplotlib font managerimport matplotlib.font_manager as font_manager# bar widthwidth = .8# open CSV filewith open('population.csv') as f: # read the first line, splitting the years years = map(int, f.readline().split(',')[1:]) # we prepare the dtype for exacting data; it's made of: # <1 string field> <6 integers fields> dtype = [('continents', 'S16')] + [('', np.int32)]*len(years) # we load the file, setting the delimiter and the dtype above y = np.loadtxt(f, delimiter=',', dtype=dtype) # "map" the resulting structure to be easily accessible: # the first column (made of string) is called 'continents' # the remaining values are added to 'data' sub-matrix # where the real data are y = y.view(np.dtype([('continents', 'S16'), ('data', np.int32, len(years))]))# extract fieldsdata = y['data']continents = y['continents'] This is the same code that is used for the CSV example (reported here for completeness). x = years[:-2]x2 = years[-2:] We are dividing the years into two groups: before and after 2010. This translates to split the last two elements of the years list. What we are going to do here is prepare the plot in two phases: First, we plot the data we consider certain values After this, we plot the data from the UN predictions next to our extrapolations # prepare the bottom arrayb1 = np.zeros(len(years)-2) We prepare the array (made of zeros) for the bottom argument of bar(). # for each line in datafor i in range(len(data)): # select all the data except the last 2 values d = data[i][:-2] For each data line, we extract the information we need, so we remove the last two values. # create bars for each element, on top of the previous barsbt = plt.bar(range(len(d)), d, width=width, color=cm.hsv(32*(i)), label=continents[i], bottom=b1)# update the bottom arrayb1 += d Then we plot the bar, and update the bottom array. # prepare the bottom arrayb2_1, b2_2 = np.zeros(2), np.zeros(2) We need two arrays because we will display two bars for the same year—one from the CSV and the other from our fitting function. # for each line in datafor i in range(len(data)): # extract the last 2 values d = data[i][-2:] Again, for each line in the data matrix, we extract the last two values that are needed to plot the bar for CSV. # select the data to compute the fitting functiony = data[i][:-2] Along with the other values needed to compute the fitting polynomial. # use a polynomial of degree 3c = np.polyfit(x, y, 3) Here, we set up a polynomial of degree 3; there is no need for higher degrees. # create a function out of those coefficientsp = np.poly1d(c) This method constructs a polynomial starting from the coefficients that we pass as parameter. # compute p on x2 values (we need integers, so the map)y2 = map(int, p(x2)) We use the polynomial that was defined earlier to compute its values for x2. We also map the resulting values to integer, as the bar() function expects them for height. # create bars for each element, on top of the previous barsbt = plt.bar(len(b1)+np.arange(len(d)), d, width=width/2, color=cm.hsv(32*(i)), bottom=b2_1) We draw a bar for the data from the CSV. Note how the width is half of that of the other bars. This is because in the same width we will draw the two sets of bars for a better visual comparison. # create the bars for the extrapolated valuesbt = plt.bar(len(b1)+np.arange(len(d))+width/2, y2, width=width/2, color=cm.bone(32*(i+2)), bottom=b2_2) Here, we plot the bars for the extrapolated values, using a dark color map so that we have an even better separation for the two datasets. # update the bottom arrayb2_1 += db2_2 += y2 We update both the bottom arrays. # label the X ticks with yearsplt.xticks(np.arange(len(years))+width/2, [int(year) for year in years]) We add the years as ticks for the X-axis. # draw a legend, with a smaller fontplt.legend(loc='upper left', prop=font_manager.FontProperties(size=7)) To avoid a very big legend, we used only the labels for the data from the CSV, skipping the interpolated values. We believe it's pretty clear what they're referring to. Here is the screenshot that is displayed on executing this example: The conclusion we can draw from this is that the United Nations uses a different function to prepare the predictions, especially because they have a continuous set of information, and they can also take into account other environmental circumstances while preparing such predictions. Tools using Matplotlib Given that it's has an easy and powerful API, Matplotlib is also used inside other programs and tools when plotting is needed. We are about to present a couple of these tools: NetworkX Mpmath
Read more
  • 0
  • 0
  • 6514

article-image-load-validate-and-submit-forms-using-ext-js-30-part-2
Packt
19 Nov 2009
4 min read
Save for later

Load, Validate, and Submit Forms using Ext JS 3.0: Part 2

Packt
19 Nov 2009
4 min read
Creating validation functions for URLs, email addresses, and other types of data Ext JS has an extensive library of validation functions. This is how it can be used to validate URLs, email addresses, and other types of data. The following screenshot shows email address validation in action: This screenshot displays URL validation in action: How to do it... Initialize the QuickTips singleton: Ext.QuickTips.init(); Create a form with fields that accept specific data formats: Ext.onReady(function() { var commentForm = new Ext.FormPanel({ frame: true, title: 'Send your comments', bodyStyle: 'padding:5px', width: 550, layout: 'form', defaults: { msgTarget: 'side' }, items: [ { xtype: 'textfield', fieldLabel: 'Name', name: 'name', anchor: '95%', allowBlank: false }, { xtype: 'textfield', fieldLabel: 'Email', name: 'email', anchor: '95%', vtype: 'email' }, { xtype: 'textfield', fieldLabel: 'Web page', name: 'webPage', vtype: 'url', anchor: '95%' }, { xtype: 'textarea', fieldLabel: 'Comments', name: 'comments', anchor: '95%', height: 150, allowBlank: false }], buttons: [{ text: 'Send' }, { text: 'Cancel' }] }); commentForm.render(document.body);}); How it works... The vtype configuration option specifies which validation function will be applied to the field. There's more... Validation types in Ext JS include alphanumeric, numeric, URL, and email formats. You can extend this feature with custom validation functions, and virtually, any format can be validated. For example, the following code shows how you can add a validation type for JPG and PNG files: Ext.apply(Ext.form.VTypes, { Picture: function(v) { return /^.*.(jpg|JPG|png|PNG)$/.test(v); }, PictureText: 'Must be a JPG or PNG file';}); If you need to replace the default error text provided by the validation type, you can do so by using the vtypeText configuration option: { xtype: 'textfield', fieldLabel: 'Web page', name: 'webPage', vtype: 'url', vtypeText: 'I am afraid that you did not enter a URL', anchor: '95%'} See also... The Specifying the required fields in a form recipe, covered earlier in this article, explains how to make some form fields required The Setting the minimum and maximum length allowed for a field's value recipe, covered earlier in this article, explains how to restrict the number of characters entered in a field The Changing the location where validation errors are displayed recipe, covered earlier in this article, shows how to relocate a field's error icon Refer to the previous recipe, Deferring field validation until form submission, to know how to validate all fields at once upon form submission, instead of using the default automatic field validation The next recipe, Confirming passwords and validating dates using relational field validation, explains how to perform validation when the value of one field depends on the value of another field The Rounding up your validation strategy with server-side validation of form fields recipe (covered later in this article) explains how to perform server-side validation Confirming passwords and validating dates using relational field validation Frequently, you face scenarios where the values of two fields need to match, or the value of one field depends on the value of another field. Let's examine how to build a registration form that requires the user to confirm his or her password when signing up. How to do it… Initialize the QuickTips singleton: Ext.QuickTips.init(); Create a custom vtype to handle the relational validation of the password: Ext.apply(Ext.form.VTypes, { password: function(val, field) { if (field.initialPassField) { var pwd = Ext.getCmp(field.initialPassField); return (val == pwd.getValue()); } return true; }, passwordText: 'What are you doing?<br/>The passwords entered do not match!'}); Create the signup form: var signupForm = { xtype: 'form', id: 'register-form', labelWidth: 125, bodyStyle: 'padding:15px;background:transparent', border: false, url: 'signup.php', items: [ { xtype: 'box', autoEl: { tag: 'div', html: '<div class="app-msg"><img src="img/businessman add.png" class="app-img" /> Register for The Magic Forum</div>' } }, { xtype: 'textfield', id: 'email', fieldLabel: 'Email', allowBlank: false, minLength: 3, maxLength: 64,anchor:'90%', vtype:'email' }, { xtype: 'textfield', id: 'pwd', fieldLabel: 'Password', inputType: 'password',allowBlank: false, minLength: 6, maxLength: 32,anchor:'90%', minLengthText: 'Password must be at least 6 characters long.' }, { xtype: 'textfield', id: 'pwd-confirm', fieldLabel: 'Confirm Password', inputType: 'password', allowBlank: false, minLength: 6, maxLength: 32,anchor:'90%', minLengthText: 'Password must be at least 6 characters long.', vtype: 'password', initialPassField: 'pwd' }],buttons: [{ text: 'Register', handler: function() { Ext.getCmp('register-form').getForm().submit(); }},{ text: 'Cancel', handler: function() { win.hide(); } }]} Create the window that will host the signup form: Ext.onReady(function() { win = new Ext.Window({ layout: 'form', width: 340, autoHeight: true, closeAction: 'hide', items: [signupForm] }); win.show();
Read more
  • 0
  • 0
  • 5410
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-sticky-features-your-blog-network-wordpress-mu-28-part-1
Packt
19 Nov 2009
9 min read
Save for later

Sticky Features for your Blog Network with WordPress MU 2.8: Part 1

Packt
19 Nov 2009
9 min read
What do people mean by "sticky"? If you have ever ran a blog or web site before, you may have noticed that it's fairly easy to get a spike in traffic by submitting a good story to a few social bookmarking sites or by being lucky enough to get a link to one of your posts from a much larger site. The problem is that after a day or so, when the submissions fall off the front page, it's likely your traffic will die down to its usual levels again. Some site owners fall into the trap of chasing after the next traffic spike, using "linkbait" articles with intentionally controversial titles and content, when they should really be focusing on quality content, improving the site, and working towards sustained growth. Many bloggers submit their site to StumbleUpon.com. StumbleUpon is a web service where users can enter their interests, and be sent to a random site that will match those interests. Those users can then either give a "thumbs up" to the site they are sent to indicating that they like the site or a "thumbs down" if they don't like it. Those votes are used to improve future suggestions and increase the chances of the next site that they "Stumble Upon" being one that they are interested in. Other popular sites for increasing traffic include Technorati (a site that measures the "authority" of a blog based on how many other bloggers are linking to it), and the news/story-related sites Reddit (a general interest site with everything from politics to gadgets-related news), and Digg (a site with a focus on tech and gaming news). A sticky blog is one that doesn't just attract new visitors, it keeps them. Instead of having a visitor click through from a link on Technorati or visit by using the Stumble! feature of StumbleUpon, skim the page they land on and then leave, a sticky blog would make that visitor stay around a little longer. Ideally, visitors would read the article they were interested in and then find themselves intrigued enough to read more articles. They may comment on some articles and then keep returning to read answers to their comments. Or, they may decide to subscribe to the blog so that they can read future posts. A sticky site encourages readers to become engaged with the community, resulting in long-term increases in traffic. When new readers arrive at the site for the first time, they get involved themselves and keep coming back. They may also tell their friends or link to the site from their own sites, giving you free promotion. Letting readers and authors communicate Interesting content is vital, but one of the best ways to get people coming back to your blog network is to give them a chance to interact with the site's authors and with each other. This not only makes the readers feel valued, it also opens up a dialogue that encourages repeat visitors. Contact forms Providing visitors with a way to contact you privately is useful for several reasons. The visitor may want to discuss advertising opportunities, submit some news you may be interested in, or ask for help with a problem they have accessing part of the site. You could post your email address on the site, but this makes you vulnerable to spam attacks. A contact form is a safer way to allow your visitors to contact you. Time for action – setting up contact forms Let's set up a contact form: Download Contact Form 7 from http://wordpress.org/extend/plugins/contact-form-7/. To install, upload the contents of the archive file to /wp-content/plugins. Activate the plugin and go to the settings page (Tools | Contact Form 7). You can also access the page by clicking Settings under the plugin name, which appears on the Manage Plugins page. You can add new fields using the Generate Tag drop-down menu. Further down the admin page you will see options to set error messages (such as the message users will see if they miss out a required field, or if they try to upload a file that is too big). Once you have created the form, make a note of the tag at the top of the screen (in our case this was [contact-form 1 "Contact form 1"] ). Create a new page (Pages | Add New) called Contact Us, add a short message to the page, and then paste the contact form tag into the page. Depending on the theme you are using, you may need to add the Pages widget to your sidebar so that visitors can find the new page. Your page should look something like this: What just happened? Contact Form 7 is a powerful contact form tool that supports CAPTCHAs (via the Really Simple CAPTCHA  plugin), file uploads, drop-down menus, and more. You can define multiple contact forms and have each one submit to a different email address. This could be useful if you wish to have different people contacted for, say, advertising queries, news submissions, and tech support. You can also have a contact form submit to multiple email addresses. So, as well as having the relevant person receive a copy of each message, the site administrator could ensure they receive a copy of all messages too. You can set a prefix for each message, in addition to the subject line the visitor sets. For example, if you set the prefix to [Slayer-Form1], all emails from that contact form will have a subject line that begins with that text. You can use this to set up filters in your email application, making it easy to prioritize emails from different contact forms. Improved comments The basic WordPress MU comment feature allows readers to post their thoughts about a blog post, but it is not very good for encouraging discussion. One useful service for bloggers is IntenseDebate. This service allows for threaded discussion in comments, subscription to comments by RSS and email, and the ability to tie blog commenting in with other social networking sites and follow comments made by other blog readers. Time for action – IntenseDebate Comments Download the IntenseDebate Comments plugin from http://wordpress.org/extend/plugins/intensedebate/. You will need to sign up for an account at http://intensedebate.com/. Activate the plugin. Go to Settings | IntenseDebate. You will be presented with a login screen. Enter the account details for the account you created in step 2. Once you have logged in, click Start Importing Comments. The import process can take a very long time, even if you don't have many comments to import. Once the import process is complete, you can tweak the settings to suit your blog—although I found the default ones were a good starting point. The IntenseDebate Comments plugin has its own Comments caption, so you may want to remove the Comments header from the index.php file in your theme folder. The new comment box should look something like this: You can moderate comments using the already familiar WordPress MU interface or the dashboard on the IntenseDebate site. What just happened? IntenseDebate is a commenting system that sits on top of WordPress and WordPress MU. It is ideal for all blogs, whether they are part of a blog network, or a standalone blog. It does not replace the existing WordPress comment system; it only complements it. This means you can use IntenseDebate in conjunction with other plugins that rely on the WordPress MU comment system. Readers can comment on your blog using the IntenseDebate comment system. If they have JavaScript turned off, they will be presented with the normal WordPress comment system instead. IntenseDebate has lots of useful features that will make your users feel a greater sense of engagement with your site's authors. Those features are described below: Threaded discussions: IntenseDebate supports threaded comments. This makes it easy for readers to follow the discussions going on in the comments section. Readers can reply to the blog post itself, or reply to a specific comment, and IntenseDebate will break related comments into threads so that the discussion is easy to keep track of. Track comments or comment anonymously: Readers can comment anonymously, or, if they have an IntenseDebate profile they can log in to it and comment using it. Any comments made will be stored in the WordPress comments database and also be sent to IntenseDebate. Subscribe to comments: Readers can subscribe to comments on a particular post by email or through their favorite RSS reader. If they have an IntenseDebate account, they also have the option to send a Twitter message or "Tweet" to alert their friends that they have commented on a particular post. Reputation and voting: Another useful feature is the reputation system. Visitors can vote on comments, and comments that get a lot of negative votes will be hidden from view unless a user requests to see them. This is a handy form of "self moderation" for the community. The reputation system applies to only logged in users and gives each user an overall rating based on the quality of their comments on sites all over the Internet. Activating IntenseDebate on your users' blogs One important thing to remember is that even if you set IntenseDebate to automatically activate for your users, it won't do anything unless they set it up. Your users will still have the original WordPress MU comment system. They will be alerted to the fact that the plugin is not working for them by a message that will appear at the top of every page in their admin panel. Have a go hero – tweaking IntenseDebate IntenseDebate has so many features that there is not enough room to cover them all here. Take a look at the Extras (http://intensedebate.com/extras) page for some widgets that you may want to add to your blog. Also, check the Settings page for your blog in IntenseDebate. You can edit the moderation settings on that page. The default settings include a list of spam words that will cause comments to be flagged for moderation. Comments will also be flagged for moderation if they contain more than two URLs. You can tweak the commenting system's settings to filter by IP address, email address, key words, and profanity. You can also alter how the comments are displayed, the text displayed when people report comments, the layout, and the location of the blog's RSS feed. You may want to change that to use the FeedBurner version of the RSS feed. >> continue Reading: Sticky Features for your Blog Network with WordPress MU 2.8: Part 2
Read more
  • 0
  • 0
  • 1832

article-image-microsoft-chart-xml-data
Packt
18 Nov 2009
4 min read
Save for later

Microsoft Chart with XML Data

Packt
18 Nov 2009
4 min read
Introduction SQL 2000 Server provided T-SQL language extensions to operate bi-directionally with relational and XML sources. It also provided two system stored procedures, sp_XML_preparedocument and sp_XML_removedocument, that assist the XML to Relational transformation. This support for returning XML data from relational data using the For XML clause is continued in SQL Server 2005 and SQL Server 2008 although the support for XML is lot more extensive. The shape of the data returned by the For XML clause is further modified by choosing the following modes, raw, auto, explicit, or path. As a preparation for this article we will be creating an XML document starting from the PrincetonTemp table used in a previous article, Binding MS Chart Control to LINQ Data Source Control, on this site. Creating an XML document from an SQL Table Open the SQL Server Management and create a new query [SELECT * from PrincetonTemp for XML auto]. You can use the For XML Auto clause to create a XML document (actually what you create is a fragment - a root-less XML without a processing directive) as shown in Figure 01. Figure 01: For XML Auto clause of a SELECT statement The result shown in a table has essentially two columns with the second column containing the document fragment shown in the next listing. Listing 01: <PrincetonTemp Id="1" Month="Jan " Temperature="4.000000000000000e+001" RecordHigh="6.000000000000000e+001"/> <PrincetonTemp Id="2" Month="Feb " Temperature="3.200000000000000e+001" RecordHigh="5.000000000000000e+001"/> <PrincetonTemp Id="3"Month="Mar " Temperature="4.300000000000000e+001" RecordHigh="6.500000000000000e+001"/> <PrincetonTemp Id="4" Month="Apr " Temperature="5.000000000000000e+001" RecordHigh="7.000000000000000e+001"/> <PrincetonTemp Id="5" Month="May " Temperature="5.300000000000000e+001" RecordHigh="7.400000000000000e+001"/> <PrincetonTemp Id="6" Month="Jun " Temperature="6.000000000000000e+001" RecordHigh="7.800000000000000e+001"/> <PrincetonTemp Id="7" Month="Jul " Temperature="6.800000000000000e+001" RecordHigh="7.000000000000000e+001"/> <PrincetonTemp Id="8" Month="Aug " Temperature="7.100000000000000e+001" RecordHigh="7.000000000000000e+001"/> <PrincetonTemp Id="9" Month="Sep " Temperature="6.000000000000000e+001" RecordHigh="8.200000000000000e+001"/> <PrincetonTemp Id="10" Month="Oct " Temperature="5.500000000000000e+001" RecordHigh="6.700000000000000e+001"/> <PrincetonTemp Id="11" Month="Nov " Temperature="4.500000000000000e+001" RecordHigh="5.500000000000000e+001"/> <PrincetonTemp Id="12" Month="Dec " Temperature="4.000000000000000e+001" RecordHigh="6.200000000000000e+001"/> This result is attribute-centric as each row of data corresponds to a row in the relational table with each column represented as an XML attribute. The same data can be extracted in an element centric manner by using the directive elements in the SELECT statement as shown in the next figure. Figure 02: For XML auto, Elements clause of a Select statement This would still give us an XML fragment but now it is displayed with element nodes as shown in the next listing (only two nodes 1 and 12 are shown). Listing 02: <PrincetonTemp><Id>1</Id><Month>Jan </Month><Temperature>4.000000000000000e+001</Temperature> <RecordHigh>6.000000000000000e+001</RecordHigh> </PrincetonTemp> ... <PrincetonTemp><Id>12</Id><Month>Dec </Month><Temperature>4.000000000000000e+001</Temperature> <RecordHigh>6.200000000000000e+001 </RecordHigh></PrincetonTemp> To make a clear distinction between the results returned by the two select statements the first row of data is shown in blue. This has returned elements and not attributes. As you can see the returned XML still lacks a root element as well as the XML processing directive. To continue with displaying this data in MS Chart Save Listing 2 as PrincetonXMLDOC.xml to a location of your choice. Create a Framework 3.5 Web Site project Let us create a web site project and display the chart on the Default.aspx page. Open Visual Studio 2008 from its shortcut on the desktop. Click File  New | Web Site...|(or Shift+Alt+N) to open the New Web Site window. Change the default name of the site to a name of your choice (herein Chart_XMLWeb) as shown. Make sure you are creating a .NET Framework 3.5 web site as shown here. Figure 03: New Framework 3.5 Web Site Project Click on APP_Data folder in the solution explorer as shown in the next figure and click on Add Existing Item… menu item. Figure 04: Add an existing item to the web site folder In the interactive window that gets displayed browse to the location where you saved the PrincetonXMLDOC.xml file and click Add button. This will add the XML file to the ADD_Data folder of the web site project. Double click PrincetonXMLDOC.xml in the web site project folder to display and verify its contents as shown in the next figure. Only nodes 1 and 12 are shown expanded. As mentioned previously this is an XML fragment. Figure 05: Imported PrincetonXMLDOC.xml Modify this document by adding the <root/> as well as the XML processing instruction as shown in the next figure. Build the project. Figure 06: Modified PrincetonXMLDOX.xml (valid XML document)
Read more
  • 0
  • 0
  • 14701

article-image-controlling-which-class-sees-our-resources-moodle-19
Packt
18 Nov 2009
4 min read
Save for later

Controlling Which Class Sees Our Resources in Moodle 1.9

Packt
18 Nov 2009
4 min read
While for the most part, teachers on the same course would want to cover the same material, it can sometimes be the case that one teacher might only want their own class to see a particular item but keep it hidden from others. I myself am doing this currently on a Certificate course whereby the students who have finished are able to view some extension activities that other students still working on the qualification do not have access to. Hiding resources from some students and showing them to others can be done by using "groupings" in Moodle. Groupings – a way to hide resources from some and display to others In order for this to work we need to check certain features: We are using Moodle 1.9. Groups and groupings have been enabled by our Moodle admin (in Site Admin > Experimental as below). We have the students on our Moodle course set up in different teacher groups. Ok – let us assume, we want group French 1 only to see our forum and wiki and we want group French 2 only to see our assignment. If we click on groups in the course administration block we see: If we look to the top of the Groups screen we see three tabs. The one to select next is Groupings. Having clicked on it, we get presented with a screen asking us to create a new grouping. A grouping is like an invisibility cloak (think: Harry Potter!) whereby any people in the grouping can be made invisible to others on the course. If we click on Create grouping we are then asked to give a name (and optional description) for our grouping. Note that we have not yet added any people to the grouping; we are merely setting it up. Once we have scrolled down and saved the changes we are returned to the above screen where we see the grouping has been created – but it has no people and it has no activities assigned to it: The next action to take is to click on the people icon in the Edit box. This sends us to a screen where we can choose which groups to put into this grouping "invisibility cloak": By clicking on a group on the right and moving it across with the arrow to the left we can assign a group to a grouping. You cannot assign individuals to a grouping; you can only assign groups. However –there is nothing preventing you making a group of one single person and then assigning that group! You can also have more than one group in a grouping, should you wish to. We now have our group French 1 in a grouping. The next step is to repeat the process for the group French 2. When that is done, it is important to check in the course settings (in the course admin block) that groups and groupings are enabled. Finally, we go to the activities we have set up – in this instance, a forum, wiki and assignment. We need to assign the tasks to the appropriate groupings. If the tasks have already been set up, as here, we click on the pen/hand icon to go into the editing area. If we are setting them up from scratch we assign the grouping at the time of creation. Scroll down to the section Common Module Settings and choose the appropriate grouping for that task, also checking Available for group members only: The same process must be gone through with the other tasks we want to control access to (in this instance, the wiki and assignment). And then – it’s done! If we the teacher look at the course we see that each activity has the name of the grouping greyed out next to it: Summary A student in one of those groupings, however, would only see their own activities and have no idea the others existed! A simple but effective way to control access to your Moodle tasks on a shared course. If you have read this article you may be interested to view : Setting up your Moodle Grade Book Adding Worksheets and Resources with Moodle Interacting with the Students using Moodle 1.9 (part 1)
Read more
  • 0
  • 0
  • 1505

article-image-restful-java-web-services-design
Packt
18 Nov 2009
5 min read
Save for later

RESTful Java Web Services Design

Packt
18 Nov 2009
5 min read
We'll leave the RESTful implementation for a later article. Our sample application is a micro-blogging web service (similar to Twitter), where users create accounts and then post entries. Finally, while designing our application, we'll define a set of steps that can be applied to designing any software system that needs to be deployed as a RESTful web service. Designing a RESTful web service Designing RESTful web services is not different from designing traditional web applications. We still have business requirements, we still have users who want to do things with data, and we still have hardware constraints and software architectures to deal with. The main difference, however, is that we look at the requirements to tease out resources and forget about specific actions to be taken on these resources. We can think of RESTful web service design as being similar to Object Oriented Design (OOD). In OOD, we try to identify objects from the data we want to represent together with the actions that an object can have. But the similarities end at the data structure definition, because with RESTful web services we already have specific calls that are part of the protocol itself. The underlying RESTful web service design principles can be summarized in the following four steps: Requirements gathering—this step is similar to traditional software requirement gathering practices. Resource identification—this step is similar to OOD where we identify objects, but we don't worry about messaging between objects. Resource representation definition—because we exchange representation between clients and servers, we should define what kind of representation we need to use. Typically, we use XML, but JSON has gained popularity. That's not to say that we can't use any other form of resource representation—on the contrary, we could use XHTML or any other form of binary representation, though we let the requirements guide our choices. URI definition—with resources in place, we need to define the API, which consists of URIs for clients and servers to exchange resources' representations. This design process is not static. These are iterative steps that gravitate around   resources. Let's say that during the URI definition step we discover that one of the URI's responses is not covered in one of the resources we have identified. Then we go back to define a suitable resource. In most cases, however, we find that the resources that we already have cover most of our needs, and we just have to combine existing resources into a meta-resource to take care of the new requirement. Requirements of sample web service The RESTful web service we design in this article is a social networking web application similar to Twitter. We follow an OOD process mixed with an agile philosophy for designing and coding our applications. This means that we create just enough documentation to be useful, but not so much that we spend an inordinate amount of time deciphering it during our implementation phase. As with any application, we begin by listing the main business requirements, for which we have the following use cases (these are the main functions of our application): A web user creates an account with a username and a password (creating an account means that the user is now registered). Registered users post blog entries to their accounts. We limit messages to 140 characters. Registered and non-registered users view all blog entries. Registered and non-registered users view user profiles. Registered users update their user profiles, for example, users update their password. Registered and non-registered users search for terms in all blog entries. However simple this example may be, social networking sites work on these same principles: users sign up for accounts to post personal updates or information. Our intention here, though, is not to fully replicate Twitter or to fully create a social networking application. What we are trying to outline is a set of requirements that will test our understanding of RESTful web services design and implementation. The core value of social networking sites lies in the ability to connect to multiple users who connect with us, and the value is derived from what the connections mean within the community, because of the tendency of users following people with similar interests. For example, the connections between users create targeted distribution networks.The connections between users create random graphs in the graph theory sense, where nodes are users and edges are connections between users. This is what is referred to as the social graph. Resource identification Out of the use cases listed above, we now need to define the service's resources. From reading the requirements we see that we need users and messages. Users appear in two ways: a single user and a list of users. Additionally, users have the ability to post blog entries in the form of messages of no more than 140 characters. This means that we need resources for a single message and a list of messages. In sum, we identify the following resources: User List of users Message List of messages
Read more
  • 0
  • 0
  • 11057
article-image-integrating-websphere-extreme-scale-data-grid-relational-database-part-2
Packt
18 Nov 2009
6 min read
Save for later

Integrating Websphere eXtreme Scale Data Grid with Relational Database: Part 2

Packt
18 Nov 2009
6 min read
Removal versus eviction Setting an eviction policy on a BackingMap makes more sense now that we're using a Loader. Imagine that our cache holds only a fraction of the total data stored in the database. Under heavy load, the cache is constantly asked to hold more and more data, but it operates at capacity. What happens when we ask the cache to hold on to one more payment? The BackingMap needs to remove some payments in order to make room for more. BackingMaps have three basic eviction policies: LRU (least-recently used), LFU (least-frequently used), and TTL (time-to-live). Each policy tells the BackingMap which objects should be removed in order to make room for more. In the event that an object is evicted from the cache, its status in the database is not changed. With eviction, objects enter and leave the cache due to cache misses and evictions innumerable times, and their presence in the database remains unchanged. The only thing that affects an object in the database is an explicit call to change (either persist or merge) or remove it as per our application. Removal means the object is removed from the cache, and the Loader executes the delete from SQL to delete the corresponding row(s) from the database. Your data is safe when using evictions. The cache simply provides a window into your data. A remove operation explicitly tells both ObjectGrid and the database to delete an object. Write-through and write-behind Getting back to the slow down due to the Loader configuration, by default, the Loader uses write-through behavior: Now we know the problem. Write-through behavior wraps a database transaction for every write! For every ObjectGrid transaction, we execute one database transaction. On the up side, every object assuredly reaches the database, provided it doesn't violate any relational constraints. Despite this harsh reaction to write-through behavior, it is essential for objects that absolutely must get to the database as fast as possible. The problem is that we hit the database for every write operation on every BackingMap. It would be nice not to incur the cost of a database transaction every time we write to the cache. Write-behind behavior gives us the help we need. Write-behind gives us the speed of an ObjectGrid transaction and the flexibility that comes with storing data in a database: Each ObjectGrid transaction is now separate from a database transaction. BackingMap now has two jobs. The first job is to store our objects as it always does. The second job is to send those objects to the JPAEntityLoader. The JPAEntityLoader then generates SQL statements to insert the data into a database. We configured each BackingMap with its own JPAEntityLoader. Each BackingMap requires its own Loader because each Loader is specific to a JPA entity class. The relationship between JPAEntityLoader and a JPA entity is established when the BackingMap is initialized. The jpaTxCallback we specified in the ObjectGrid configuration coordinates the transactions between ObjectGrid and a JPA EntityManager. In a write-through situation, our database transactions are only as large as our ObjectGrid transactions. Update one object in the BackingMap and one object is written to the database. With write-behind, our ObjectGrid transaction is complete, and our objects are put in a write-behind queue map. That queue map does not immediately synchronize with the database. It waits for some specified time or for some number of updates, to write out its contents to the database: We configure the database synchronization conditions with the setWriteBehind("time;conditions") method on a BackingMap instance. Programmatically the setWriteBehind method looks like this: BackingMap paymentMap = grid.getMap("Payment");paymentMap.setLoader(new JPAEntityLoader());paymentMap.setWriteBehind("T120;C5001"); The same configuration in XML looks like this: <backingMap name="Payment" writeBehind="T120;C5001"pluginCollectionRef="Payment" /> Enabling write-behind is as simple as that. The setWriteBehind method takes one string parameter, but it is actually a two-in-one. At first, the T part is the time in seconds between syncing with the database. Here, we set the payment BackingMap to wait two minutes between syncs. The C part indicates the number (count) of changes made to the BackingMap that triggers a database sync. Between these two parameters, the sync occurs on a whichever comes first basis. If two minutes elapse between syncs, and only 400 changes (persists, merges, or removals) have been put in the write-behind queue map, then those 400 changes are written out to the database. If only 30 seconds elapse, but we reach 5001 changes, then those changes will be written to the database. ObjectGrid does not guarantee that the sync will take place exactly when either of those conditions is met. The sync may happen a little bit before (116 seconds or 4998 changes) or a little bit later (123 seconds or 5005 changes). The sync will happen as close to those conditions as ObjectGrid can reasonably do it. The default value is "T300;C1000". This syncs a BackingMap to the database every five minutes, or 1000 changes to the BackingMap. This default is specified either with the string "T300;C1000" or with an empty string (" "). Omitting either part of the sync parameters is acceptable. The missing part will use the default value. Calling setWriteBehind("T60") has the BackingMap sync to the database every 60 seconds, or 1000 changes. Calling setWriteBehind("C500") syncs every five minutes, or 500 changes. Write-behind behavior is enabled if the setWriteBehind method is called with an empty string. If you do not want write-behind behavior on a BackingMap, then do not call the setWriteBehind method at all. A great feature of the write-behind behavior is that an object changed multiple times in the cache is only written in its final form to the database. If a payment object is changed in three different ObjectGrid transactions, the SQL produced by the JPAEntityLoader will reflect the object's final state before the sync. For example: entityManager.getTransaction().begin();Payment payment = createPayment(line, batch);entityManager.getTransaction().commit();some time later...entityManager.getTransaction().begin();payment.setAmount(new BigDecimal("44.95"));entityManager.getTransaction().commit();some time later...entityManager.getTransaction().begin();payment.setPaymentType(PaymentType.REAUTH);entityManager.getTransaction().commit(); With write-through behavior, this would produce the following SQL: insert into payment (id, amount, batch_id, card_id, payment_type) values (12345, 75.00, 31, 6087, 'AUTH');update payment set (id, amount, batch_id, card_id, payment_type) values (12345, 44.95, 31, 6087, 'AUTH') where id = 12345;update payment set (id, amount, batch_id, card_id, payment_type) values (12345, 44.95, 31, 6087, 'REAUTH') where id = 12345; Now that we're using write-behind, that same application behavior produces just one SQL statement: insert into payment (id, amount, batch_id, card_id, payment_type) values (12345, 44.95, 31, 6087, 'REAUTH');
Read more
  • 0
  • 0
  • 2427

article-image-create-quick-application-cakephp-part-2
Packt
18 Nov 2009
7 min read
Save for later

Create a Quick Application in CakePHP: Part 2

Packt
18 Nov 2009
7 min read
Editing a Task Now that we can add tasks to CakeTooDoo, the next thing that we will be doing is to have the ability to edit tasks. This is necessary because the users should be able to tick on a task when it has been completed. Also, if the users are not happy with the title of the task, they can change it. To have these features in CakeTooDoo, we will need to add another action to our Tasks Controller and also add a view for this action. Time for Action: Creating the Edit Task Form Open the file tasks_controller.php and add a new action named edit as shown in the following code: function edit($id = null) { if (!$id) { $this->Session->setFlash('Invalid Task'); $this->redirect(array('action'=>'index'), null, true); } if (empty($this->data)) { $this->data = $this->Task->find(array('id' => $id)); } else { if ($this->Task->save($this->data)) { $this->Session->setFlash('The Task has been saved'); $this->redirect(array('action'=>'index'), null, true); } else { $this->Session->setFlash('The Task could not be saved. Please, try again.'); } } } Inside the directory /CakeTooDoo/app/views/tasks, create a new file named edit.ctp and add the following code to it: <?php echo $form->create('Task');?> <fieldset> <legend>Edit Task</legend> <?php echo $form->hidden('id'); echo $form->input('title'); echo $form->input('done'); ?> </fieldset> <?php echo $form->end('Save');?> We will be accessing the Task Edit Form from the List All Task page. So, let's add a link from the List All Tasks page to the Edit Task page. Open the index.ctp file in /CakeTooDoo/app/views directory, and replace the HTML comment <!-- different actions on tasks will be added here later --> with the following code: <?php echo $html->link('Edit', array('action'=>'edit', $task['Task']['id'])); ?> Now open the List All Tasks page in the browser by pointing it to http://localhost/CakeTooDoo/tasks/index and we will see an edit link beside all the tasks. Click on the edit link of the task you want to edit, and this will take you to do the Edit Task form, as shown below: Now let us add links in the Edit Task Form page to the List All Tasks and Add New Task page. Add the following code to the end of edit.ctp in /CakeTooDoo/app/views: <?php echo $html->link('List All Tasks', array('action'=>'index')); ?><br /> <?php echo $html->link('Add Task', array('action'=>'add')); ?> What Just Happened? We added a new action named edit in the Tasks controller. Then we went on to add the view file edit.ctp for this action. Lastly, we linked the other pages to the Edit Task page using the HTML helper. When accessing this page, we need to tell the action which task we are interested to edit. This is done by passing the task id in the URL. So, if we want to edit the task with the id of 2, we need to point our browser to http://localhost/CakeTooDoo/tasks/edit/2. When such a request is made, Cake forwards this request to the Tasks controller's edit action, and passes the value of the id to the first parameter of the edit action. If we check the edit action, we will notice that it accepts a parameter named $id. The task id passed in the URL is stored in this parameter. When a request is made to the edit action, the first thing that it does is to check if any id has been supplied or not. To let users edit a task, it needs to know which task the user wants to edit. It cannot continue if there is no id supplied. So, if $id is undefined, it stores an error message to the session and redirects to the index action that will show the list of current tasks along with the error message. If $id is defined, the edit action then checks whether there is any data stored in $this->data. If no data is stored in $this->data, it means that the user has not yet edited. And so, the desired task is fetched from the Task model, and stored in $this->data in the line: $this->data = $this->Task->find(array('id' => $id)); Once that is done, the view of the edit action is then rendered, displaying the task information. The view fetches the task information to be displayed from $this->data. The view of the edit action is very similar to that of the add action with a single difference. It has an extra line with echo $form->hidden('id');. This creates an HTML hidden input with the value of the task id that is being edited. Once the user edits the task and clicks on the Save button, the edited data is resent to the edit action and saved in $this->data. Having data in $this->data confirms that the user has edited and submitted the changed data. Thus, if $this->data is not empty, the edit action then tries to save the data by calling the Task Model's save() function: $this->Task->save($this->data). This is the same function that we used to add a new task in the add action. You may ask how does the save() function of model knows when to add a new record and when to edit an existing one? If the form data has a hidden id field, the function knows that it needs to edit an existing record with that id. If no id field is found, the function adds a new record. Once the data has been successfully updated, a success message is stored in the session and it redirects to the index action. Of course the index page will show the success message. Adding Data Validation If you have come this far, by now you should have a working CakeTooDoo. It has the ability to add a task, list all the tasks with their statuses, and edit a task to change its status and title. But, we are still not happy with it. We want the CakeTooDoo to be a quality application, and making a quality application with CakePHP is as easy as eating a cake. A very important aspect of any web application (or software in general), is to make sure that the users do not enter inputs that are invalid. For example, suppose a user mistakenly adds a task with an empty title, this is not desirable because without a title we cannot identify a task. We would want our application to check whether the user enters title. If they do not enter a title, CakeTooDoo should not allow the user to add or edit a task, and should show the user a message stating the problem. Adding these checks is what we call Data Validation. No matter how big or small our applications are, it is very important that we have proper data validation in place. But adding data validation can be a painful and time consuming task. This is especially true, if we have a complex application with lots of forms. Thankfully, CakePHP comes with a built-in data validation feature that can really make our lives much easier. Time for Action: Adding Data Validation to Check for Empty Title In the Task model that we created in /CakeTooDoo/app/models, add the following code inside the Task Model class. The Task Model will look like this: <?php class Task extends AppModel { var $name = 'Task'; var $validate = array( 'title' => array( 'rule' => VALID_NOT_EMPTY, 'message' => 'Title of a task cannot be empty' ) ); } ?> Now open the Add Task form in the browser by pointing it to http://localhost/CakeTooDoo/tasks/add, and try to add a task with an empty title. It will show the following error message:
Read more
  • 0
  • 0
  • 2328

article-image-formatting-and-enhancing-your-moodle-materials-part-1
Packt
18 Nov 2009
7 min read
Save for later

Formatting and Enhancing Your Moodle Materials: Part 1

Packt
18 Nov 2009
7 min read
There are three main types of Moodle pages to consider when it comes to design: Moodle front pages Moodle course pages Moodle activities Before we go into detail about design considerations, let's look at examples of each of these to see how we can improve them with a few basic steps. Moodle front page If we take Moodle straight out of the box, set up some blocks for the main menu, provide some useful links, and set the front page settings to show a list of courses, we could have something like this: BEFORE It's functional enough, but not very engaging. Just by making a few changes, we can make the front page much more interesting and readable: AFTER What's changed? There's a new theme (Moodle speak for the color scheme and automatic font choices). As we'll see in a bit, some themes also include tabs and drop-down menus. There's an appropriate image in the top-center of the screen to draw users in. The About this site block has a photo of the administrator, which provides a personal touch. There's an easily-identifiable "start here icon"—another helpful feature that guides your users in the right direction. Moodle course page Like the Moodle front page, a standard course page automatically creates three columns for us to fill with text. If we choose a topics format from the Settings menu and write out a list of activities and links for our course, it could look something like this: BEFORE The problem here is that it's difficult to distinguish important information from unimportant information. There's a lot of scrolling to be done, and there are no visual clues as to what the course page is about. Here's one way of transforming the page: AFTER What's changed? There's a new theme. The theme includes tabs with links to key parts of the site. There's an image related to the course topic (teaching) at the top of the course page. The long list in the previous version has been reduced to a more manageable size. Important information is at the top of the page, and is in a larger font size. It contrasts with less important information, which has a smaller font size. Lines are used to separate different sorts of information. There is more color harmony—at attempt to get the colors to blend. There's an avatar introduction in the left block for new users. Moodle activity When we're pushed for time, it's all too tempting just to set out a list of references without paying due attention to instructions and a helpful hierarchy of information, as in the following example: BEFORE There's a lot of information here. We can use the Book module to organize the information, and make the page more readable, as in the following transformation: AFTER What's changed? The previous list has been divided into sections in the Book module There's a "how-to" section at the beginning of the Table of Contents Graphics from the target websites have been included as visual clues The Tool labels such as Audacity and Findsounds are in a larger font size to make them stand out An action girl icon indicates task instructions Task instructions are in bold blue to make them stand out A grid is used to separate sections As we can see, by enhancing the visual design of our sites we can make our materials more engaging and effective. We can also make them more attractive by improving the quality of the audio, images, and video that we use. Here are some principles we could take on board: Contrast Consider hierarchies of importance in your materials. The default font size on HTML pages is 12 points, similar to what you're reading now. Vary the size to make more important information stand out. You can also use images, buttons, and navigation signs to help users see the function of pages and content more quickly and remember it. Consistency Being consistent in your use of fonts for certain sorts of information, font sizes for ranking information, and navigation links will make it easier for users to understand the site and will make it more aesthetically pleasing. It's also better not to use too many different fonts or make your site too fancy or you will end up with a dog's breakfast. As a rule, it'll look better if you use different sizes of a limited number of fonts, rather than including lots of different fonts. To promote design consistency on your Moodle site, consider setting up a style guide so that all teachers use the same design framework. Alignment A basic principle of graphic design is to make sure that the objects on your page are aligned with each other. Imagine a grid that they stick to. Aligned objects look more professional and enhance contrast within pages. Moodle organizes that automatically for us with front pages and course pages, but when we set up instruction pages for activities, we need to keep alignment principles in mind, as we have more design freedom. Quality Aim for the best quality audio recordings and images. It is likely to make a big difference to language learners if they can listen to clear recordings and easily identify the content of images. This article Each of the following sections in this article contributes to the above principles by demonstrating some of the tools available in Moodle that help you with your design. You'll find a consideration of these and other website design issues at http://www.asktog.com/basics/firstPrinciples.html. Here are the main topics covered in this article: Text Images Videos Sound Navigation Blocks Layout Style guide Accessibility Feedback Text There are two main ways of entering text in Moodle: Adding text pages Adding web pages using the HTML editor The most common way is by using the HTML editor. Most of this section on text will look at formatting options using that. Adding text pages When you select Add a resource... and then Compose a text page, you get a choice of formatting options for your page. You might find it useful to use the Moodle auto-format, as it automatically creates emoticons, paragraphs, and hyperlinks for you if you write in web addresses. Creating hyperlinks is a little more time-consuming if you choose the HTML format, as you have to create all hyperlinks manually. Markdown format is also useful if you want to create a structured document with lists and emphasis. You can, of course, produce all these in the HTML format, using the editing menu. The following options are available when you select Add a resource... and then Compose a text page. Formatting options Details Moodle auto-format This has limited formatting options, but will automatically turn URLs like http://moodle.org into hyperlinks and will include emoticons like J when you type :). It keeps line breaks and converts blank lines into new paragraphs. HTML format This does not automatically format text, but gives you a wide range of possibilities for editing your text. It allows you to change font faces, font sizes, and color, as well as embed graphic images, sound, and video. Note that if you select Compose a text page and then the HTML format option, you will need to enter pure HTML-that's the code that produces web pages. If you are not familiar with HTML, you'll be better off choosing Compose a web page and then using the HTML graphic editor. Plain text format This format keeps spaces and new lines, but no other formatting is available. Markdown format Markdown allows you to easily add emphasis (bold, italics), structure (bullet points and headings), and links (to images or other web resources). You can use Markdown in many places in Moodle. Simply select it from the formatting drop-down list, which is found below the text entry area, wherever you have the choice.  
Read more
  • 0
  • 0
  • 3679
article-image-archiva-team-part-1
Packt
18 Nov 2009
11 min read
Save for later

Archiva in a Team: Part 1

Packt
18 Nov 2009
11 min read
Roles and permissions In preparation for the latter sections of this article, let's familiarize ourselves with the user roles and permissions available in Archiva. The list of available roles can be seen by clicking a user account in User Management and then clicking on the Edit Roles link. Some of the roles in Archiva are resource-based with each repository treated as a resource. This means that access is controlled at the repository level. There are eight types of roles available in Archiva. They are: System Administrator: Provides access to Manage and Administration sections, user administration privileges, and read and write permissions to all repositories. User Administrator: Provides access to User Management and User Roles pages. Global Repository Manager: Provides read and write permissions to all repositories. Global Repository Observer: Provides read permission to all repositories. Repository Manager (resource level): Provides read and write permissions to a given repository. Repository Observer (resource level): Provides read permission to a given repository. Registered User: The default role assigned to a user who has registered in Archiva. Guest: Provides the same permissions that are enabled for the built-in guest user account, which we will discuss later on. A user assigned with a Global Repository Manager or resource level Repository Manager role automatically gains the Global Repository Observer or resource level Repository Observer role respectively. Users assigned with a Repository Manager role should be able to access the Find section as well as Upload Artifact and Delete Artifact menu in the web application. On the other hand, users with a Repository Observer role should only be able to access the Find section. Repository-level security applies to each corresponding operation. This means that a user will only be able to search, browse, and upload to or delete artifacts from those repositories that they have permission to access. When managing roles and permissions, another thing to take note of is the guest account. To enable access without authentication for a specific resource or operation, just assign the guest user the appropriate role. By default, the guest user is already assigned the Repository Observer role for internal and snapshots repositories. This allows anyone to be able to browse and search for artifacts from these repositories. If you edit the guest user account, you should be able to see the following configuration: As you can see the guest user doesn't yet have read access to the releases repository. In our examples, we will assume that the repository will be available to everyone that can access Archiva. So to make this consistent with the snapshots repository, check the Repository Observer box for releases and submit the form. You can see for yourself how the guest account works by logging out of Archiva and clicking Browse on the navigation menu. The artifacts that were requested and were downloaded to our proxy repository should be visible in the Browse page, similar to what is seen in the following screenshot: As we work through the rest of the article, we will cover a few more things about access control in Archiva. Now that we are familiar with the security basics, we are ready to tackle some of the more advanced features of Archiva. In the next section, we will learn techniques for configuring our Archiva repositories. Introducing repository groups In Archiva 1.1, the concept of repository groups (also known as virtual repositories) was introduced. Taking the meaning of the term virtual literally, these repositories are physically non-existent repositories. A virtual repository is simply a URL which gives a single interface to a group of managed repositories. Let's visualize this with a simple scenario. For example, we have a Maven 2 project which has dependencies on artifacts that reside in multiple repositories. In this case, we will assume that we have a nearby proxy cache configured in Archiva for each of them. Given this scenario, it would mean that we have to configure each of these repositories in our settings.xml (or POM), in order for us to get the needed artifacts and to be able to build our project. If these repositories are secured, we also need to configure our credentials for each. This leaves us with a long (and possibly messy) settings.xml. Remember, a messy configuration is an attraction for errors. To avoid this problem, we can make use of repository groups in Archiva. We can create a repository group and configure or add multiple repositories under that group. So when an artifact request is made (for example, by Maven) using the repository group URL, the repositories underneath it will be searched until the requested artifact is found and returned to the client. The following section teaches us how to configure repository groups and experience their strength first-hand. Configuring and using repository groups Before jumping into configuration, it is good to see how it will be without the aid of repository groups. As the Centrepoint project refers to the released version—POM Apache Maven 2: Effective Implementations Book, anyone who builds that project must be able to get the organization POM from the releases repository. This is a perfect setup for using repository groups. Let's begin by wiping out our local repository again and building the Centrepoint project. centrepoint$ mvn clean install The build should fail with the following error: [INFO] Scanning for projects...Downloading: http://localhost:8081/archiva/repository/internal/com/effectivemaven/effectivemaven-parent/1/effectivemaven-parent-1.pom[INFO] ----------------------------------------------------------[ERROR] FATAL ERROR[INFO] ----------------------------------------------------------[INFO] Failed to resolve artifact.GroupId: com.effectivemavenArtifactId: effectivemaven-parentVersion: 1Reason: Unable to download the artifact from any repository com.effectivemaven:effectivemaven-parent:pom:1from the specified remote repositories: internal (http://localhost:8081/archiva/repository/internal)   Our organization POM cannot be found because it resides in the Archiva releases repository, and we don't have it configured in our settings.xml. The version in ../effectivemaven-parent/pom.xml is also not used because the versions now differ. To get past this problem, we must add the following configuration in the settings.xml: <profiles> <profile> <id>repositories</id> <activation> <activeByDefault>true</activeByDefault> </activation> <repositories> <repository> <id>releases</id> <name>Archiva Managed Releases Repository</name> <url> http://localhost:8081/archiva/repository/releases </url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </profile> </profiles> We already configured the <server> credentials for the releases repository when we tried deploying to Archiva using Maven so we no longer need to configure that. If you try building Centrepoint again, the build will still fail. Notice that Maven didn't even seem to try looking for the artifact from the releases repository we added previously. This is because we have locked down Maven to use only the local mirror repository internal. This is the effect of the <mirrorOf>*</mirrorOf> configuration in our settings.xml, Staying in Control with Archiva. Just change it to <mirrorOf>*,!releases</mirrorOf> so that Maven would respect the additional repositories. Execute the build again. This time we should be able to get a successful build. However, for every member of the team working on the Centrepoint project, the settings.xml (now over 40 lines long) is needed at the minimum. As the project grows bigger, more artifacts are added. Also, if these new artifacts are located in other repositories, you would need to add this repository to your settings.xml and so on and so forth. We already learned at the start of this section that in situations such as this, a repository group can make things easier for us developers. Let us see how we can create one. Let's go back to our running Archiva instance. Click Repository Groups, then type public in the Identifier field on the upper right-hand corner of the page and click Add Group. We now have a virtual repository named public with the following URL: http://localhost:8081/archiva/repository/public. You may change the name of the repository group to a more appropriate one if the repositories are not really for public consumption. To add managed repositories under the group, just select the repository you would like to add from the list under the created group and click Add Repository. Add the releases and internal repositories (this order is used so that requests for the organization's artifacts are never made on external proxied repositories). Note that we don't want to add the snapshots repository to the group as that might change the behavior of the repository. One example of this is when dealing with version ranges. You might end up getting a snapshot version instead of a released version. Now, with this configuration, we are telling Archiva that if an artifact request is made on the repository group public, it should look for the artifact in these two repositories (based on the order they are listed) and return the first matching artifact it sees. You can change the ordering of the repositories to be searched by moving a repository up or down the repository group configuration via the Up and Down icons. After configuration, the page should look similar to the following: Now that we have a repository group that we can use, let's configure it in our settings.xml. Remove the profile we added previously, and adjust the mirror section as follows: <mirrors> <mirror> <id>public</id> <url>http://localhost:8081/archiva/repository/public</url> <mirrorOf>*</mirrorOf> </mirror> </mirrors> Notice how much shorter and simpler our settings.xml is now. Group credentials The guest user has access to all of the repositories in the group so we don't need a corresponding <server> for the mirror. However, if read access control applies to any repositories in the group, make sure to add a <server> for the ID of the mirror (not the underlying repositories that are no longer visible to Maven). The existing <server> definitions continue to be used for deployment, as deployment cannot be done to a group. Let's try building Centrepoint again, but this time with a clean local repository, using the new settings.xml. We should be able to see both com.effectivemaven: effectivemaven-parent:pom:1 and the other dependencies from the central repository being retrieved from our public repository group, ending with a successful build as follows: [INFO] Scanning for projects...Downloading: http://localhost:8081/archiva/repository/public//com/effectivemaven/effectivemaven-parent/1/effectivemaven-parent-1.pom1K downloaded[INFO] Reactor build order:...[INFO] ----------------------------------------------------------[INFO] Building Centrepoint[INFO] task-segment: [clean, install][INFO] ----------------------------------------------------------Downloading: http://localhost:8081/archiva/repository/public//org/apache/maven/plugins/maven-clean-plugin/2.2/maven-clean-plugin-2.2.pom3K downloadedDownloading: http://localhost:8081/archiva/repository/public//org/apache/maven/plugins/maven-plugins/10/maven-plugins-10.pom What else can we do with repository groups? Consider, for example, that we added new dependencies to our Centrepoint project and these dependencies are projects being worked on by another team within the company. Let's say the other team have their own deployment repository (separate from ours) managed by Archiva as well. We no longer have need to make any changes in our settings.xml (or POM). The repository just needs to be added in the public repository group and the appropriate permissions assigned to the Centrepoint project developers' accounts. Configuration is much simpler now and is concentrated in Archiva itself. Developers and team members won't have to configure their settings.xml each time a new repository is needed.   RSS feeds—discovering new artifacts in your repository RSS has become the de facto standard with regard to news feeds and updates on the web. The Archiva community has seen how the project can take advantage of this current trend by providing RSS feeds for new artifacts in the repository. Projects that use or depend on specific libraries would be able to know when a new release is available or when there is a new build. This is especially useful when a project is dependent on a fix that would be available in the next release or in the next build. A Repository Observer role is required at least in order to subscribe to a feed in Archiva. There are two levels of RSS feeds available in Archiva: repository level and artifact level. In the following sections, we will be using Thunderbird's RSS feed reader for demonstration purposes. You can get Thunderbird from http://www.mozillamessaging.com/en-US/thunderbird/ and can set it up using the installation guides at http://www.mozillamessaging.com/en-US/support/. You can also use other RSS feed readers such as Google Reader. If access to your repositories require authentication, your feed reader must support authentication. If security is lenient, you can just disable authentication for read operations to your repository by granting the guest account the Repository Observer role.
Read more
  • 0
  • 0
  • 1856

article-image-papervision3d-external-models-part-1
Packt
18 Nov 2009
22 min read
Save for later

Papervision3D External Models: Part 1

Packt
18 Nov 2009
22 min read
This article covers the following: Modeling for Papervision3D Preparing for loading models Creating and loading models using Autodesk 3ds Max Loading an animation from Autodesk 3ds Max Creating and loading models using SketchUp Creating and loading models using Blender Controlling loaded materials Let's start off by having a look at some general practices to keep in mind when modeling for Papervision3D. Modeling for Papervision3D In this section, we will discuss several techniques that relate to modeling for Papervision3D. As Papervision3D is commonly used for web-based projects, modeling requires a different mindset than modeling for an animated movie, visualization, or game. Most of the techniques discussed relate to improving performance. This section is especially useful for modelers who need to create models for Papervision3D. Papervision3D PreviewerPapervision3D Previewer is a small program that should be part of every modeller's toolbox. This tool comes in handy for testing purposes. It allows a modeler to render an exported model in Papervision3D, and it displays some statistics that show how the model performs. At the time of writing, this tool was not compatible with Papervision3D 2.1, which could result in small problems when loading external models.Papervision3D Previewer can be downloaded from http://code.google.com/p/mrdoob/wiki/pv3dpreviewer Keep your polygon count low Papervision3D is a cutting edge technology that brings 3D to the Flash Player. It does this at an amazing speed relative to the capabilities of the Flash player. However, performance of Papervision3D is just a fraction of the performance that can be achieved with hardware-accelerated engines such as used by console games. Even with hardware-accelerated games there is a limit to the number of polygons that can be rendered, meaning there is always a compromise between detail and performance. This counts even more for Papervision3D, so always try to model using as few polygons as possible. Papervision3D users often wonder what the maximum number of triangles is that the Flash player can handle. There is no generic answer to this question, as performance depends on more factors than just the number of triangles. On average, the total triangle count should be no more than 3000, which equals 1500 polygons (remember that one polygon is made of two triangles). Unlike most 3D modeling programs, Papervision3D is triangle based and not polygon based. Add polygons to resolve artifacts Although this seems to contradict the previous suggestion to keep your polygon count low, sometimes you need more polygons to get rid of texture distortion or to reduce z-sorting artifacts. z-sorting artifacts will often occur in areas where objects intersect or closely intersect each other. Subdividing polygons in those areas can make z-sorting more accurate. Often this needs to be done by creating new polygons for the intersecting triangles of approximately the same size. There are several approaches to prevent z-sorting problems. Depending on the object you're using, it can be very time consuming to tweak and find the optimal amount and location of polygons. The amount of polygons you add in order to solve the problem should still be kept as low as possible. Finding the optimal values for your model will often result in switching a lot between Papervision3D and the 3D modeling program. Keep your textures small Textures used in the 3D modeling tool can be exported along with the model to a format that is readable for Papervision3D. This is a valuable feature as the texture will automatically be loaded by Papervision3D. However, the image, which was defined in the 3D authoring tool, will be used exactly as provided by Papervision3D. If you choose a 1024 by 1024 pixels image as the texture, for example the wheels of a car, Papervision3D loads the entire image and draws it on the wheel of a car that appears on screen at a size of 50 by 50 pixels for example. There are several problems related to this: It's a waste of bandwidth to load such a large image. Loading any image takes time, which should be kept as short as possible. It's a waste of capacity. Papervision3D needs to resize the image from 1024 by 1024 pixels to an image, which will be, for example, maximal 50 by 50 pixels on screen. Always choose texture dimensions that make sense for the application using it, and keep in mind that they have to be power of two. This will enable mipmapping and smoothing, which come without extra performance costs. Use textures that Flash can read 3D modeling programs usually read a variety of image sources. Some even support reading Adobe Photoshop's native file-format PSD. Flash can load only GIF, JPG, or PNG files at run time. Therefore, stick to these formats in your model so that you do not have to convert the textures when the model needs to be exported to Papervision3D. Use UV maps If your model is made up of several objects and textures, it's a good idea to use UV mapping, which is the process of unwrapping the model and defining all its textures into one single image. This way we can speed up initial loading of an application by making one request from Flash to load this image instead of loading dozens of images. UV mapping can also be used to tile or reuse parts of the image. The more parts of the UV-mapped image you can reuse, the more bandwidth you'll save. Always try to keep your UV-mapped image as small as possible, just as with keeping your normal textures small. In case you have a lot of objects sharing the same UV map and you need a large canvas to unwrap the UV map, be aware of the fact that the maximum image size supported by Flash Player 9 is 2880x2880 pixels. With the benefits of power of two textures in mind, the maximum width and height is 2048x2048 pixels. Baking textures Baking textures is the process of integrating shadows, lighting, reflection, or entire 3D objects into a single image. Most 3D modeling tools support this. This contradicts what has been said about tiling images in UV maps, as baking results in images that usually can only be used once because of the baked information on the texture. However, it can increase the level of realism of your application, just like shading does, but without the loss of performance caused by calculating shading in real time. Never use them in combination with a tiling image, as repeated shading, for instance, will result in unnatural looking renders. Therefore, each texture needs to be unique, which will cause longer loading times before you can show a scene. Use recognizable names for objects and materials It is always a good convention to use recognizable names for all your objects. This counts for the classes, methods, and properties in your code, and also for the names of the 3D objects in your modeling tool. Always think twice before renaming an object that is used by an application. The application might use the name of an object as the identifier to do something with it—for example, making it clickable. When working in a team of modelers and programmers, you really need to make this clear to the modelers as changing the name of an object can easily break your application. Size and positioning Maintaining the same relative size for your modeled objects, as you would use for instantiating primitives in your scene, is a good convention. Although you could always adjust the scale property of a loaded 3D model, it is very convenient when both Papervision3D and your modeling tool use the same scale. Remember that Papervision3D doesn't have a metric system defining units of a certain value such as meters, yards, pixels, and so on. It just uses units. Another convention is to position your object or objects at the origin of the 3D space in the modeling tool. Especially when exporting a single object from a 3D modeling tool, it is really helpful if it is located at a position of 0 on all axes. This way you can position the 3D object in Papervision3D by using absolute values, without needing to take the offset into account. You can compare this with adding movie clips to your library in Flash. In most cases, it is pretty useful when the elements of a movie clip are centered on their registration point. Finding the balance between quality and performance For each project you should try to find the balance between lightweight modeling and quality. Because each project is different in requirements, scale, and quality, there is no rule that applies for all. Keep the tips mentioned in the previous sections in mind and try to be creative with them. If you see a way to optimize your model, then do not hesitate to use it. Before we have a look at how to create and export models for Papervision3D, we will create a basic application for this purpose. Creating a template class to load models In order to show an imported 3D model using Papervision3D, we will create a basic application. Based on the orbit example (code bundle-chapter 6, click the following link to download: http://www.packtpub.com/files/code/5722_Code.zip) we create the following class. Each time we load a new model we just have to alter the init() method. First, have a look at the following base code for this example: package { import flash.events.Event; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.primitives.Cube; import org.papervision3d.view.BasicView; public class ExternalModelsExample extends BasicView { private var model:DisplayObject3D; private var rotX:Number = 0.1; private var rotY:Number = 0.1; private var camPitch:Number = 90; private var camYaw:Number = 270; private var easeOut:Number = 0.1; public function ExternalModelsExample() { stage.frameRate = 40; init(); startRendering(); } private function init():void { model = new Plane(); scene.addChild(model); } private function modelLoaded(e:FileLoadEvent):void { //To be added } override protected function onRenderTick(e:Event=null):void { var xDist:Number = mouseX - stage.stageWidth * 0.5; var yDist:Number = mouseY - stage.stageHeight * 0.5; camPitch += ((yDist * rotX) - camPitch + 90) * easeOut; camYaw += ((xDist * rotY) - camYaw + 270) * easeOut; camera.orbit(camPitch, camYaw); super.onRenderTick(); } }} We have created a new plane using a wireframe as its material. The plane is assigned to a class property named model, which is of the DisplayObject3D type. In fact, any external model is a do3D. No matter what type of model we load in the following examples, we can always assign it to the model property. The classes that we'll use for loading 3D models all inherit from DisplayObject3D. Now that we have created a default application, we are ready to create our first model in 3D Studio Max, export it, and then import it into Papervison3D. Creating models in Autodesk 3ds Max and loading them into Papervision3D Autodesk 3ds Max (also known as 3D Studio Max or 3ds Max) is one of the widely-known commercial 3D modeling and animation programs. This is a good authoring tool to start with, as it can save to two of the file formats Papervision3D can handle. These are: COLLADA (extension *.dae): An open source 3D file type, which is supported by Papervision3D. This is the most advanced format and has been supported since Papervision3D's first release. It also supports animations and is actually just a plain text XML file. 3D Studio (extension *.3ds): As the name suggests, this is one of the formats that 3ds Max natively supports. Generally speaking it is also one of the most common formats to save 3D models in. As of 3ds Max version 9, there is a built-in exporter plugin available that supports exporting to COLLADA. However, you should avoid using this, as at the time of writing, the models it exports are not suitable for Papervision3D. Don't have a license of 3ds Max and want to get along with the following examples? Go to www.autodesk.com to download a 30-day trial. Installing COLLADA Max An exporter that does support COLLADA files suitable for Papervision3D is called COLLADA Max. This is a free and open source exporter that works with all versions of 3ds Max 7 and higher. Installing this exporter is easy. Just follow the steps mentioned below: Make sure you have installed 3ds Max version 7 or higher. Go to http://sourceforge.net/projects/colladamaya/. Click on View all files and select the latest COLLADA Max version. (At the time of writing this is COLLADA Max NextGen 0.9.5, which is still in beta, but is the only version that works with 3ds Max 2010). Save the download somewhere on your computer. Run the installer. Click Next, until the installer confirms that the exporter is installed. Start 3ds Max and double check if we can export using the COLLADA or COLLADA NextGen filetype, as shown in the following screenshot: If the only COLLADA export option is Autodesk Collada, then something went wrong during the installation of COLLADA Max, as this is not the exporter that works with Papervision3D. Now that 3ds Max is configured correctly for exporting a file format that can be read by Papervision3D, we will have a look at how to create a basic textured model in 3ds Max and export it to Papervision3D. Creating the Utah teapot and export it for Papervision3D If you already know how to work with 3ds Max, this step is quite easy. All we need to do is create the Utah teapot, add UV mapping, add a material to it, and export it as COLLADA. However, if you are new to 3ds Max, the following steps needs to be clarified. First, we start 3ds Max and create a new scene. The creation of a new scene happens by default on startup. The Utah teapot is one of the objects that comes as a standard primitive in 3ds Max. This means you can select it from the default primitives menu and draw it in one of the viewports. Draw it in the top viewport so that the teapot will not appear rotated over one of its axes. Give it a Radius of 250 in the properties panel on the right, in order to make it match with the units that we'll use in Papervision3D. Position the teapot at the origin of the scene. You can do this by selecting it and changing the x, y, and z properties at the bottom of your screen. You would expect that you need to set all axes to 0, although this is not the case. In this respect, the teapot differs from other primitives in 3ds Max, as the pivot point is located at the bottom of the teapot. Therefore, we need to define a different value for the teapot on the z-axis. Setting it to approximately -175 is a good value. To map a material to the teapot, we need to define a UV map first. UV mapping is also known as UVW mapping. Some call it UV mapping and others call it UVW mapping. 3ds Max uses the term UVW mapping. While having the teapot still selected, go to modify and then select UVW Mapping from the modifier list. Select Shrink Wrap and click Fit in the Alignment section. This will create a UVW map for us. Open the material editor using keyboard shortcut m. Here we define the materials that we use in 3ds Max. Give the new material a name. Replace 01 – Default with a material name of your choice—for example, teapotMaterial. Provide a bitmap as the diffuse material. You can do this by clicking on the square button, at the right of the Diffuse value within Blinn Basic Parameters section. A new window called Material/Map Browser will open. Double-click Bitmap to load an external image. Select an image of your choice. We will use teapotMaterial.jpg The material editor will now update and show the selected material on an illustrative sphere. This is your newly-created material, which you need to drag on the created teapot. The teapot model can now be exported. Depending on the version of the installed COLLADA exporter, select COLLADA or COLLADA NextGen. Note that you should not export using Autodesk Collada, as this exporter doesn't work properly for Papervision3D. Give it a filename of your choice, for example teapot, and hit Save. The exporter window will pop up. The default settings are fine for exporting to Papervision3D, so click OK to save the file. Save the model in the default 3ds Max file format (.max) somewhere on your local disk, so we can use it later when discussing other ways to export this model to Papervision3D. The model that we have created and exported is now ready to be imported by Papervision3D. Let's take a look at how this works. Importing the Utah teapot into Papervision3D To work with the exported Utah teapot, we will use the ExternalModelsExample project that we created previously in this article. Browse to the folder inside your project where you have saved your document class. Create a new folder called assets and copy to this folder, the created COLLADA file along with the image used as the material of the teapot. The class used to load an external COLLADA file is called DAE, so let's import it. import org.papervision3d.objects.parsers.DAE; This type of class is also known as a parser, as it parses the model from a loaded file. When you have a closer look at the source files of Papervision3D and its model parsers, you will probably find out about the Collada class. This might be a little confusing as we use the DAE parser to load a COLLADA file and we do not use the Collada parser. Although you could use either, this article uses the DAE parser exclusively, as it is a more recent class, supporting more features such as animation. There is no feature that is supported by the Collada parser, and is not supported by the DAE parser. Replace all code inside the init() method with the following code that loads a COLLADA file: model = new DAE();model.addEventListener(FileLoadEvent.LOAD_COMPLETE,modelLoaded);DAE(model).load("assets/teapot.DAE"); Because model is defined as a DisplayObject3D class type, we need to cast it to DAE to make use of its methods so that we can call the load() method. An event listener is defined, waiting for the model to be completely loaded and parsed. Once it is loaded, the modelLoaded() method will be triggered. It is a good convention to add models only to the scene once the model is completely loaded. Add the following line of code to the modelLoaded() method: scene.addChild(model); COLLADA Utah Teapot Example Publishing this code will result in the teapot with the texture as created in 3ds Max. In real-world applications it is good practice to keep your models in one folder and your textures in another. You might want to organize the files similar to the following structure: Models in /assets/models/ Textures in /assets/textures/ By default, textures are loaded from the same folder as the model is loaded from, or optionally from the location as specified in the COLLADA file. To include the /assets/textures/ folder we can add a file search path, which defines to have a look in the specified folder, to see if the file is located there, in case none can be found on the default paths. This can be defined as follows: daeModel.addFileSearchPath("assets/textures"); You can call this method multiple times, in order to have multiple folders defined. Internally, in Papervision3D, it will loop through an array of file paths. Exporting and importing the Utah teapot in 3ds format Now that we have seen how to get an object from 3ds Max into a Papervision3D project, we have a look at another format that is supported by both 3ds Max and Papervision3D. This format is called 3D Studio, using a 3ds extension. It is one of the established 3D file formats that are supported by most 3D modeling tools. Exporting and importing is very similar to COLLADA. Let's first export the file to the 3D Studio format. Open the Utah teapot, which we've modeled earlier in this article. Leave the model as it is, and go straight to export. This time we select 3D Studio (*.3DS) as the file type. Save it into your project folder and name it teapot. Click OK when asked whether to preserve Max's texture coordinates. If your model uses teapotMaterial.jpg, or an image with more than eight characters in its filename, the exporter will output a warning. You can close this warning, but you need to be aware of the output message. It says that the bitmap filename is a non-8.3 filename, that is, a maximum amount of 8 characters for the filename and a 3-character extension. The 3D Studio file is an old format, released at the time when there was a DOS version of 3ds Max. Back then it was an OS naming convention to use short filenames, known as 8.3 filenames. This convention still applies to the 3D Studio format, for the sake of backward compatibility. Therefore, the reference to the bitmap has been renamed inside the exported 3D Studio file. Because the exported 3D Studio file changed only the reference to the bitmap filename internally and it did not affect the file it refers to, we need to create a file using this renamed file reference. Otherwise, it won't be able to find the image. In this case we need to create a version of the image called teapotMa.jpg. Save this file in the same folder as the exported 3D Studio file. As you can see, it is very easy to export a model from 3ds Max to a format Papervision3D can read. Modeling the 3D object is definitely the hardest and most time consuming part, simply because creating models takes a lot of time. Loading the model into Papervision3D is just as easy as exporting it. First, copy the 3D Studio file plus the renamed image to the assets folder of your project. We can then alter the document class in order to load the 3ds file. The class that is used to parse a 3D Studio file is called Max3DS and needs to be imported. import org.papervision3d.objects.parsers.Max3DS; In the init() method you should replace or comment the code that loads the COLLADA model from our previous example, with the following: model = new Max3DS();model.addEventListener(FileLoadEvent.LOAD_COMPLETE,modelLoaded);Max3DS(model).load("assets/teapot.3ds", null, "./assets/"); As the first parameter of the load method, we pass a file reference to the model we want to load. The second parameter defines a materials list, which we will not use for this example. The third and final parameter defines the texture folder. This folder is relative to the location of the published SWF. Note that this works slightly different than the DAE parser, which loads referenced images from the path relative to the folder in which the COLLADA file is located or loads images as specified by the addFileSearchPath() method. ExternalModelsExample Publish the code and you'll see the same teapot. However, this time it's using the 3D Studio file format as its source. Importing animated models The teapot is a static model that we exported from a 3D program and loaded into Papervision3D. It is also possible to load animated models, which contain one or multiple animations. 3ds Max is one of the programs in which you can create an animation for use in Papervision3D. Animating doesn't require any additional steps. You can just create the animation and export it. This also goes for other modeling tools that support exporting animations to COLLADA. For the sake of simplicity, this example will make use of a model that is already animated in 3ds Max. The model contains two animations, which together make up one long animation on a shared timeline. We will export this model and its animation to COLLADA, load it into Papervision3D, and play the two animations. Open animatedMill.max in 3ds Max. This file can be found in the zip file that can be downloaded from: http://www.packtpub.com/files/code/5722_Code.zip. You can see the animation of the model directly in 3ds Max by clicking the play button in the menu at the bottom right corner, which will animate the blades of the mill. The first 180 frames animate the blades from left to right. Frames 181 to 360 animate the blades from right to left. As the model is already animated, we can go ahead with exporting, without making any changes to the model. Export it using the COLLADA filetype and save it somewhere on your computer. When the COLLADA Max exporter settings window pops up, we need to check the Sample animation checkbox. By default Start and End are set to the length of the timeline as it is defined in 3ds Max. In case you just want to export a part of it, you can define the start and end frames you want to export. For this example we leave them as they are: 0 and 360. By completing these steps you have successfully exported an animation in the COLLADA format for Papervision3D. Now, have a look at how we can load the animated model into Papervision3D. First, you need to copy the exported COLLADA and the applied material—Blades.jpg, House.jpg, and Stand.jpg—to the assets folder of your project. To load an animated COLLADA, we can use the DAE class again. We only need to define some parameters at instantiation, so the animation will loop. model = new DAE(true,null,true);model.addEventListener(FileLoadEvent.LOAD_COMPLETE,modelLoaded);DAE(model).load("assets/animatedMill.dae"); Take a look at what these parameters stand for.
Read more
  • 0
  • 0
  • 3013
Modal Close icon
Modal Close icon