Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
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-getting-started-scratch-14-part-2
Packt
16 Oct 2009
7 min read
Save for later

Getting Started with Scratch 1.4 (Part 2)

Packt
16 Oct 2009
7 min read
Add sprites to the stage In the first part we learned that if we want something done in Scratch, we tell a sprite by using blocks in the scripts area. A single sprite can't be responsible for carrying out all our actions, which means we'll often need to add sprites to accomplish our goals. We can add sprites to the stage in one of the following four ways: paint new sprite, choose new sprite from file, get a surprise sprite, or by duplicating a sprite. Duplicating a sprite is not in the scope of this article. The buttons to insert a new sprite using the other three methods are directly above the sprites list. Let's be surprised. Click on get surprise sprite (the button with the "?" on it.). If the second sprite covers up the first sprite, grab one of them with your mouse and drag it around the screen to reposition it. If you don't like the sprite that popped up, delete it by selecting the scissors from the tool bar and clicking on the sprite. Then click on get surprise sprite again. Each sprite has a name that displays beneath the icon. See the previous screenshot for an example. Right now, our sprites are cleverly named Sprite1 and Sprite2. Get new sprites The create new sprite option allows you to draw a sprite using the Paint Editor when you need a sprite that you can't find anywhere else. You can also create sprites using third-party graphics programs, such as Adobe Photoshop, GIMP, and Tux Paint. If you create a sprite in a different program, then you need to import the sprite using the choose new sprite from file option. Scratch also bundles many sprites with the installation, and the choose new sprite from file option will allow you to select one of the included files. The bundled sprites are categorized into Animals, Fantasy, Letters, People, Things, and Transportation, as seen in the following screenshot: If you look at the screenshot carefully, you'll notice the folder path lists Costumes, not sprites. A costume is really a sprite. If you want to be surprised, then use the get surprise sprite option to add a sprite to the project. This option picks a random entry from the gallery of bundled sprites. We can also add a new sprite by duplicating a sprite that's already in the project by right-clicking on the sprite in the sprites list and choosing duplicate (command C on Mac). As the name implies, this creates a clone of the sprite. The method we use to add a new sprite depends on what we are trying to do and what we need for our project. Time for action – spin sprite spin Let's get our sprites spinning. To start, click on Sprite1 from the sprites list. This will let us edit the script for Sprite1. From the Motion palette, drag the turn clockwise 15 degrees block into the script for Sprite1 and snap it in place after the if on edge, bounce block. Change the value on the turn block to 5. From the sprites list, click on Sprite2. From the Motion palette, drag the turn clockwise 15 degrees block into the scripts area. Find the repeat 10 block from the Control palette and snap it around the turn clockwise 15 degrees block. Wrap the script in the forever block. Place the when space key pressed block on top of the entire stack of blocks. From the Looks palette, snap the say hello for 2 secs block onto the bottom of the repeat block and above the forever block. Change the value on the repeat block to 100. Change the value on the turn clockwise 15 degrees block to 270. Change the value on the say block to I'm getting dizzy! Press the Space bar and watch the second sprite spin. Click the flag and set the second sprite on a trip around the stage. What just happened? We have two sprites on the screen acting independently of each other. It seems simple enough, but let's step through our script. Our cat got bored bouncing in a straight line across the stage, so we introduced some rotation. Now as the cat walked, it turned five degrees each time the blocks in the forever loop ran. This caused the cat to walk in an arc. As the cat bounced off the stage, it got a new trajectory. We told Sprite2 to turn 270 degrees for 100 consecutive times. Then the sprite stopped for two seconds and displayed a message, "I'm getting dizzy!" Because the script was wrapped in a forever block, Sprite2 started tumbling again. We used the space bar as the control to set Sprite2 in motion. However, you noticed that Sprite1 did not start until we clicked the flag. That's because we programmed Sprite1 to start when the flag was clicked. Have a go hero Make Sprite2 less spastic. Instead of turning 270 degrees, try a smaller value, such as 5. Sometimes we need inspiration So far, we've had a cursory introduction to Scratch, and we've created a few animations to illustrate some basic concepts. However, now is a good time to pause and talk about inspiration. Sometimes we learn by examining the work of other people and adapting that work to create something new that leads to creative solutions. When we want to see what other people are doing with Scratch, we have two places to turn. First, our Scratch installation contains dozens of sample projects. Second, the Scratch web site at http://scratch.mit.edu maintains a thriving community of Scratchers. Browse Scratch's projects Scratch includes several categories of projects for Animation, Games, Greetings, Interactive Art, Lists, Music and Dance, Names, Simulations, Speak up, and Stories. Time for action – spinner Let's dive right in. From the Scratch interface, click the Open button to display the Open Project dialog box, as seen in the following screenshot. Click on the Examples button. Select Simulations and click OK. Select Spinner and click OK to load the Spinner project. Follow the instructions on the screen and spin the arrow by clicking on the arrow. We're going to edit the spinner wheel. From the sprites list, click on Stage. From the scripts area, click the Backgrounds tab. Click Edit on background number 1 to open the Paint Editor. Select a unique color from the color palette, such as purple. Click on the paint bucket from the toolbar, then click on one of the triangles in the circle to change its color. The paint bucket is highlighted in the following screenshot. Click OK to return to our project. What just happened? We opened a community project called Spinner that came bundled with Scratch. When we clicked on the arrow, it spun and randomly selected a color from the wheel. We got our first look at a project that uses a background for the stage and modified the background using Scratch's built-in image editor. The Paint Editor in Scratch provides a basic but functional image editing environment. Using the Paint Editor, we can create a new sprite/background and modify a sprite/background. This can be useful if we are working with a sprite or background that someone else has created. Costume versus background A costume defines the look of a sprite while a background defines the look of the stage. A sprite may have multiple costumes just as the stage can have multiple backgrounds. When we want to work with the backgrounds on the stage, we use the switch to background and next background blocks. We use the switch to costume and next costume blocks when we want to manipulate a sprite's costume. Actually, if you look closely at the available looks blocks when you're working with a sprite, you'll realize that you can't select the backgrounds. Likewise, if you're working with the stage, you can't select costumes.
Read more
  • 0
  • 0
  • 5462

article-image-customizing-backend-editing-typo3-templates
Packt
22 Nov 2010
11 min read
Save for later

Customizing the Backend Editing in TYPO3 Templates

Packt
22 Nov 2010
11 min read
TYPO3 Templates Create and modify templates with TypoScript and TemplaVoila Build dynamic and powerful TYPO3 templates using TypoScript, TemplaVoila, and other core technologies. Customize dynamic menus, logos, and headers using tricks you won’t find in the official documentation. Build content elements and template extensions to overhaul and improve TYPO3’s default back-end editing experience. Follow along with the step-by-step instructions to build a site from scratch using all the lessons in the book in a practical example. Updating the rich text editor While we are making life easier for the editors, we can work on one of the areas they have to spend the most time in: the Rich Text Editor (RTE). The rich text editor allows anybody editing text or content in the TYPO3 backend to add formatting and styling such as bold or italics without using special syntax or HTML, and see the results in the text area immediately. This is also known as a WYSIWYG (What You See Is What You Get) editor and we've used it in the previous chapters to edit our own content: Out of the box, TYPO3 comes with the htmlArea RTE (extension key: rtehtmlarea), and it really is a good editor to work with. The problem is that it's configured by default to fit everybody, so it doesn't really fit anybody particularly well without a little bit of modification: it has it's own classes that we probably don't actually use, toolbars that may give too many options, and it blocks some handy tags such as the embed and object tags that we need for embedded video. Luckily, the htmlArea RTE is very configurable like everything in TYPO3 and allows us to override or add to almost all of its rules. There's an entire TSref document (http://typo3.org/documentation/documentlibrary/extension-manuals/rtehtmlarea/current), so we're not going to try to cover everything that is possible. The TSref is being updated with the new releases, so I recommend checking it out if you have any questions or want to get more information on configurations that we have only glossed over or skipped. As a final note, some of the configuration properties in this section will work on other RTE options, but many are special for the htmlArea RTE. We are going to talk about the htmlArea RTE because it is already installed by default and has a lot of powerful options, but you may choose to install a different editor as an extension in the future. TYPO3 allows us to replace the RTE in the backend with TYPO3 extensions, and we might want to replace the default htmlArea RTE if we need to support older browsers or use special features like plugins for editing images. If you are using a different editor, you may need to look at its documentation for any differences in configuration. Editing the TSconfig Configuration of the RTE is done completely in the TSconfig for the user or the page. We've used the TypoScript template for frontend configuration and layout, but the TSconfig is mainly used for configuring backend modules in TYPO3 like the RTE. The rich text editor is a backend module, so we need to use the TSconfig to configure it for our editors. The TSconfig can be modified through the Page properties view on any page in the Options tab (shown in the following screenshot): Above you can see an example of the TSconfig with some of the modifications that we are going to look at for the RTE. Of course, you can edit the TSconfig on any page in the page tree that you would like, but we are going to be working on the Root page. Like templates, the TSconfig is inherited from the parent pages in the page tree, so we can modify all of the instances of the RTE in the entire site by modifying the Root page. CSS properties The first thing that we want to update in our editor is the CSS. Without special configuration, the htmlArea RTE uses its own default CSS to decide how the different options such as headings, bold, italics, and so on, look in the text area preview. We can update the TSconfig, to load our own external stylesheet for the RTE that more closely resembles our working frontend site; the editors will see the same basic styling for paragraphs and headings as the visitors and have a better idea of what their content will look like in the frontend. According to the TSref on htmlArea, the following stylesheets are applied to the contents of the editing area by default in ascending order (we'll talk about each one in a moment): The htmlarea-edited-content.css file from the current backend TYPO3 skin (contains selectors for use in the editor but not intended to be applied in the frontend) A CSS file generated from the mainStyleOverride and inlineStyle assignments Any CSS file specified by contentCSS property in the page TSConfig We don't need to worry about the first file, htmlarea-edited-content.css. The TYPO3 skin that styles everything in the backend controls it. By default, there is an extension named TYPO3 skin, and we can simply override any of the styles by using the contentCSS property that we will see in a minute. The mainStyleOverride and inlineStyle properties are controlled by the htmlArea RTE, and TYPO3 generates a CSS file based on their settings in the extension. The mainStyleOverride contains all of the default text settings including sizes and font choices. If we are using our own CSS, we will want to ignore the original styles, so we are going to use the ignoreMainStyleOverride property in our TSconfig. To ignore set this property for our RTE, we can add the following line to the TSconfig on our main page: RTE.default.ignoreMainStyleOverride = 1 The inlineStyle assignments in TYPO3 create default classes for use in the RTE. You've probably already noticed some of them as options in the style drop-downs in the editor (Frame with yellow background, Justify Center, Justify Right, and so on). If we override the inlineStyle assignments, the default classes are removed from the RTE. Of course, we don't need to eliminate these classes just to use our own, but we can do this if we are trying to clean up the RTE for other editors or want to make our own alignment styles. Finally, we can use the contentCSS property to load our own external stylesheet into the RTE. To use our own stylesheet, we will use the following code in the TSconfig to use a new stylesheet named rte.css in our editor: RTE.default.contentCSS = fileadmin/templates/css/rte.css At this point, we're all pretty used to the syntax of TypoScript, but a review might be in order. In the previous line of TypoScript, we are updating the contentCSS property in the default instances of the RTE object with the new value fileadmin/templates/css/rte.css. If you understand that line, then everything else we're about to cover will be easy to pick up. As we want to use our own CSS file and override the defaults at once, this will be the TypoScript for our TSconfig: RTE.default { contentCSS = fileadmin/templates/css/rte.css ignoreMainStyleOverride = 1 } Of course, the next thing we need to do is create our new stylesheet. We don't want to use the complete stylesheet that we are using for the frontend because it could be thousands of lines and will have a lot of formatting and page layout rules that we don't need for simple text editing. Instead, we can just copy the most important text and paragraph styles from our style.css file in the fileadmin/templates/css/ directory into a new file called rte.css. In addition, we're going to add two new classes to style.css and copy them over; we'll create a class named blue to set the font color to pure blue and a class named red to set the font color to pure red. This should be the content of our new file, rte.css: p, ul, div { color: #666; font-size: 12px; line-height: 18px; } h1 { font-size: 24px; line-height: 36px; margin-bottom: 18px; font-weight: 200; font-variant: small-caps; } h2 { margin-bottom: 18px; line-height: 18px; font-size: 18px; } h3 { font-size: 15px; line-height: 18px; } h4, h5, h6 { font-size: 12px; line-height: 18px; } ul, ol { margin: 0px 0px 18px 18px; } ul { list-style-type: circle; } ol { list-style: decimal; } td { padding: 5px; } :link, :visited { font-weight: bold; text-decoration: none; color: #036; } .blue { color: #0000ff; } .red { color: #ff0000; } With our new CSS we will notice at least a subtle difference in our RTE. In the following screenshot, we can see the original RTE on the left and the updated RTE on the right. As you can see, our text is now spaced out better and lightened to match the frontend: As we have overridden the default classes without creating any new ones, the Block style and Text style drop-downs are both empty now. In the RTE, block styles are used for the "blocks" of our content such as paragraphs and headings while the text styles are applied directly to words or pieces of text within a larger block. Put simply, if we wanted a whole paragraph to be blue, we would use the Block style drop-down, and we would use the Text style drop-down if we only wanted a single word to be blue. Both of these drop-downs use our CSS classes for styling, so we'll go ahead and create our new classes in the TSconfig. Classes properties All of the classes in our external CSS file (rte.css) are made available as soon as we declared the file with the contentCSS property. If we want to use them, we just need to associate them with a style type (paragraph, character, image, and so on) for the default RTE. If we wanted to associate the blue and red classes with text styles, for example, we would add the following to our page's TSconfig: RTE.default.classesCharacter = blue, red Before we assign the classes to a type, we should declare them in the TSconfig so they show up properly in the RTE. By declaring the classes, we can set the titles we want to show in the RTE and how we want the titles to be styled in the drop-downs. Without declarations, the styles will still show up, but the titles will just be CSS class names. We want to declare them in TSconfig with specific title to make our editors' lives easier. We can add the following code to the TSconfig to declare the classes in our RTE and set more descriptive titles that will be shown in blue or red in the drop-down menus: RTE.classes { blue { name = Blue Text value = color: blue; } red { name = Red Text value = color: red; } } We can use CSS classes for more than just the text style, of course. The table below shows all of the main ways that we can associate and use classes in the htmlArea RTE, but you can read more in the htmlArea TSref. Go ahead and try some of them out with the example TypoScript lines that are shown. RTE class properties Toolbar properties Along with what shows up inside the content of the RTE, we can modify the toolbar itself to control what editors are able to see and use. By controlling the toolbar, we can make the RTE easier for editors and make sure that the branding and styling is consistent. The table below shows some of the most useful properties we can use to alter the toolbar available to editors. We can actually go much further in editing the individual buttons of the toolbar, but this is changing enough between major releases that I recommend using the TSref as a reference for your version of the htmlArea RTE. HTML editor properties Finally, we can change the way that the RTE works with HTML. For example, the RTE uses paragraph tags (&ltp></p>) for all blocks in our text area, but we can replace this behavior with break tags (&ltbr />) if we want. The RTE also strips certain tags, and we can change that with RTE properties as well. The following table shows the most common properties that we can use in the Page TSconfig to modify the HTML in the htmlArea RTE. Even if we don't need anything else in this section; using allowTags to allow embedded video can make our editor" lives easier if we want to embed YouTube or Vimeo players in our website. All of this information is also available in the TSref for the htmlArea if you need an updated reference.
Read more
  • 0
  • 0
  • 5462

article-image-designing-avatar-flash-multiplayer-virtual-worlds
Packt
27 Aug 2010
9 min read
Save for later

Designing an Avatar in Flash Multiplayer Virtual Worlds

Packt
27 Aug 2010
9 min read
(For more resources on Flash, see here.) Designing an avatar Avatar is very important in a virtual world because most of the features are designed around avatars. Users interact with each other via their avatars, they explore the virtual world via avatars, and they complete challenges to level up their avatars. An avatar is composited by graphics and animation. The avatar graphics are its looks. It is not a static image but a collection of images to display the directions and appearance. There are different approaches of drawing the avatar graphics depending on the render methods and how many directions and animations the avatar needs. Animations represent different actions of the avatar. The most basic animation is walking. Other animations such as hand waving and throwing objects are also common. There will be different animation sets for different virtual world designs. A fighting topic virtual world will probably contain a collection of fighting animation sets. A hunting topic virtual world will contain animations of collection items and using hunting tools. Determining the direction numbers of avatars' views Isometric tile is composed by diamond shapes with four-edge connection to the other tiles. It is not hard to imagine that every avatar in the isometric view may face towards four directions. They are the north east, south east, south west, and north west. However, sometimes using only these four directions may not be enough; some game designs may require the avatar to face the user or walk to the other isometric tile a cross the diamond corner. In this case, eight directions are required. The direction number of the avatars affects the artwork drawing directly. Just imagine that we are building a virtual world where players can fight with each other. How many animations are there for an avatar to fight? Say, five sets of animations. How many directions can the avatar faces? 4? 8? Or even 12? For example, we are now talking about five sets of animations with 8 directions of each avatar. That's already 40 animations for only one avatar. We may design the virtual world to have 12 kinds of avatars and each avatar to have different clothes for customization. The graphics workload keeps increasing when only one of these aspects increases. That's why I often consider different approaches that reduce the graphic workload of the avatars. Take four directions as an example. In most cases, we have very similar animations when the avatar is facing south-east and south-west. And the animation of north-east and north-west are similar too. Therefore, it is a common technique that mirrors the animation of west side into east side. It can be easily done in Flash by just changing the x-axis of the scaling property to between -1 and 1. This property results in the avatar flipping from one side to another side. For a 4-directions animation set, only 2 directions need to be drawn. In an 8-directions animation set, only 5 directions need to be drawn. Next, we will discuss the rendering methods that will conclude how the amount of directions, animations, and customization affect the graphic workload. Rendering avatars in Flash virtual world There are different approaches to render avatars in Flash virtual world. Each rendered method comes with both advantages and disadvantages. Some methods take more time to draw with fancy outlook while others may take more time to program. It is important to decide which rendering methods of the avatar are required in predevelopment stage. It will be much more difficult to change the rendering method after the project is in development. We will discuss different rendering methods and the pros and cons of them. Drawing an avatar using vector animation It is convenient to use the Flash native vector drawing for avatar because every drawing can be done within the Flash. The output can be cute and cartoon style. One advantage of using vector is that color customization is easy to implement by using the native ActionScript color transform. We can easily assign different colors to different parts of the avatar without extra graphic drawing. Another advantage of using vector animation is that we can scale up and down the avatars whenever needed. It is useful when we need to zoom in or out of the map and the avatars in the virtual world. The following graph shows the comparison of scaling up a vector and bitmap graphic: The disadvantage is that we need to draw the animation of every part of the avatar in every direction frame by frame. Flash tweening can help but the workload is heavier than other methods. We can prerender the animations or control them by ActionScript in methods discussed later. In vector animation, every animation is hand-drawn and thus any late modification on the avatar design can cost quite a lot of workload. There may not be too many directions of the avatars meaning the rotation of the avatars will not be very smooth. Rendering avatars using bitmap sprite sheet Sprite sheet is a graphics technique that is used in almost all game platforms. Sprite sheet is a large bitmap file that contains every frame of animation. Bitmap data from each frame is masked and rendered to the screen. A Flash developer may think that there is a timeline with frame one on the top left and counting the frame from left to right in each row from top to bottom. This technique is useful when the avatar graphic designer has experience in other game platforms. Another advantage of using bitmap data is faster rendering than vector in Flash player. The other advantage is the sprite sheet can be rendered from 3D software. For example, we can make an avatar model in Maya (http://autodesk.com/maya) or 3Ds Max (http://autodesk.com/3dsmax) with animations set up. Then we set up eight cameras with orthographic perspective. The orthographic perspective ensures the rendered image fits the isometric world. After setting up the scene, just render the whole animation with eight different cameras and we will get all the bitmap files of the avatar. The benefit is that the rendering process is automatic so that we can reduce the workload a lot. Later if we want to modify the character, we only need to modify it in the 3D software and render it again. One big disadvantage of using sprite sheet is the file size. The sprite sheets are in bitmap format and one set of animation can cost up to several hundred kilobytes. The file size can be very large when there are many animations and many more bitmaps for switching styles of the avatar. The other disadvantage is that changing color is quite difficult. Unlike vector rendering where color replacement can be done by ActionScript, we need to replace another bitmap data to change the color. That means every available color doubles the file size. Rendering avatars using real-time 3D engine We described how to use 3D software to prerender graphics of the avatars in the previous section. Instead of prerendering the graphics into 2D bitmap, we can integrate a Flash 3D engine to render the 3D model into isometric view in real time. Real-time 3D rendering is the next trend of Flash. There are several 3D engines available in the market that support rendering complex 3D models with animations. Papervision3D (http://blog.papervision3d.org/) and Away3D (http://away3d.com/) are two examples among them. The advantage of using 3D rendering in isometric is that the rotation of avatars can be very smooth. Also different textures can share the same model and different models can share the same animation skeleton. Thanks to this great graphic reusability, 3D rendering virtual world can create different combinations of avatar appearance and animations without adding extra graphic workload in development. However, one disadvantage of using 3D rendering is the Flash player performance. The latest version of Flash player is 10.1 at the time of writing. The following screenshots show that the CPU resources usage is very high when rendering the isometric 3D environment with three avatars on screen: Rendering avatars using 2D bone skeleton Bone skeleton used to be an uncommon method to render avatar. What it does is creates an animated skeleton and then glues different parts of body together onto the skeleton. It is somehow similar to the skeleton and mesh relationship in 3-D software but in two dimensions instead. A lot of mathematics is needed to calculate the position and rotation of each part of the body and make the implementation difficult. Thanks to the introduction of bone tool and inverse kinematics in Flash CS4, this technique is becoming more mature and easier to be used in the Flash world. Adobe has posted a tutorial about using bone tool to create a 2D character (http://www.adobe.com/devnet/flash/articles/character_animation_ik.html). The following screenshot shows another bone skeleton example from gotoAndPlay demonstrating how to glue the parts into a walking animation. The post can be found in this link: http://www.gotoandplay.it/_articles/2007/04/skeletal_animation.php The advantage of using 2D bone skeleton is that animations are controlled by ActionScript. The reusing of animations means this technique fits those game designs that require many animations. A dancing virtual world that requires a lot of different unique animations is one example that may need this technique. One disadvantage is that the large amount of mathematic calculation for the animations makes it difficult to implement. Every rendering methods has its own advantages and disadvantages and not one of the methods fits all type of games. It is the game designer's job to decide a suitable rendering method for a game or virtual world project. Therefore, it is important to know their limitations and consider thoughtfully before getting started with development. We can take a look at how other Flash virtual worlds render avatars by checking the showcase of the SmartFoxServer (http://www.smartfoxserver.com/showcase/).
Read more
  • 0
  • 0
  • 5461

article-image-writing-package-python
Packt
23 Oct 2009
18 min read
Save for later

Writing a Package in Python

Packt
23 Oct 2009
18 min read
Writing a Package Its intents are: To shorten the time needed to set up everything before starting the real work, in other words the boiler-plate code To provide a standardized way to write packages To ease the use of a test-driven development approach To facilitate the releasing process It is organized in the following four parts: A common pattern for all packages that describes the similarities between all Python packages, and how distutils and setuptools play a central role How generative programming (http://en.wikipedia.org/wiki/Generative_programming) can help this through the template-based approach The package template creation, where everything needed to work is set Setting up a development cycle A Common Pattern for All Packages The easiest way to organize the code of an application is to split it into several packages using eggs. This makes the code simpler, and easier to understand, maintain, and change. It also maximizes the reusability of each package. They act like components. Applications for a given company can have a set of eggs glued together with a master egg. Therefore, all packages can be built using egg structures. This section presents how a namespaced package is organized, released, and distributed to the world through distutils and setuptools. Writing an egg is done by layering the code in a nested folder that provides a common prefix namespace. For instance, for the Acme company, the common namespace can be acme. The result is a namespaced package. For example, a package whose code relates to SQL can be called acme.sql. The best way to work with such a package is to create an acme.sql folder that contains the acme and then the sql folder: setup.py, the Script That Controls Everything The root folder contains a setup.py script, which defines all metadata as described in the distutils module, combined as arguments in a call to the standard setup function. This function was extended by the third-party library setuptools that provides most of the egg infrastructure. The boundary between distutils and setuptools is getting fuzzy, and they might merge one day. Therefore, the minimum content for this file is: from setuptools import setupsetup(name='acme.sql') name gives the full name of the egg. From there, the script provides several commands that can be listed with the -help-commands option. $ python setup.py --help-commands Standard commands:  build             build everything needed to install  ...  install           install everything from build directory  sdist         create a source distribution  register      register the distribution  bdist         create a built (binary) distributionExtra commands:  develop       install package in 'development mode'  ...  test          run unit tests after in-place build alias         define a shortcut  bdist_egg     create an "egg" distribution The most important commands are the ones left in the preceding listing. Standard commands are the built-in commands provided by distutils, whereas Extra commands are the ones created by third-party packages such as setuptools or any other package that defines and registers a new command. sdist The sdist command is the simplest command available. It creates a release tree where everything needed to run the package is copied. This tree is then archived in one or many archived files (often, it just creates one tar ball). The archive is basically a copy of the source tree. This command is the easiest way to distribute a package from the target system independently. It creates a dist folder with the archives in it that can be distributed. To be able to use it, an extra argument has to be passed to setup to provide a version number. If you don't give it a version value, it will use version = 0.0.0: from setuptools import setupsetup(name='acme.sql', version='0.1.1' This number is useful to upgrade an installation. Every time a package is released, the number is raised so that the target system knows it has changed. Let's run the sdist command with this extra argument: $ python setup.py sdistrunning sdist...creating disttar -cf dist/acme.sql-0.1.1.tar acme.sql-0.1.1gzip -f9 dist/acme.sql-0.1.1.tarremoving 'acme.sql-0.1.1' (and everything under it)$ ls dist/acme.sql-0.1.1.tar.gz Under Windows, the archive will be a ZIP file. The version is used to mark the name of the archive, which can be distributed and installed on any system having Python. In the sdist distribution, if the package contains C libraries or extensions, the target system is responsible for compiling them. This is very common for Linux-based systems or Mac OS because they commonly provide a compiler. But it is less usual to have it under Windows. That's why a package should always be distributed with a pre-built distribution as well, when it is intended to run under several platforms. The MANIFEST.in File When building a distribution with sdist, distutils browse the package directory looking for files to include in the archive. distutils will include: All Python source files implied by the py_modules, packages, and scripts option All C source files listed in the ext_modules option Files that match the glob pattern test/test*.py README, README.txt, setup.py, and setup.cfg files Besides, if your package is under Subversion or CVS, sdist will browse folders such as .svn to look for files to include .sdist builds a MANIFEST file that lists all files and includes them into the archive. Let's say you are not using these version control systems, and need to include more files. Now, you can define a template called MANIFEST.in in the same directory as that of setup.py for the MANIFEST file, where you indicate to sdist which files to include. This template defines one inclusion or exclusion rule per line, for example: include HISTORY.txtinclude README.txtinclude CHANGES.txtinclude CONTRIBUTORS.txtinclude LICENSErecursive-include *.txt *.py The full list of commands is available at http://docs.python.org/dist/sdist-cmd.html#sdist-cmd. build and bdist To be able to distribute a pre-built distribution, distutils provide the build command, which compiles the package in four steps: build_py: Builds pure Python modules by byte-compiling them and copying them into the build folder. build_clib: Builds C libraries, when the package contains any, using Python compiler and creating a static library in the build folder. build_ext: Builds C extensions and puts the result in the build folder like build_clib. build_scripts: Builds the modules that are marked as scripts. It also changes the interpreter path when the first line was set (!#) and fixes the file mode so that it is executable. Each of these steps is a command that can be called independently. The result of the compilation process is a build folder that contains everything needed for the package to be installed. There's no cross-compiler option yet in the distutils package. This means that the result of the command is always specific to the system it was build on. Some people have recently proposed patches in the Python tracker to make distutils able to cross-compile the C parts. So this feature might be available in the future. When some C extensions have to be created, the build process uses the system compiler and the Python header file (Python.h). This include file is available from the time Python was built from the sources. For a packaged distribution, an extra package called python-dev often contains it, and has to be installed as well. The C compiler used is the system compiler. For Linux-based system or Mac OS X, this would be gcc. For Windows, Microsoft Visual C++ can be used (there's a free command-line version available) and the open-source project MinGW as well. This can be configured in distutils. The build command is used by the bdist command to build a binary distribution. It calls build and all dependent commands, and then creates an archive in the same was as sdist does. Let's create a binary distribution for acme.sql under Mac OS X: $ python setup.py bdistrunning bdistrunning bdist_dumbrunning build...running install_scriptstar -cf dist/acme.sql-0.1.1.macosx-10.3-fat.tar .gzip -f9 acme.sql-0.1.1.macosx-10.3-fat.tarremoving 'build/bdist.macosx-10.3-fat/dumb' (and everything under it)$ ls dist/acme.sql-0.1.1.macosx-10.3-fat.tar.gz    acme.sql-0.1.1.tar.gz Notice that the newly created archive's name contains the name of the system and the distribution it was built under (Mac OS X 10.3). The same command called under Windows will create a specific distribution archive: C:acme.sql> python.exe setup.py bdist...C:acme.sql> dir dist25/02/2008  08:18     <DIR>          .25/02/2008  08:18     <DIR>          ..25/02/2008  08:24             16 055 acme.sql-0.1.win32.zip               1 File(s)          16 055 bytes               2 Dir(s)   22 239 752 192 bytes free If a package contains C code, apart from a source distribution, it's important to release as many different binary distributions as possible. At the very least, a Windows binary distribution is important for those who don't have a C compiler installed. A binary release contains a tree that can be copied directly into the Python tree. It mainly contains a folder that is copied into Python's site-packages folder. bdist_egg The bdist_egg command is an extra command provided by setuptools. It basically creates a binary distribution like bdist, but with a tree comparable to the one found in the source distribution. In other words, the archive can be downloaded, uncompressed, and used as it is by adding the folder to the Python search path (sys.path). These days, this distribution mode should be used instead of the bdist-generated one. install The install command installs the package into Python. It will try to build the package if no previous build was made and then inject the result into the Python tree. When a source distribution is provided, it can be uncompressed in a temporary folder and then installed with this command. The install command will also install dependencies that are defined in the install_requires metadata. This is done by looking at the packages in the Python Package Index (PyPI). For instance, to install pysqlite and SQLAlchemy together with acme.sql, the setup call can be changed to: from setuptools import setupsetup(name='acme.sql', version='0.1.1',      install_requires=['pysqlite', 'SQLAlchemy']) When we run the command, both dependencies will be installed. How to Uninstall a Package The command to uninstall a previously installed package is missing in setup.py. This feature was proposed earlier too. This is not trivial at all because an installer might change files that are used by other elements of the system. The best way would be to create a snapshot of all elements that are being changed, and a record of all files and directories created. A record option exists in install to record all files that have been created in a text file: $ python setup.py install --record installation.txtrunning install...writing list of installed files to 'installation.txt' This will not create any backup on any existing file, so removing the file mentioned might break the system. There are platform-specific solutions to deal with this. For example, distutils allow you to distribute the package as an RPM package. But there's no universal way to handle it as yet. The simplest way to remove a package at this time is to erase the files created, and then remove any reference in the easy-install.pth file that is located in the sitepackages folder. develop setuptools added a useful command to work with the package. The develop command builds and installs the package in place, and then adds a simple link into the Python site-packages folder. This allows the user to work with a local copy of the code, even though it's available within Python's site-packages folder. All packages that are being created are linked with the develop command to the interpreter. When a package is installed this way, it can be removed specifically with the -u option, unlike the regular install: $ sudo python setup.py developrunning develop...Adding iw.recipe.fss 0.1.3dev-r7606 to easy-install.pth fileInstalled /Users/repos/ingeniweb.sourceforge.net/iw.recipe.fss/trunkProcessing dependencies ...$ sudo python setup.py develop -urunning developRemoving...Removing iw.recipe.fss 0.1.3dev-r7606 from easy-install.pth file Notice that a package installed with develop will always prevail over other versions of the same package installed. test Another useful command is test. It provides a way to run all tests contained in the package. It scans the folder and aggregates the test suites it finds. The test runner tries to collect tests in the package but is quite limited. A good practice is to hook an extended test runner such as zope.testing or Nose that provides more options. To hook Nose transparently to the test command, the test_suite metadata can be set to 'nose.collector' and Nose added in the test_requires list: setup(...test_suite='nose.collector',test_requires=['Nose'],...) register and upload To distribute a package to the world, two commands are available: register: This will upload all metadata to a server. upload: This will upload to the server all archives previously built in the dist folder. The main PyPI server, previously named the Cheeseshop, is located at http://pypi.python.org/pypi and contains over 3000 packages from the community. It is a default server used by the distutils package, and an initial call to the register command will generate a .pypirc file in your home directory. Since the PyPI server authenticates people, when changes are made to a package, you will be asked to create a user over there. This can also be done at the prompt: $ python setup.py registerrunning register...We need to know who you are, so please choose either: 1. use your existing login, 2. register as a new user, 3. have the server generate a new password for you (and email it toyou), or 4. quitYour selection [default 1]: Now, a .pypirc file will appear in your home directory containing the user and password you have entered. These will be used every time register or upload is called: [server-index]username: tarekpassword: secret There is a bug on Windows with Python 2.4 and 2.5. The home directory is not found by distutils unless a HOME environment variable is added. But, this has been fixed in 2.6. To add it, use the technique where we modify the PATH variable. Then add a HOME variable for your user that points to the directory returned by os.path.expanduser('~'). When the download_url metadata or the url is specified, and is a valid URL, the PyPI server will make it available to the users on the project web page as well. Using the upload command will make the archive directly available at PyPI, so the download_url can be omitted: Distutils defines a Trove categorization (see PEP 301: http://www.python.org/dev/peps/pep-0301/#distutils-trove-classification) to classify the packages, such as the one defined at Sourceforge. The trove is a static list that can be found at http://pypi.python.org/pypi?%3Aaction=list_classifiers, and that is augmented from time to time with a new entry. Each line is composed of levels separated by "::": ...Topic :: TerminalsTopic :: Terminals :: SerialTopic :: Terminals :: TelnetTopic :: Terminals :: Terminal Emulators/X TerminalsTopic :: Text Editors Topic :: Text Editors :: DocumentationTopic :: Text Editors :: Emacs... A package can be classified in several categories, which can be listed in the classifiers meta-data. A GPL package that deals with low-level Python code (for instance) can use: Programming Language :: PythonTopic :: Software Development :: Libraries :: Python ModulesLicense :: OSI Approved :: GNU General Public License (GPL) Python 2.6 .pypirc Format The .pypirc file has evolved under Python 2.6, so several users and their passwords can be managed along with several PyPI-like servers. A Python 2.6 configuration file will look somewhat like this: [distutils]index-servers =    pypi    alternative-server    alternative-account-on-pypi[pypi]username:tarekpassword:secret[alternative-server]username:tarekpassword:secretrepository:http://example.com/pypi The register and upload commands can pick a server with the help of the -r option, using the repository full URL or the section name: # upload to http://example.com/pypi$ python setup.py sdist upload -r   alternative-server#  registers with default account (tarek at pypi)$ python setup.py register#  registers to http://example.com$ python setup.py register -r http://example.com/pypi This feature allows interaction with servers other than PyPI. When dealing with a lot of packages that are not to be published at PyPI, a good practice is to run your own PyPI-like server. The Plone Software Center (see http://plone.org/products/plonesoftwarecenter) can be used, for example, to deploy a web server that can interact with distutils upload and register commands. Creating a New Command distutils allows you to create new commands, as described in http://docs.python.org/dist/node84.html. A new command can be registered with an entry point, which was introduced by setuptools as a simple way to define packages as plug-ins. An entry point is a named link to a class or a function that is made available through some APIs in setuptools. Any application can scan for all registered packages and use the linked code as a plug-in. To link the new command, the entry_points metadata can be used in the setup call: setup(name="my.command",          entry_points="""             [distutils.commands]             my_command = my.command.module.Class          """) All named links are gathered in named sections. When distutils is loaded, it scans for links that were registered under distutils.commands. This mechanism is used by numerous Python applications that provide extensibility. setup.py Usage Summary There are three main actions to take with setup.py: Build a package. Install it, possibly in develop mode. Register and upload it to PyPI. Since all the commands can be combined in the same call, some typical usage patterns are: # register the package with PyPI, creates a source and# an egg distribution, then upload them$ python setup.py register sdist bdist_egg upload# installs it in-place, for development purpose$ python setup.py develop# installs it$ python setup.py install The alias Command To make the command line work easily, a new command has been introduced by setuptools called alias. In a file called setup.cfg, it creates an alias for a given combination of commands. For instance, a release command can be created to perform all actions needed to upload a source and a binary distribution to PyPI: $ python setup.py alias release register sdist bdist_egg uploadrunning aliasWriting setup.cfg$ python setup.py release... Other Important Metadata Besides the name and the version of the package being distributed, the most important arguments setup can receive are: description: A few sentences to describe the package long_description: A full description that can be in reStructuredText keywords: A list of keywords that define the package author: The author's name or organization author_email: The contact email address url: The URL of the project license: The license (GPL, LGPL, and so on) packages: A list of all names in the package; setuptools provides a small function called find_packages that calculates this namespace_packages: A list of namespaced packages A completed setup.py file for acme.sql would be: import osfrom setuptools import setup, find_packagesversion = '0.1.0'README = os.path.join(os.path.dirname(__file__), 'README.txt')long_description = open(README).read() + 'nn'setup(name='acme.sql',      version=version,      description=("A package that deals with SQL, "                    "from ACME inc"),      long_description=long_description,      classifiers=[        "Programming Language :: Python",        ("Topic :: Software Development :: Libraries ::          "Python Modules"),        ],      keywords='acme sql',      author='Tarek',      author_email='tarek@ziade.org',      url='http://ziade.org',      license='GPL',      packages=find_packages(),      namespace_packages=['acme'],      install_requires=['pysqlite','SQLAchemy']      ) The two comprehensive guides to keep under your pillow are: The distutils guide at http://docs.python.org/dist/dist.html The setuptools guide at http://peak.telecommunity.com/DevCenter/setuptools 
Read more
  • 0
  • 0
  • 5460

article-image-moodle-plugins
Packt
25 Oct 2011
8 min read
Save for later

Moodle Plugins

Packt
25 Oct 2011
8 min read
  (For more resources on Moodle, see here.) There are a number of additional plugin types; namely, Enrolments, Authentication, Message outputs, Licences, and Web services. Plugins—an overview Moodle plugins are modules that provide some specific, usually ring-fenced, functionality. You can access the plugins area via the Plugins menu that is shown in the following screenshot:   Plugins overview displays a list of all installed plugins. The information shown for each plugin includes the Plugin name, an internal Identifier, its Source (Standard or Extension), its Version (in date format), its Availability (enabled or disabled), a link to the plugin Settings, and an option to Uninstall the plugin. The table is useful to get a quick overview of what has been installed on your system and what functionality is available. Some areas contain a significant number of plugins, for instance, Authentication and Portfolios. Other categories only contain one or two plugins. The expectation is that more plugins will be developed in the future, either as part of the Moodle's core or by third-party developers. This guarantees the extensibility of Moodle without the need to change the system itself. Be careful when modifying settings in any of the plugins. Inappropriate values can cause problems throughout the system. The last plugin type in the preceding screenshot is labeled Local plugins. This is the recommended place for any local customizations. These customizations can be changes to existing functionality or the introduction of new features. For more information about local plugins, check out the readme.txt file in the local directory in your dirroot. Module plugins Moodle distinguishes between three types of module plugins that are used in the courses—the front page (which is treated as a course), the My Moodle page, and the user profile pages: Activities modules (which also covers resources) Blocks Filters   Activities modules Navigating to Plugins | Activity modules | Manage activities displays the following screen: The table displays the following information: Column Description Activity module Icon and name of the activity/resource as they appear in courses and elsewhere. Activities The number of times the activity module is used in Moodle. When you click on the number, a table, which displays the courses in which the activity module has been used, is shown. Version Version of the activity module (format YYYYMMDDHH). Hide/Show The opened eye indicates that the activity module is available for use, while the closed eye indicates that it is hidden (unavailable). Delete Performs delete action. All activities, except the Forum activity, can be deleted. Settings Link to activity module settings (not available for all items). Clicking on the Show/Hide icon toggles its state; if it is hidden it will be changed to be shown and vice versa. If an activity module is hidden, it will not appear in the Add an activity or Add a resource drop-down menu in any Moodle course. Hidden activities and resources that are already present in courses are hidden but are still in the system. It means that, once the activity module is visible again, the items will also re-appear in courses. You can delete any Moodle Activity module (except the Forum activity). If you delete an activity or resource that has been used anywhere in Moodle, all the already-created activity modules will also be deleted and so will any associated user data! Deleting an activity module cannot be undone; it has to be installed from scratch. It is highly recommended not to delete any activity modules unless you are 100 percent sure that you will never need them again! If you wish to prevent usage of an activity or resource type, it is better to hide it instead of deleting it. The Feedback activity has been around for some time as a third-party add-on. It is hidden by default because it has been newly introduced in the core of Moodle 2, due to its popularity. You might probably want to make this available for your teachers. The settings are different for each activity module. For example, the settings for the Assignment module only contain three parameters, whereas the settings for the Quiz module allow the modification of a wide range of parameters. The settings for Moodle Activity modules are not covered here, as they are mostly self-explanatory and also dealt with in great detail in the Moodle Docs of the respective modules. It is further expected that the activity modules will undergo a major overhaul in the 2.x versions to come, making any current explanations obsolete. Configuration of blocks Navigating to Plugins | Blocks | Manage blocks displays a table, as shown in the screenshot that follows. It displays the same type of information as for Activity modules. Some blocks allow multiple instances, that is, the block can be used more than once on a page. For example, you can only have one calendar, whereas you can have as many Remote RSS Feeds as you wish. You cannot control this behavior, as it is controlled by the block itself. You can delete any Moodle block. If you delete a block that is used anywhere in Moodle, all the already-created content will also be deleted. Deleting a block cannot be undone; it has to be installed from scratch. Do not delete or hide the Settings block, as you will not be able to access any system settings anymore! Also, do not delete or hide the Navigation block, as users will not be able to access a variety of pages. Most blocks are shown by default (except the Feedback and Global search blocks). Some blocks require additional settings to be set elsewhere for the block to function. For example, RSS feeds and tags have to be enabled in Advanced features, the Feedback activity module has to be shown, or global search has to be enabled (via Development | Experimental | Experimental settings).   The parameters of all standard Moodle blocks are explained in the respective Moodle Docs pages. Configuration of filters Filters scan any text that has been entered via the Moodle HTML editor and automatically transform it into different, often more complex, forms. For example, entries or concepts in glossaries are automatically hyperlinked in text, URLs pointing to MP3 or other audio files become embedded, flash-based controls (that offer pause and rewind functionality) appear, uploaded videos are given play controls, and so on. Moodle ships with 12 filters, which are accessed via Plugins | Filters | Manage filters:   By default, all filters are disabled. You can enable them by changing the Active? status to On or Off, but available. If the status is set to On, it means that the filter is activated throughout the system, but can be de-activated locally. If the status is set to Off, but available, it means that the filter is not activated, but can be enabled locally. In the preceding screenshot, the Multimedia plugins and Display emoticons as images (smileys) filters have been turned On and will be used throughout the system, as they are very popular. The TeX notation and Glossary auto-linking filters are available, but have to be activated locally. The former is only of use to the users who deal with mathematical or scientific notation and will trigger the Insert equation button in the Moodle editor. The Glossary auto-linking filter might be used in some courses. It can then be switched off temporarily at activity module level when learners have to appear for an exam. Additionally, you can change the order in which the filters are applied to text, using the up and down arrows. The filtering mechanism operates on a first-come, firstserved basis, that is, if a filter detects a text element that has to be transformed, it will do so before the next filter is applied. Each filter can be configured to be applied to Content and headings or Content only, that is, filters will be ignored in names of activity modules. The settings of some filters are described in detail in the Moodle Docs. As with activities and blocks, it is recommended to hide filters if you don't require them on your site. In addition to the filter-specific settings, Moodle provides a number of settings that are shared among all filters. These settings are accessed via the Filters | Common filters menu and are shown in the following screenshot: Setting Description Text cache lifetime It is the time for which Moodle keeps text to be filtered in a dedicated cache. Filter uploaded files By default, only text entered via the Moodle editor is filtered. If you wish to include uploaded files, you can choose any one from the HTML files only and All files options. Filter match once per page Enable this setting if the filter should stop analyzing text after it finds a match, that is, only the first occurrence will be transformed. Filter match once per text Enable this setting if the filter should only generate a single link for the first matching text instance found in each item of text on a page. This setting is ignored if the Filter match once per page parameter is enabled.  
Read more
  • 0
  • 0
  • 5458

article-image-optimizing-graphql-with-apollo-engine-tutorial
Bhagyashree R
02 Apr 2019
13 min read
Save for later

Optimizing GraphQL with Apollo Engine [Tutorial]

Bhagyashree R
02 Apr 2019
13 min read
Apollo Engine is a commercial product produced by MDG, the Meteor Development Group, the company behind Apollo. It provides many great features, which we'll explore in this article. We will also answer these questions using the Apollo Engine: How is our GraphQL API performing, are there any errors, and how can we improve the GraphQL schema? This article is taken from the book Hands-on Full-Stack Web Development with GraphQL and React by Sebastian Grebe. This book will guide you in implementing applications by using React, Apollo, Node.js, and SQL. By the end of the book, you will be proficient in using GraphQL and React for your full-stack development requirements. To follow along with the examples implemented in this article, you can download the code from the book’s GitHub repository. Setting up Apollo Engine First, you need to sign up for an Apollo Engine account. At the time of writing, they offer three different plans, which you can find by going to their plans page. When signing up, you get a two-week trial of the Team plan, which is one of the paid plans. Afterward, you'll be downgraded to the free plan. You should compare all three plans to understand how they differ—they're all worth checking out. To sign up, go to its login page. Currently, you can only sign up using a GitHub account. If you don't have one already, create a GitHub account. After logging in, you will see a dashboard that looks as follows: The next step is to add a service with the NEW SERVICE button in the top-right corner. The first thing you need to enter is a unique id for your service across all Apollo Engine services. This id will be auto-generated through the organization you select, but can be customized. Secondly, you will be asked to publish your GraphQL schema to Apollo Engine. Publishing your GraphQL schema means that you upload your schema to Apollo Engine so that it can be processed. It won't get publicized to external users. You can do this using the command provided by Apollo Engine. For me, this command looked as follows: npx apollo service:push --endpoint="http://localhost:8000/graphql" --key="YOUR_KEY" The preceding endpoint must match your GraphQL route. The key comes from Apollo Engine itself, so you don't generate it on your own. Before running the preceding command, you have to start the server, otherwise, the GraphQL schema isn't accessible. Once you've uploaded the schema, Apollo Engine will redirect you to the service you just set up. Notice that the GraphQL introspection feature needs to be enabled. Introspection means that you can ask your GraphQL API which operations it supports. Introspection is only enabled when you run your Apollo Server in a development environment, or if you explicitly enable introspection in production. I highly discourage this because it involves giving away information about queries and mutations that are accepted by your back end. However, if you want to enable it, you can do this by setting the introspection field when initializing Apollo Server. It can be added inside the index.js file of the graphql folder: const server = new ApolloServer({ schema: executableSchema, introspection: true, Ensure that you remove the introspection field when deploying your application. If you aren't able to run the GraphQL server, you also have the ability to specify a schema file. Once you publish the GraphQL schema, the setup process for your Apollo Engine service should be done. We'll explore the features that we can now use in the following sections of this article. Before doing this, however, we have to change one thing on the back end to get Apollo Engine working with our back end. We already used our API Key to upload our GraphQL schema to Apollo Engine. Everything, such as error tracking and performance analysis, relies on this key. We also have to insert it in our GraphQL server. If you entered a valid API key, all requests will be collected in Apollo Engine. Open index.js in the server's graphql folder and add the following object to the ApolloServer initialization: engine: { apiKey: ENGINE_KEY } The ENGINE_KEY variable should be extracted from the environment variables at the top of the file. We also need to extract JWT_SECRET with the following line: const { JWT_SECRET, ENGINE_KEY } = process.env; Verify that everything is working by running some GraphQL requests. You can view all past requests by clicking on the Clients tab in Apollo Engine. You should see that a number of requests happened, under the Activity in the last hour panel. If this isn't the case, there must be a problem with the Apollo Server configuration. Analyzing schemas with Apollo Engine The Community plan of Apollo Engine offers schema registry and explorer tools. You can find them by clicking on the Explorer tab in the left-hand panel. If your setup has gone well, the page should look as follows: Let's take a closer look at this screenshot: On the page, you see the last GraphQL schema that you have published. Each schema you publish has a unique version, as long as the schema includes changes. Beneath the version number, you can see your entire GraphQL schema. You can inspect all operations and types. All relations between types and operations are directly linked to each other. You can directly see the number of clients and various usage statistics next to each operation, type, and field. You can search through your GraphQL schema in the top bar and filter the usage statistics in the panel on the right. You can also switch to the Deprecation tab at the top. This page gives you a list of fields that are deprecated. We won't use this page because we are using the latest field definitions, but it's vital if you're running an application for a longer time. Having an overview of our schema is beneficial. In production, every new release of our application is likely to also bring changes to the GraphQL schema. With Apollo Engine, you can track those changes easily. This feature is called schema-change validation and is only included in the paid Team plan of Apollo Engine. It's worth the extra money because it allows you to track schema changes and also to compare how those fields are used. It allows us to draw conclusions about which clients and versions are being used at the moment. I have created an example for you in the following screenshot: Here, I published an initial version of our current GraphQL schema. Afterward, I added a demonstration type with one field, called example. On the right-hand side, you can see the schema difference between the initial and second releases of the GraphQL schema. Viewing your schema inside Apollo Engine, including the history of all previous schemas, is very useful. Performance metrics with Apollo Engine When your application is live and heavily used, you can't check the status of every feature yourself; it would lead to an impossible amount of work. Apollo Engine can tell you how your GraphQL API is performing by collecting statistics with each request that's received. You always have an overview of the general usage of your application, the number of requests it receives, the request latency, the time taken to process each operation, the type, and also each field that is returned. Apollo Server can provide these precise analytics since each field is represented in a resolver function. The time elapsed to resolve each field is then collected and stored inside Apollo Engine. At the top of the Metrics page, you have four tabs. The first tab will look as follows: If your GraphQL API is running for more than a day, you'll receive an overview that looks like the one here. The left-hand graph shows you the request rate over the last day. The graph in the middle shows the service time, which sums up the processing time of all requests. The right-hand graph gives you the number of errors, along with the queries that caused them. Under the overview, you'll find details about the current day, including the requests per minute, the request latency over time, and the request latency distribution: Requests Per Minute (rpm): It is useful when your API is used very often. It indicates which requests are sent more often than others. Latency over time: It is useful when the requests to your API take too long to process. You can use this information to look for a correlation between the number of requests and increasing latency. Request-latency distribution: It shows you the processing time and the number of requests. You can compare the number of slow requests with the number of fast requests in this chart. In the right-hand panel of Apollo Engine, under Metrics, you'll see all your GraphQL operations. If you select one of these, you can get even more detailed statistics. Now, switch to the Traces tab at the top. The first chart on this page looks as follows: The latency distribution chart shows all the different latencies for the currently-selected operation, including the number of sent requests with that latency. In the preceding example, I used the postsFeed query. Each request latency has its own execution timetable. You can see it by clicking on any column in the preceding chart. The table should look like the following screenshot: The execution timetable is a big foldable tree. It starts at the top with the root query, postsFeed, in this case. You can also see the overall time it took to process the operation. Each resolver function has got its own latency, which might include, for example, the time taken for each post and user to be queried from the database. All the times from within the tree are summed up and result in a total time of about 90 milliseconds. It's obvious that you should always check all operations and their latencies to identify performance breakdowns. Your users should always have responsive access to your API. This can easily be monitored with Apollo Engine. Error tracking with Apollo Engine We've already looked at how to inspect single operations using Apollo Engine. Under the Clients tab, you will find a separate view that covers all client types and their requests: In this tab, you can directly see the percentage of errors that happened during each operation. In the currentUser query, there were 37.14% errors out of the total currentUser requests. If you take a closer look at the left-hand side of the image, you will see that it says, Unidentified clients. Since version 2.2.3 of Apollo Server, client awareness is supported. It allows you to identify the client and track how consumers use your API. Apollo automatically extracts an extensions field inside each GraphQL operation, which can hold a name and version. Both fields—Name and Version—are then directly transferred to Apollo Engine. We can filter by these fields in Apollo Engine. We will have a look at how to implement this in our back end next. In this example, we'll use HTTP header fields to track the client type. There will be two header fields: apollo-client-name and apollo-client-version. We'll use these to set custom values to filter requests later in the Clients page. Open the index.js file from the graphql folder. Add the following function to the engine property of the ApolloServer initialization: engine: { apiKey: ENGINE_KEY, generateClientInfo: ({ request }) => { const headers = request.http.headers; const clientName = headers.get('apollo-client-name'); const clientVersion = headers.get('apollo-client-version'); if(clientName && clientVersion) { return { clientName, clientVersion }; } else { return { clientName: "Unknown Client", clientVersion: "Unversioned", }; } }, }, The generateClientInfo function is executed with every request. We extract the two fields from the header. If they exist, we return an object with the clientName and clientVersion properties that have the values from the headers. Otherwise, we return a static Unkown Client text. To get both of our clients – the front end and back end – set up, we have to add these fields. Perform the following steps: Open the index.js file of the client's apollo folder file. Add a new InfoLink to the file to set the two new header fields: const InfoLink = (operation, next) => { operation.setContext(context => ({ ...context, headers: { ...context.headers, 'apollo-client-name': 'Apollo Frontend Client', 'apollo-client-version': '1' }, })); return next(operation); }; Like AuthLink, this link will add the two new header fields next to the authorization header. It sets the version header to '1' and the name of the client to 'Apollo Frontend Client'. We will see both in Apollo Engine soon. Add InfoLink in front of AuthLink in the ApolloLink.from function. On the back end, we need to edit the apollo.js file in the ssr folder: const InfoLink = (operation, next) => { operation.setContext(context => ({ ...context, headers: { ...context.headers, 'apollo-client-name': 'Apollo Backend Client', 'apollo-client-version': '1' }, })); return next(operation); }; The link is almost the same as the one for the front end, except that we set another apollo-client-name header. Add it just before AuthLink in the ApolloLink.from function. The client name differs between the front end and back end code so you can compare both clients inside Apollo Engine. If you execute some requests from the back end and front end, you can see the result of these changes directly in Apollo Engine. Here, you can see an example of how that result should look: At the top of the screenshot, we see the number of requests the back end has made. In the middle, all the clients that we have no further information on are listed, while at the bottom, we can see all requests that have been made by the client-side code. Unknown clients might be external applications that are accessing your API. When releasing a new version of your application, you can increase the version number of the client. The version number represents another comparable field. We now know which clients have accessed our API from the information provided by Apollo Engine. Let's take a look at what Apollo Engine can tell us about errors. When you visit the Error tab, you will be presented with a screen that looks like the following screenshot: The first chart shows the number of errors over a timeline. Under the graph, you can see each error with a timestamp and the stack trace. You can follow the link to see the trace in detail, with the location of the error. If you paid for the Team plan, you can also set alerts when the number of errors increases or the latency time goes up. You can find these alerts under the Integrations tab. This article walked you through how to sign up to and set up Apollo Engine. Further, we will learn how to analyze schemas, check how our GraphQL API is performing, and track errors using Apollo Engine. If you found this post useful, do check out the book, Hands-on Full-Stack Web Development with GraphQL and React. This book teaches you how to build scalable full-stack applications while learning to solve complex problems with GraphQL. Applying Modern CSS to Create React App Projects [Tutorial] Keeping animations running at 60 FPS in a React Native app [Tutorial] React Native development tools: Expo, React Native CLI, CocoaPods [Tutorial]
Read more
  • 0
  • 0
  • 5457
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-creating-your-first-blackberry-project
Packt
23 Jul 2010
14 min read
Save for later

Creating your First BlackBerry Project

Packt
23 Jul 2010
14 min read
(For more resources on BlackBerry, see here.) So, without any further words, let's get to work! Choosing the SDK version Remember that the first step is to choose the SDK version to use. For this project we want to choose the lowest possible SDK version, which is 4.2.1. This is because this application is so simple that it will not need to use any of the newer features of more recent versions of the SDK. By choosing a lower version, more models of handheld can be used to run this application. Conversely, choosing a higher SDK version means that fewer models of handhelds can run the application. Therefore, you should choose the lowest version of the SDK that still supports the features you require in order to support as many devices as possible. We will go through the steps of actually applying this later on, but for now, the choice is made and we are ready to move on. Creating a new project You need to create a new project for your new application. The IDE makes it very simple to get started, but because you are creating a BlackBerry project you have to be careful. Let's get started and see what I mean. Time for action – creating a new project You can create a new project by clicking on File | New | Project... option in the menu bar (not the File | Java Project menu item). The New Project dialog gives you many choices for which type of project to create. You want to create a BlackBerry project, of course. Expand the BlackBerry folder in the tree and then select the BlackBerry Project node. When that is done click on the Next button. Enter TipCalc as the name of the application and click on the Finish button to create the new project. What just happened? These three steps are all that is needed to create a BlackBerry project in Eclipse. You were told earlier that choosing New | Java Project was not the right thing to do. This is because the wizard that you get from choosing this menu item is the Swiss Army Knife wizard that will set up any kind of project for Eclipse. It is powerful, complicated, and not for beginners. Because of this, we just won't use it at all. The BlackBerry Project option is much easier to use, you just have to remember to use the New | Project... option instead of the New | Java Project option. Once you have chosen the right menu item, the New Project dialog is shown. Apparently, it is possible to have so many project types available that finding the one you want can be a challenge. The text field at the top of the dialog will filter the tree below to include only projects whose name matches the filter test. In our case though, the BlackBerry project is right near the top and easily accessible so there really isn't a need for the search feature. The last step of the wizard prompts you to enter the name of your new application. Project names are used as a directory name but are not used in code so they can have some special characters, such as a space, which would otherwise be invalid for code. If you try to provide a name that is invalid the wizard will show a warning about the name to indicate the name is not valid. Below the Project name text box is a checkbox indicating to use the default workspace location. By leaving the box checked the new project will be placed in a directory named after the project name under the directory set as the workspace. You can change the location where the new project files are stored by unchecking the Default location checkbox and then entering a new location in the edit field provided. Adding a package to the new project Next, you will create a new package for the application to use. A Java package is a container for the objects in your application and is used to prevent conflicts if the classes you create happen to have the same name as another class in the same project or even the system classes. Packages are equivalent to namespaces in C# and Visual Basic .NET (VB.NET). Adding a package to the project in this way is a minor housekeeping task, but is also an overall good technique because it forces you to choose your package name up front before creating any code. In Java, the naming convention for a package is to use your Internet domain name in reverse—almost like you were creating a new server. In this case, we will use the package name com.rimdev.demo.tipcalc. The package name can be any valid Java name and doesn't have to follow these conventions. Time for action – creating a new project Add the package by right-clicking on the src folder in the Package Explorer and then selecting New | Package. After selecting the menu the New Java Package wizard is shown. This small wizard is here only to collect the folder where the package files will be and the name of the package itself. Because you selected the src folder to begin with, that part is already filled in so you need to specify only the name of the package. Enter the package name com.rimdev.demo.tipcalc into the Name field and then click on Finish to create the package. What just happened? At this point you have an empty project that is ready to start being used. You've taken the BlackBerry application project that you had before and added a package to the src directory in preparation for creating the actual source files (which will come next). The project tree is expanded slightly to include the package you just created under the src directory—the directory whose icon looks like a little mail parcel. Creating a package in your project doesn't result in any actual source files being created. Instead, it sets up the project so that when you do create files later on they will be created with package definitions already included in them. Start at the beginning Every application must have a starting point, and for BlackBerry applications it is at a method named main. The use of the name main goes all the way back to the C programming language, if not further. At that time, simply making a method named main was enough to be able to run an application. However, because Java is an object-oriented language, you can't just make a method named main. In Java, all methods must be in a class, and this includes the method main as well. In addition to the main method all BlackBerry applications must contain an object derived from Application as well. As both the Application-derived class and the main method are required, it is standard practice to include the main method in the same class as your Application. Application and UiApplication As we just said, every BlackBerry application must contain a class derived from Application. The Application class contains the bare essentials for interacting with the BlackBerry operating system. If an application displays a User Interface (UI) then the bare essentials in the Application class are not enough. Instead, you should use UiApplication—the derived class that handles the special processing needed to interact with the user as well as the operating system. So, the next step is to create a class derived from UiApplication and that contains the main method to serve as the starting point of your BlackBerry application. Time for action – adding the UiApplication class To create this starting class right-click on the package you just created in the project and select New | Class. First, give the class a name; enter TipCalcApplication into the Name field. The next step is to set the superclass for your new class. The superclass is another name for a base class, or the class from which your new class will be derived. Eclipse offers a strong browser tool to quickly and easily find the class. Click on the Browse button next to the Superclass field . This dialog is aware of all of the classes in the libraries and allows you to choose the proper one. By default, the class java.lang.Object is set as the superclass. Replace java.lang.Object with uiapplication. Notice that as you do so, other class names appear in the list below, but once it is completely entered only the net.rim.device.api."ui.UiApplication" class is shown. Also notice that even though you entered the name in lowercase and did not enter the complete package name, the filter found the correct class with the correct casing. Click on OK to select this class. Back at the New Java Class dialog there is one more setting to make and that is to check the public static void main(String args[]) option. This creates a stub main function that is used to initiate the application. Use this checkbox only when creating UiApplication objects ; no other classes need them. Check the public static void main(String[] args) checkbox so the wizard will generate the main function. Finally, click on Finish and see the new class in the project. What just happened? You just created the first class for use in your new application! Well, to be more accurate you used Eclipse to set up a new class with some standard elements based on how you filled out the dialog. You could have done the same thing by simply creating a new file and manually adding all of the code by hand, but that's just not as interesting, is it? To be real though, the tools that Eclipse provides are truly helpful and easy to use. The New Java Class dialog that is displayed has many options that can be set and which will cause Eclipse to generate different code. Notice that the package name has already been supplied in the dialog because we started creating this class by right-clicking on the package name in the project. Also, the Source Folder is properly set already because you created the package inside the src folder previously. A closer look at the code Now, let's look at the code that was generated. package com.rimdev.demos.tipcalc;import net.rim.device.api.ui.UiApplication;public class TipCalcApplication extends UiApplication { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub }} The first line of code is the package declaration for com.rimdev.demos.tipcalc. This line defines the package where the TipCalcApplication class will reside. The package can be specified in the New Class dialog but because we previously added the package to the project, the package was supplied automatically to the new New Class dialog. package com.rimdev.demos.tipcalc; The next line is an import statement for net.rim.device.api.ui.UiApplication. Import statements are similar to .NET using or imports statements and declare which libraries are being used. The Java convention is to specifically import each class being referenced. It is possible to wildcard the import statement though, in which case the class name would be replaced with *, that is, net.rim.device.api.ui.*. When doing this all of the classes in that package will be imported into your application and this can make coding easier. It can certainly be annoying having to go back each time you want to use a new class and add the import statement for it. Eclipse is pretty smart and shouldn't include any classes unless they are actually being used when it compiles your application, so there shouldn't be any negative impact on performance. Having said all that, the established convention is not to use wildcarding because it also makes it less clear for someone looking at your application later on to know exactly which classes are being used. In the end, it is probably best to stay with the established convention, which we will do in this article. import net.rim.device.api.ui.UiApplication; Next, we have the class declaration itself. Again, notice that the extends keyword is already added and the class chosen to be the superclass, UiApplication, is added as well. These are added because we chose the UiApplication to be the superclass in the New Class dialog. public class TipCalcApplication extends UiApplication { Lastly, notice that the public static void main method is also created. Remember that every application must have a main method, and this is that method. The method was added because we checked the checkbox for it. Very simple and easy! The words public and static are special keywords that allow the main method to be called by the system before any of the objects in your application are created. public static void main(String[] args) { // TODO Auto-generated method stub} Time for action – expanding TipCalcApplication Now that you have the class created with some of the boilerplate code it's time to expand it and make the application actually do something. You can start off by giving the static main function something to do. Replace the main method with the following code. /** * @param args */public static void main(String[] args) { // TODO Auto-generated method stub // Create a new instance of the application. TipCalcApplication theApp = new TipCalcApplication(); // To make the application enter the event thread and startprocessing messages, // we invoke the enterEventDispatcher() method. theApp.enterEventDispatcher();} Secondly, you need to add the TipCalcApplication constructor to the class so add the following code. private TipCalcApplication(){ // Push the main screen instance onto the UI stack forrendering. pushScreen(new TipCalcMainScreen());} What just happened? The code that you just added takes the simple generated code that you got from the New Class wizard and expands it to set up and start the application. The first thing you did was to put some code in the initially empty main method. This code in the main function is used to actually create an instance of the application's object, which happens to contain the main method. This may seem strange unless you are used to it and understand what the static keyword means. If not, then just understand that static means that the main method can be called without an instance of the object that contains it. You still do need to create an instance of the application though, and so that's the first step. theApp = new TipCalcApplication(); The next line of code in the main method is the call to the enterEventDispatcher method on the application that you just created. This is a method already implemented in the UiApplication class. It does all of the setup necessary to get the application started, runs the application, and waits until the application is finished. theApp.enterEventDispatcher(); As we said earlier, an Application object is required, but it's the main function that is the actual entry point of the program. When the main function is exited the application is terminated and cleaned up by the operating system. The Application object, and more specifically the call to enterEventDispatcher, is why a class derived from Application is required. The last thing to do for this class is to create the constructor and show the first screen. We haven't created the screen yet, but we can go ahead and create the code to use it. The constructor is also very simple and does only one thing. You could do more in the setup and initialization of things in the application constructor of course (if your application needs it), but this simple application does not. Here we create a new instance of the TipCalcMainScreen class and then push it onto the UI stack. The TipCalcMainScreen is the class that you will create next and is the screen that you will display to the user. We will come back to pushScreen and the UI Stack later. pushScreen(new TipCalcMainScreen());
Read more
  • 0
  • 0
  • 5456

article-image-detecting-shapes-employing-hough-transform
Packt
29 Oct 2015
13 min read
Save for later

Detecting Shapes Employing Hough Transform

Packt
29 Oct 2015
13 min read
In this article by Amgad Muhammad, the author of OpenCV Android Programming By Example, we will see a famous shape analysis technique called the Hough Transform. You will learn about the basic idea behind this technique, which made it very popular and widely used. Detecting shapes We have seen how to detect edges; however, this process is a pixel-by-pixel process that answers the question whether this pixel is an edge or not. Moving forward in shape analysis, we would need more concrete information than just the edge test; we will need better representation. For example, if we have a picture of a box and we did the edge detection, we will end up with thousands and thousands of edge pixels; however, if we tried to fit a line to these edge pixels, we will get a rectangle that is more symbolic and is a useful representation. Understanding the Hough line transform There are many ways to fit a line through a number of points and Hough transform is considered the underconstrained method where we use only one point to find all the possible lines that can go through this point. We use another point to also find all the lines that can go through it and we keep doing this for all the points that we have. We end up with a voting system where each point is voting for a line and the more points laying on the same line, the higher the votes given to this line. In a nutshell, the Hough transform can be described as mapping a point in  space to the parameter space of the shape of interest. With the equation of a line in the x and y space, , we transform it to the slope (a) and intercept space (b) and with this transformation, a point in the x and yspace is actually a line in the slope and intercept space with the equation : Insert image_4584_03_07.png Here we have five points in the x and y space (left). When converted to the slope and intercept space, we get five lines (right): Insert image_4584_03_08.png Now, every point in the x and y space will vote for a slope and intercept in the slope and intercept space, so all we have to do is find the maxima in the parameter space and this will be the line to fit our points: Insert image_4584_03_09.png In the right image, you can find the maxima value based on the votes of the points in the left image, and in the left image you can see that maxima is the slope and intercept of the line fitting the points. In the case of vertical lines, the slope is infinity; that's why it is more practical to use the polar equation of a line instead of the slope and intercept form. In this case, the equation that we will work with is  and again, we have two parameters,  and , and we will follow the same idea except that now the space is and  instead of the slope and intercept: Insert image_4584_03_10.png We will follow the voting system to find the maxima, which represents the  and  of the line fitting our points. However, this time, a point in the  and  space will be sinusoid, and if two or more sinusoids intersect at the same and , this means that they belong to the same line: Insert image_4584_03_11.png You can see the Hough transform in action using the applets at http://www.rob.cs.tu-bs.de/teaching/interactive/. Detecting lines using Hough transform In OpenCV, we have two implementations of the Hough line transform: The standard Hough transform: The process is pretty much following the preceding process; however, it is considered the slower option as the algorithm has to examine all the edge points in a given image. The probabilistic Hough line transform: This option is the one that we will use in our example. In the probabilistic version, the algorithm attempts to minimize the amount of computation needed to detect lines by exploiting the difference in the fraction of votes needed to detect the lines. Intuitively, for strong/long lines, we only need a small fraction of its supporting points to vote before deciding if the accumulator bin reaches a count that is non-accidental; however, for shorter lines, a higher portion is needed to decide this. In conclusion, the algorithm tries to minimize the number of edge points that are needed to decide on the fitting line. UI definitions We will add a new item menu to start the Hough transform algorithm. Go to the res/menu/soft_scanner.xml file and open it to include the following item menu: <item android_id="@+id/action_HTL"        android_enabled="true"        android_visible="true"        android_title="@string/action_HL"> </item> Detecting and drawing lines The process to use the Hough line transform is divided in four steps: Load the image of interest. Detect image edges using Canny; the output will be a binary image. Call either the standard or probabilistic Hough line transform on the binary image. Draw the detected lines. In SoftScanner Activity, we need to edit the onOptionesItemSelected method and add the following case: else if(id==R.id.action_HTL) {   if(sampledImage==null)   {     Context context = getApplicationContext();     CharSequence text = "You need to load an image first!";     int duration = Toast.LENGTH_SHORT;       Toast toast = Toast.makeText(context, text, duration);     toast.show();     return true;   }   Mat binaryImage=new Mat();   Imgproc.cvtColor(sampledImage,     binaryImage,Imgproc.COLOR_RGB2GRAY);     Imgproc.Canny(binaryImage, binaryImage, 80, 100);     Mat lines = new Mat();   int threshold = 50;     Imgproc.HoughLinesP(binaryImage, lines, 1, Math.PI/180,     threshold);   Imgproc.cvtColor(binaryImage, binaryImage,     Imgproc.COLOR_GRAY2RGB);   for (int i = 0; i < lines.cols(); i++)   {     double[] line = lines.get(0, i);     double xStart = line[0],     yStart = line[1],     xEnd = line[2],     yEnd = line[3];      org.opencv.core.Point lineStart = new       org.opencv.core.Point(xStart, yStart);     org.opencv.core.Point lineEnd = new       org.opencv.core.Point(xEnd, yEnd);       Core.line(binaryImage, lineStart, lineEnd, new       Scalar(0,0,255), 3);   }   displayImage(binaryImage);     return true; } The code is actually straightforward, as follows: if(sampledImage==null) {   Context context = getApplicationContext();   CharSequence text = "You need to load an image first!";   int duration = Toast.LENGTH_SHORT;     Toast toast = Toast.makeText(context, text, duration);   toast.show();   return true; } We first handle the case if the user clicks the item menu and didn't load an image: Mat binaryImage=new Mat(); Imgproc.cvtColor(sampledImage, binaryImage,   Imgproc.COLOR_RGB2GRAY);   Imgproc.Canny(binaryImage, binaryImage, 80, 100); Then, we initialize a new Mat object and convert the loaded image from the full color space to the grayscale space. Finally, we call Imgproc.Canny to convert the grayscale image to a binary image with only the edges displayed: Mat lines = new Mat(); int threshold = 50; Imgproc.HoughLinesP(binaryImage, lines, 1, Math.PI/180, threshold); The next step is to call Imgproc.HoughLinesP, which is the probabilistic version of the original Hough transform method, passing in the following parameters: A Mat object representing the binary image version of the loaded image A Mat object to hold the detected lines as the parameters A double for the resolution, in pixels, of the parameter, ; in our case, we set it to one pixel A double for the resolution, in radians, of the parameter, ; in our case, we set to it to one degree, An integer for the accumulator threshold to return only the lines with enough votes Usually, when using the probabilistic version of the Hough transform, you would use a smaller threshold because the algorithm is used to minimize the number of points used to vote. However, in the standard Hough transform, you should use a larger threshold. Imgproc.cvtColor(binaryImage, binaryImage, Imgproc.COLOR_GRAY2RGB); for (int i = 0; i < lines.cols(); i++) {   double[] line = lines.get(0, i);   double xStart = line[0],   yStart = line[1],   xEnd = line[2],   yEnd = line[3];   org.opencv.core.Point lineStart = new     org.opencv.core.Point(xStart, yStart);   org.opencv.core.Point lineEnd = new     org.opencv.core.Point(xEnd, yEnd);     Core.line(binaryImage, lineStart, lineEnd, new Scalar(0,0,255), 3); } displayImage(binaryImage); Finally, we convert the binary image to a full color space to display the detected lines and then we loop on the detected lines' Mat object columns and draw them one by one using the parameters, : Insert image_4584_03_15.png Hough lines (in blue) detected from the edge image Detecting circles using Hough transform OpenCV provides another implementation of the Hough transform, but this time, instead of detecting lines, we will detect circles following the same idea of transforming the  space to the parameters space. With an equation of a circle, ,we have three parameters, ; where a and b are the centers of the circle in the x and y direction, respectively, and r is the radius. Now, the parameter space is three-dimensional and every edge point belonging to a circle will vote in this three-dimensional space; then we search for the maxima in the parameter space to detect the circle center and radius. This procedure is very memory- and computation-intensive and the three-dimensional space will be very sparse. The good news is that OpenCV implements the circle Hough transform using a method called Hough gradient method. The Hough gradient method works as follows: in step one, we will apply an edge detector, for example, the Canny edge detector. In step two, we will increment the accumulator cells (two-dimensional space) in the direction of the gradient for every edge pixel. Intuitively, if we are encountering a circle, the accumulator cell with higher votes is actually that circle's center. Now, we have built a list of potential centers and we need to find the circle's radius so we will—for every center—consider the edge pixels by sorting them according to their distance from the center and keep a single radius that is supported (voted for) by the highest number of edge pixels: Insert image_4584_03_14.jpg UI definitions To trigger the circle Hough transform, we will add one item to our existing menu. Go to the res/menu/soft_scanner.xml file and open it to include the following item menu: <item android_id="@+id/action_CHT"        android_enabled="true"        android_visible="true"        android_title="@string/action_CHT"> </item> Detecting and drawing circles The process of detecting circles is similar to the process of detecting lines: Load the image of interest. Convert it from a full color space to a grayscale space. Call the Hough circle transform method on the grayscale image. Draw the detected circles. We will again edit onOptionsItemSelected to handle the circle Hough transform case: else if(id==R.id.action_CHT) {   if(sampledImage==null)   {     Context context = getApplicationContext();     CharSequence text = "You need to load an image first!";     int duration = Toast.LENGTH_SHORT;       Toast toast = Toast.makeText(context, text, duration);     toast.show();     return true;   }   Mat grayImage=new Mat();   Imgproc.cvtColor(sampledImage, grayImage, Imgproc.COLOR_RGB2GRAY);     double minDist=20;   int thickness=5;   double cannyHighThreshold=150;   double accumlatorThreshold=50;   Mat circles = new Mat();   Imgproc.HoughCircles(grayImage, circles,     Imgproc.CV_HOUGH_GRADIENT, 1,     minDist,cannyHighThreshold,accumlatorThreshold,0,0);     Imgproc.cvtColor(grayImage, grayImage, Imgproc.COLOR_GRAY2RGB);   for (int i = 0; i < circles.cols(); i++)   {     double[] circle = circles.get(0, i);     double centerX = circle[0],       centerY = circle[1],       radius = circle[2];     org.opencv.core.Point center = new       org.opencv.core.Point(centerX, centerY);     Core.circle(grayImage, center, (int) radius, new       Scalar(0,0,255),thickness);   }   displayImage(grayImage);   return true; } The code for the circle Hough transform is just as the one to detect lines except for the following part: double minDist=20; int thickness=5; double cannyHighThreshold=150; double accumlatorThreshold=50;   Mat circles = new Mat(); Imgproc.HoughCircles(grayImage, circles,   Imgproc.CV_HOUGH_GRADIENT, 1,   minDist,cannyHighThreshold,accumlatorThreshold,0,0);   Imgproc.cvtColor(grayImage, grayImage, Imgproc.COLOR_GRAY2RGB); for (int i = 0; i < circles.cols(); i++) {   double[] circle = circles.get(0, i);   double centerX = circle[0],     centerY = circle[1],     radius = circle[2];   org.opencv.core.Point center = new     org.opencv.core.Point(centerX, centerY);   Core.circle(grayImage, center, (int) radius, new     Scalar(0,0,255),thickness); } We detect circles by calling Imgproc.HoughCircles and passing to it the following parameters: A Mat object representing the 8-bit, single-channel grayscale input image. A Mat object that will hold the detected circles. Every column of the matrix will hold a circle represented by these parameters, . An integer for the detection method and currently, OpenCV only implements the Hough gradient algorithm. A double used as an inverse ratio of the accumulator resolution to the image resolution. For example, if we passed one, the accumulator has the same resolution as the input image. If we passed two, the accumulator is half the resolution of the input image. A double for the minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed. A double used for the upper threshold for the internal Canny edge detector; as it will be half the upper one for the lower threshold. A double for the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. An integer for the minimum radius to be detected; if unknown, pass zero. An integer for the maximum radius to be detected; if unknown, pass zero. Finally, we loop on the detected circles and draw them one by one using Core.circle. Summary In this article, we covered a well-known shape analysis technique called the Hough Transform to fit lines and circles in the edge pixels.  
Read more
  • 0
  • 0
  • 5455

article-image-redis-cluster-client-development
Zhe Lin
09 May 2016
5 min read
Save for later

Redis Cluster Client Development

Zhe Lin
09 May 2016
5 min read
In this post, I'd like to discuss how to write a client for a Redis Cluster a little deeper. The assumption here is that readers have a working knowledge of the Redis protocol, and therefore we will talk about how to deal with data sharding/resharding in a Redis Cluster. As is known, each Redis instance in a cluster serves a number of non-overlapping data slots. This means two basic things: There's a way to know how the cluster shards its dataset, which is the CLUSTER NODES command. If you send a data command such as GETSET to a Redis instance that doesn't contain the slot of the command key, you will get a MOVED error, so you need to keep the sharding information up to date. A CLUSTER NODES command to each Redis instance in a cluster will bring you equivalent sharding and replication information and can help you know who serves what. For example, the result could be like this: 33e5b1010d56d328370a993cf8420d70b3052d2c 127.0.0.1:7004 slave 71568798b4f1edeb0577614e072b492173b63808 0 1444704850437 2 connected 71568798b4f1edeb0577614e072b492173b63808 127.0.0.1:7002 master - 0 1444704848935 2 connected 3000-8499 f34b1ee569f3b856a80633a0b68892a58bfc87d2 127.0.0.1:7001 slave 1141f524b3ac82bb47bb101e0f8ae75ed56cdf54 0 1444704850938 1 connected 1141f524b3ac82bb47bb101e0f8ae75ed56cdf54 127.0.0.1:7003 master - 0 1444704849436 1 connected 0-2999 8500-10499 026f1e9b8c205de0a3645fd8a5eae3fbd0ca8639 127.0.0.1:7005 master - 0 1444704850838 3 connected 10500-16383 79ef081c431bbc7edc305a9611278be0df8fcd04 127.0.0.1:7000 myself,slave 026f1e9b8c205de0a3645fd8a5eae3fbd0ca8639 0 0 1 connected By simple splitting of each line by the space character, there are at least eight items a line. The first four items are node id, address, flags, and master node id. A node with the myself flag is the one receiving the CLUSTER NODES command. If a node has the slave flag, its master node ID, which won't be a dash, indicates who it has replicated. A node with a fail, fail?, or handshake flag is not connectible from others and may probably fail to respond, so you can just ignore it. Then let's see the items after the first eight, which indicate the slots held by the node. The slots' ranges are closed intervals; for example, 3000-8499 means 3000, 3001, ..., 8498, 8499, so the node at 127.0.0.1:7002 serves 5,500 slots. And the ranges could be separated so that the slots' ranges 127.0.0.1:7003 contained are 0-2999 and 8500-10499. After parsing the cluster information, you may know which master node a data command belongs to. If you don't mind getting possibly stale data, you can increase the QPS by sending reading commands to a slave. A hint is that you need to send a READONLY command before you can read data from the slave Redis. It's a good start if your client library is able to parse static sharding information. Since the Redis Cluster may reshard, you need to know what happens when Redis instances join or quit the cluster. For example, after a Redis that binds 127.0.0.1:8000 joined and slot #0 is migrating to it from 127.0.0.1:7003. However, your client probably has no idea about that and sends a command such as GET h-893 (h-893 is in slot #0) to 127.0.0.1:7003 as usual. Then the result could be one of the following: Normal response if the slot is in migrating state and the key hits the cache at 127.0.0.1:7003. An -ASK [ADDRESS] error if the slot is in migrating state and the key doesn't hit the cache (non-existent or just migrated). A -MOVED [SLOT#] [ADDRESS] error if the slot is completely migrated to the new instance. In case #2, you may need to retry the command later, and in either of the other two cases, you need to update the sharding information. You can simply redirect the command to the new address according to what the MOVED error told you, or update the complete slots mapping. When a Redis instance quits the cluster and become a free node, it won't reset your TCP connections, but will lways reply with a -CLUSTERDOWN error for any data commands. In this case, don't panic and try doing a sharding information update from other Redis instances (so that your client has to remember all the instances in case of it). But if you think it over, you may realize that there's a chance that the Redis can join another cluster after it quits the old one, and it happens to serve the same slots it used to. Therefore, you client may work normally but data actually goes somewhere else. So, your client ought to provide an approach for an initiative sharding update. As we have discussed normal cases, what happens when some Redis has been killed? This won't be so complicated if the slaves fail over their disconnected masters and eventually the cluster state turns to OK (otherwise, ask your Redis administrator to fix it immediately). Your client will encounter an I/O exception of TCP connection reset when the Redis server is down or some error is writing to the socket. Anyway, it's time to do a sharding information update. These are the things that a client for a Redis Cluster should cover. Hopefully, this helps you if you decide to write a cluster client, or provides you with valuable information if you want to learn more details about your client lib (provided you are already using a Redis Cluster). About the author Zhe Lin is a system engineer at the IT Developing Center at Hunantv.com. He is in charge of Redis related toolkit developing, maintenance and in-company training. Major works include: * [redis-trib.py] : Redis Cluster creating and resharding toolkit in Python2 * [redis-cerberus] : Redis Cluster proxy * [redis-ctl] : Redis management tool with web UI
Read more
  • 0
  • 0
  • 5453

article-image-mail-basics-ibm-lotus-notes-85
Packt
19 Aug 2010
6 min read
Save for later

Mail Basics in IBM Lotus Notes 8.5

Packt
19 Aug 2010
6 min read
(For more resources on IBM, see here.) Accessing mail in Lotus Notes The first step in exploring mail is to open mail in Lotus Notes. There are a couple of ways that we can open mail: First, from the Home page by clicking the Mail icon as in the following screenshot. If we click the New button, it will create a new message. Also, by clicking Open and selecting Mail from the list. Creating and replying to messages In the following sections we will discuss how to create and reply to messages including reviewing message actions including setting delivery options. Creating a message Once we have opened mail, we can create a message by clicking on the New button and then selecting Message as shown next. As we can see from the message drop down list, there are other options available such as Meeting, Contact, and so on that we can create. Another way to create a message is by using the keyboard shortcut Ctrl+M. This can be done from anywhere within Lotus Notes, not just when we have mail opened—for example, we can create a message when we are in our Calendar, from within Contacts, or from the Home page using the Ctrl+M option. Message actions Now that we have created a message, we will explore some of the message actions. Along the top of the message, we can see buttons that enable us to do certain things. The following is a screenshot of the available options. We will briefly explore each of these options. Send: This speaks for itself; when clicked the message is sent! Send and File…: This is an excellent option when sending messages, as it allows us to not only send the message but also to file the message into our folders at the same time. When we click Send and File…, we will see the Folders dialog box with all our personal folders available. The following is a screenshot of the Folders dialog box that appears when we select the Send and File option. We would select the folder we want to file the message into and then click either the OK button or press the Enter key. The message will be filed in the folder; it will also be automatically filed into Sent and All Documents. Note that this does not mean we have three copies of the message filed in the three locations. There is only the one copy of the message in our personal folder; Sent and All Documents. This means if we delete the message from our personal folder, it will be deleted from the Sent and All Documents. When the Folders dialog box opens, if we know the name of the folder, we can start typing the folder name and that folder will be highlighted. Then if we press the Enter key, the message will be filed into that folder. Typically this is a quicker option than scrolling, especially if we have several folders. When you type the folder name you can see what you have typed in the Status bar, you can delete what you have typed if you have made a typing error. Save as Draft: This option saves our message into the Drafts folder. Delivery Options: Include options such as mood stamps and prevent copying. Flag: We can flag a message before sending it. Attachment: Clicking this icon will allow us to add an attachment to our message. Note that we can also drag an attachment into the body of the memo from Windows Explorer. Display: When we click on this button, we can see further options regarding how we want our messages to be displayed. We can select if we want to show the BCC field, Additional Mail Options, or Sender Information. The following is a screenshot of what we can see when we enable the Additional Mail Options option: High Importance is indicated to the sender by a red exclamation mark. Return receipt sends us a notification when the recipient/s have read or previewed the message. Sign adds an electronic signature to the message to ensure it has not been tampered with. Encrypt marks the message secret and can be read by only those whose name appears in the To, CC, and BCC fields. Mark Subject Confidential prepends "Mark Subject Confidential" to the subject field. More: This is the last message action, from here we can access Preferences…, Out of Office..., and so on as shown in the screenshot. Delivery options When we click the Delivery Options button in a new message, a dialog box opens with two tabs. Basic tab: Note the difference between Return receipt and Delivery report—the Return receipt option sends us notification when the person has read or previewed the message, whereas the Delivery Report option tells us when the message failed to reach the recipient, which is the default option Only on failure. Other options available are Confirm delivery or Trace entire path; the later option shows us the server route taken to deliver the message. Take the time to check out the Mood Stamps. I prefer adding the Good Job mood stamp to a message when I am congratulating someone. I often use the Confident mood stamp when I am sending a sensitive message. I will also select the Encrypt option that allows only those in the To, Cc, and Bcc fields to read it as well as Prevent copying which prevents people from forwarding, printing, copying to the clipboard and replying with history. Combining these options ensures the message is kept secure. The signing option adds digital signature to the message to confirm to the recipient the authenticity of the individual who has sent the mail. Note that all three of these options typically work only for a message sent within our organization and may not be applied to messages sent to people external to us such as someone at another company. Advanced tab: On the Advanced tab, there are options that allow us to add a Please reply by date. We can also select that replies to the memo go to another person or several other people. We can also add our name. Some organizations have shared mail files such as Sales where messages sent to sales at the company name will go into a central mail file. It is preferable to add those addresses, along with my own, to the Replies to this memo should be addressed to field so that those we work with are kept in the loop with particular communications.
Read more
  • 0
  • 0
  • 5449
article-image-enhancing-page-elements-moodle-and-javascript
Packt
04 May 2011
7 min read
Save for later

Enhancing Page Elements with Moodle and JavaScript

Packt
04 May 2011
7 min read
  Moodle JavaScript Cookbook Over 50 recipes for making your Moodle system more dynamic and responsive with JavaScript Introduction The Yahoo! UI Library (YUI) offers a range of widgets and utilities to bring modern enhancements to your traditional page elements. In this chapter, we will look at a selection of these enhancements, including features often seen on modern interactive interfaces, such as: Auto-complete: This feature suggests possible values to the user by searching against a list of suggestions as they start typing. We will look at two different ways of using this. First, by providing suggestions as the user types into a text box, and second, by providing a list of possible values for them to select from a combo list box. Auto-update: This technique will allow us to update an area of the page based on a timed interval, which has many uses as we'll see. In this example, we will look at how to create a clock by updating the time on the page at one second intervals. This technique could also be used, for example, to update a news feed every minute, or update stock information every hour. Resizable elements: A simple enhancement which allows users to dynamically resize elements to suit their needs. This could be applied to elements containing a significant amount of text which would allow the user to control the width of the text to suit their personal preference for ideal readability. Custom tooltips: Tooltips appear when an element is hovered, displaying the associated title or alternative text (that is, a description of an image or the title of a hyperlink). This enhancement allows us to have more control over the look of the tooltips making them more visually appealing and more consistent with the overall look and feel of our page. Custom buttons: This enhancement allows us to completely restyle button elements, modifying their look and feel to be consistent with the rest of our page. This also allows us to have a consistent button style across different platforms and web browsers. We will once again be using mostly YUI Version 2 widgets and utilities within the YUI Version 3 framework. At the time of writing, few YUI2 widgets have been ported to YUI3. This method allows us the convenience of the improvements afforded by the YUI3 environment combined with the features of the widgets from YUI2. Adding a text box with auto-complete A common feature of many web forms is the ability to provide suggestions as the user types, based on a list of possible values. In this example, we enhance a standard HTML input text element with this feature. This technique is useful in situations where we simply wish to offer suggestions to the user that they may or may not choose to select, that is, suggesting existing tags to be applied to a new blog post. They can either select a suggested value that matches one they have started typing, or simply continue typing a new, unused tag. How to do it... First, set up a basic Moodle page in the usual way. In this example, we create autocomplete.php with the following content: <?php require_once(dirname(__FILE__) . '/../config.php'); $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); $PAGE->set_url('/cook/autocomplete.php'); $PAGE->requires->js('/cook/autocomplete.js', true); ?> <?php echo $OUTPUT->header(); ?> <div style="width:15em;height:10em;"> <input id="txtInput" type="text"> <div id="txtInput_container"></div> </div> <?php echo $OUTPUT->footer(); ?> Secondly, we need to create our associated JavaScript file, autocomplete.js, with the following code: YUI().use("yui2-autocomplete", "yui2-datasource", function(Y) { var YAHOO = Y.YUI2; var dataSource = new YAHOO.util.LocalDataSource ( ["Alpha","Bravo","Beta","Gamma","Golf"] ); var autoCompleteText = new YAHOO.widget.AutoComplete("txtInput", "txtInput_container", dataSource); }); How it works... Our HTML consists of three elements, a parent div element, and the other two elements contained within it: an input text box, and a placeholder div element to use to display the auto-complete suggestions. Our JavaScript file then defines a DataSource to be used to provide suggestions, and then creates a new AutoComplete widget based on the HTML elements we have already defined. In this example, we used a LocalDataSource for simplicity, but this may be substituted for any valid DataSource object. Once we have a DataSource object available, we instantiate a new YUI2 AutoComplete widget, passing the following arguments: The name of the HTML input text element for which to provide auto-complete suggestions The name of the container element to use to display suggestions A valid data source object to use to find suggestions Now when the user starts typing into the text box, any matching auto-complete suggestions are displayed and can be selected, as shown in the following screenshot: Adding a combo box with auto-complete In this example, we will use auto-complete in conjunction with a combo box (drop-down list). This differs from the previous example in one significant way—it includes a drop-down arrow button that allows the user to see the complete list of values without typing first. This is useful in situations where the user may be unsure of a suitable value. In this case, they can click the drop-down button to see suggestions without having to start guessing as they type. Additionally, this method also supports the same match-as-you-type style auto-complete as that of the previous recipe. How to do it... Open the autocomplete.php file from the previous recipe for editing, and add the following HTML below the text box based auto-complete control: <div style="width:15em;height:10em;"> <input id="txtCombo" type="text" style="vertical-align:top; position:static;width:11em;"><span id="toggle"></span> <div id="txtCombo_container"></div> </div> Next, open the JavaScript file autocomplete.js, and modify it to match the following code: YUI().use("yui2-autocomplete", "yui2-datasource", "yui2-element", "yui2-button", "yui2-yahoo-dom-event", function(Y) { var YAHOO = Y.YUI2; var dataSource = new YAHOO.util.LocalDataSource ( ["Alpha","Bravo","Beta","Gamma","Golf"] ); var autoCompleteText = new YAHOO.widget.AutoComplete("txtInput", "txtInput_container", dataSource); var autoCompleteCombo = new YAHOO.widget.AutoComplete("txtCombo", "txtCombo_container", dataSource, {minQueryLength: 0, queryDelay: 0}); var toggler = YAHOO.util.Dom.get("toggle"); var tButton = new YAHOO.widget.Button({container:toggler, label:"↓"}); var toggle = function(e) { if(autoCompleteCombo.isContainerOpen()) { autoCompleteCombo.collapseContainer(); } else { autoCompleteCombo.getInputEl().focus(); setTimeout(function() { autoCompleteCombo.sendQuery(""); },0); } } tButton.on("click", toggle); }); You will notice that the HTML we added in this recipe is very similar to the last, with the exception that we included a span element just after the text box. This is used as a placeholder to insert a YUI2 button control. This recipe is somewhat more complicated than the previous one, so we included some extra YUI2 modules: element, button, and yahoo-dom-event. We define the AutoComplete widget in the same way as before, except we need to add two configuration options in an object passed as the fourth argument. Next, we retrieve a reference to the button placeholder, and instantiate a new Button widget to use as the combo box 'drop-down' button. Finally, we define a click handler for the button, and register it. We now see the list of suggestions, which can be displayed by clicking on the drop-down button, as shown in the following screenshot: How it works... The user can type into the box to receive auto-complete suggestions as before, but may now use the combo box style drop-down button instead to see a list of suggestions. When the user clicks the drop-down button, the click event is fired. This click event does the following: Hides the drop-down menu if it is displayed, which allows the user to toggle this list display on/off. If it is not displayed, it sets the focus to the text box (to allow the user to continue typing), and execute a blank query on the auto-complete widget, which will display the list of suggestions. Note that we explicitly enabled this blank query earlier when we defined the AutoComplete widget with the "minQueryLength: 0" option, which allowed queries of length 0 and above.  
Read more
  • 0
  • 0
  • 5449

article-image-webgl-animating-3d-scene
Packt
20 Jun 2012
10 min read
Save for later

WebGL: Animating a 3D scene

Packt
20 Jun 2012
10 min read
We will discuss the following topics: Global versus local transformations Matrix stacks and using them to perform animation Using JavaScript timers to do time-based animation Parametric curves Global transformation allows us to create two different kinds of cameras. Once we have applied the camera transform to all the objects in the scene, each one of them could update its position; representing, for instance, targets that are moving in a first-person shooting game, or the position of other competitors in a car racing game. This can be achieved by modifying the current Model-View transform for each object. However, if we modified the Model-View matrix, how could we make sure that these modifications do not affect other objects? After all, we only have one Model-View matrix, right? The solution to this dilemma is to use matrix stacks. Matrix stacks A matrix stack provides a way to apply local transforms to individual objects in our scene while at the same time we keep the global transform (camera transform) coherent for all of them. Let's see how it works. Each rendering cycle (each call to draw function) requires calculating the scene matrices to react to camera movements. We are going to update the Model-View matrix for each object in our scene before passing the matrices to the shading program (as attributes). We do this in three steps as follows: Once the global Model-View matrix (camera transform) has been calculated, we proceed to save it in a stack. This step will allow us to recover the original matrix once we had applied to any local transforms. Calculate an updated Model-View matrix for each object in the scene. This update consists of multiplying the original Model-View matrix by a matrix that represents the rotation, translation, and/or scaling of each object in the scene. The updated Model-View matrix is passed to the program and the respective object then appears in the location indicated by its local transform. We recover the original matrix from the stack and then we repeat steps 1 to 3 for the next object that needs to be rendered. The following diagram shows this three-step procedure for one object: Animating a 3D scene To animate a scene is nothing else than applying the appropriate local transformations to objects in it. For instance, if we have a cone and a sphere and we want to move them, each one of them will have a corresponding local transformation that will describe its location, orientation, and scale. In the previous section, we saw that matrix stacks allow recovering the original Model-View transform so we can apply the correct local transform for the next object to be rendered. Knowing how to move objects with local transforms and matrix stacks, the question that needs to be addressed is: When? If we calculated the position that we want to give to the cone and the sphere of our example every time we called the draw function, this would imply that the animation rate would be dependent on how fast our rendering cycle goes. A slower rendering cycle would produce choppy animations and a too fast rendering cycle would create the illusion of objects jumping from one side to the other without smooth transitions. Therefore, it is important to make the animation independent from the rendering cycle. There are a couple of JavaScript elements that we can use to achieve this goal: The requestAnimFrame function and JavaScript timers. requestAnimFrame function The window.requestAnimFrame() function is currently being implemented in HTML5-WebGL enabled Internet browsers. This function is designed such that it calls the rendering function (whatever function we indicate) in a safe way only when the browser/tab window is in focus. Otherwise, there is no call. This saves precious CPU, GPU, and memory resources. Using the requestAnimFrame function, we can obtain a rendering cycle that goes as fast as the hardware allows and at the same time, it is automatically suspended whenever the window is out of focus. If we used requestAnimFrame to implement our rendering cycle, we could use then a JavaScript timer that fires up periodically calculating the elapsed time and updating the animation time accordingly. However, the function is a feature that is still in development. To check on the status of the requestAnimFrame function, please refer to the following URL: Mozilla Developer Network JavaScript timers We can use two JavaScript timers to isolate the rendering rate from the animation rate. The rendering rate is controlled by the class WebGLApp. This class invokes the draw function, defined in our page, periodically using a JavaScript timer. Unlike the requestAnimFrame function, JavaScript timers keep running in the background even when the page is not in focus. This is not an optimal performance for your computer given that you are allocating resources to a scene that you are not even looking. To mimic some of the requestAnimFrame intelligent behavior provided for this purpose, we can use the onblur and onfocus events of the JavaScript window object. Let's see what we can do: Action (What) Goal (Why) Method (How) Pause the rendering To stop the rendering until the window is in focus Clear the timer calling clearInterval in the window.onblur function Slow the rendering To reduce resource consumption but make sure that the 3D scene keeps evolving even if we are not looking at it We can clear current timer calling clearInterval in the window.onblur function and create a new timer with a more relaxed interval (higher value) Resume the rendering To activate the 3D scene at full speed when the browser window recovers its focus We start a new timer with the original render rate in the window.onfocus function By reducing the JavaScript timer rate or clearing the timer, we can handle hardware resources more efficiently. In WebGLApp you can see how the onblur and onfocus events have been used to control the rendering timer as described previously. Timing strategies In this section, we will create the second JavaScript timer that will allow controlling the animation. As previously mentioned, a second JavaScript timer will provide independency between how fast your computer can render frames and how fast we want the animation to go. We have called this property the animation rate. However, before moving forward you should know that there is a caveat when working with timers: JavaScript is not a multi-threaded language. This means that if there are several asynchronous events occurring at the same time (blocking events) the browser will queue them for their posterior execution. Each browser has a different mechanism to deal with blocking event queues. There are two blocking event-handling alternatives for the purpose of developing an animation timer. Animation strategy The first alternative is to calculate the elapsed time inside the timer callback. The pseudo-code looks like the following: var initialTime = undefined; var elapsedTime = undefined; var animationRate = 30; //30 ms function animate(deltaT){ //calculate object positions based on deltaT } function onFrame(){ elapsedTime = (new Date).getTime() – initialTime; if (elapsedTime < animationRate) return; //come back later animate(elapsedTime); initialTime = (new Date).getTime(); } function startAnimation(){ setInterval(onFrame,animationRate/1000); } Doing so, we can guarantee that the animation time is independent from how often the timer callback is actually executed. If there are big delays (due to other blocking events) this method can result in dropped frames. This means the object's positions in our scene will be immediately moved to the current position that they should be in according to the elapsed time (between consecutive animation timer callbacks) and then the intermediate positions are to be ignored. The motion on screen may jump but often a dropped animation frame is an acceptable loss in a real-time application, for instance, when we move one object from point A to point B over a given period of time. However, if we were using this strategy when shooting a target in a 3D shooting game, we could quickly run into problems. Imagine that you shoot a target and then there is a delay, next thing you know the target is no longer there! Notice that in this case where we need to calculate a collision, we cannot afford to miss frames, because the collision could occur in any of the frames that we would drop otherwise without analyzing. The following strategy solves that problem. Simulation strategy There are several applications such as the shooting game example where we need all the intermediate frames to assure the integrity of the outcome. For example, when working with collision detection, physics simulations, or artificial intelligence for games. In this case, we need to update the object's positions at a constant rate. We do so by directly calculating the next position for the objects inside the timer callback. var animationRate = 30; //30 ms var deltaPosition = 0.1 function animate(deltaP){ //calculate object positions based on deltaP } function onFrame(){ animate(deltaPosition); } function startAnimation(){ setInterval(onFrame,animationRate/1000); } This may lead to frozen frames when there is a long list of blocking events because the object's positions would not be timely updated. Combined approach: animation and simulation Generally speaking, browsers are really efficient at handling blocking events and in most cases, the performance would be similar regardless of the chosen strategy. Then, deciding to calculate the elapsed time or the next position in timer callbacks will then depend on your particular application. Nonetheless, there are some cases where it is desirable to combine both animation and simulation strategies. We can create a timer callback that calculates the elapsed time and updates the animation as many times as required per frame. The pseudocode looks like the following: var initialTime = undefined; var elapsedTime = undefined; var animationRate = 30; //30 ms var deltaPosition = 0.1; function animate(delta){ //calculate object positions based on delta } function onFrame(){ elapsedTime = (new Date).getTime() - initialTime; if (elapsedTime < animationRate) return; //come back later! var steps = Math.floor(elapsedTime / animationRate); while(steps > 0){ animate(deltaPosition); steps -= 1; } initialTime = (new Date).getTime(); } function startAnimation(){ initialTime = (new Date).getTime(); setInterval(onFrame,animationRate/1000); } You can see from the preceding code snippet that the animation will always update at a fixed rate, no matter how much time elapses between frames. If the app is running at 60 Hz, the animation will update once every other frame, if the app runs at 30 Hz the animation will update once per frame, and if the app runs at 15 Hz the animation will update twice per frame. The key is that by always moving the animation forward a fixed amount it is far more stable and deterministic. The following diagram shows the responsibilities of each function in the call stack for the combined approach: This approach can cause issues if for whatever reason an animation step actually takes longer to compute than the fixed step, but if that is occurring, you really ought to simplify your animation code or put out a recommended minimum system spec for your application. Web Workers: Real multithreading in JavaScript You may want to know that if performance is really critical to you and you need to ensure that a particular update loop always fires at a consistent rate then you could use Web Workers. Web Workers is an API that allows web applications to spawn background processes running scripts in parallel to their main page. This allows for thread-like operation with message-passing as the coordination mechanism. You can find the Web Workers specification at the following URL: W3C Web Workers
Read more
  • 0
  • 0
  • 5448

article-image-getting-started-modernizr-using-php-ide
Packt
30 Apr 2013
5 min read
Save for later

Getting started with Modernizr using PHP IDE

Packt
30 Apr 2013
5 min read
(For more resources related to this topic, see here.) From the Modernizr website: Modernizr is a small JavaScript library that detects the availability of native implementations for next-generation web technologies, i.e. features that stem from the HTML5 and CSS3 specifications. Many of these features are already implemented in at least one major browser (most of them in two or more), and what Modernizr does is, very simply, tell you whether the current browser has this feature natively implemented or not. Basically with this library, we can see if the user's browser can support certain features you wish to use on your site. This is important to do, as unfortunately not every browser is created the same. Each one has its own implementation of the HTML5 standard, so some features may be available on Google Chrome but not on Internet Explorer. Using Modernizr is a better alternative to the standard, but it is unreliable, user agent (UA) string checking. Let's begin. Getting ready Go ahead and create a new Web Project in Aptana Studio. Once it is set up, go ahead and add a new folder to the project named js. Next thing we need to do is to download the Development Version of Mondernizr from the Modernizr download page (http://modernizr.com/download/). You will see options to build your own package. The development version will do until you are ready for production use. As of this writing, the latest version is 2.6.2 and that will be the version we use. Place the downloaded file into the js folder. How to do it... Follow these steps: For this exercise, we will simply do a browser test to see if your browser currently supports the HTML5 Canvas element. Type this into a JavaScript file named canvas.js and add the following code: if (Modernizr.canvas) { var c=document.getElementById("canvastest"); var ctx=c.getContext("2d"); // Create gradient Var grd=ctx.createRadialGradient(75,50,5,90,60,100); grd.addColorStop(0,"black"); grd.addColorStop(1,"white"); // Fill with gradient ctx.fillStyle=grd; ctx.fillRect(10,10,150,80); alert("We can use the Canvas element!"); } else { alert("Canvas Element Not Supported"); } Now add the following to index.html: <!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Canvas Support Test</title> <script src = "js/modernizr-latest.js" type="text/ javascript"></script> </head> <body> <canvas id="canvastest" width="200" height="100" style="border:1px solid #000000">Your browser does not support the HTML5 canvas tag.</canvas> <script src = "js/canvas.js"> </script> </body> </html> Let's preview the code and see what we got. The following screenshot is what you should see: How it works... What did we just do? Well, let's break it down: <script src = "js/modernizr-latest.js" type="text/javascript"></script> Here, we are calling in our Modernizr library that we downloaded previously. Once you do that, Modernizr does some things to your page. It will redo your opening <html> tag to something like the following (from Google Chrome): <html class=" js flexbox flexboxlegacy canvas canvastext webgl notouch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths"> This is all the features your browser supports that Modernizr was able to detect. Next up we have our <canvas> element: <canvas id="canvastest" width="200" height="100" style="border:1px solid #000000">Your browser does not support the HTML5 canvas tag.</ canvas> Here, we are just forming a basic canvas that is 200 x 100 with a black border going around it. Now for the good stuff in our canvas.js file, follow this code snippet: <script> if (Modernizr.canvas) { alert("We can use the Canvas element!"); var c=document.getElementById("canvastest"); var ctx=c.getContext("2d"); // Create gradient var grd=ctx.createRadialGradient(75,50,5,90,60,100); grd.addColorStop(0,"black"); grd.addColorStop(1,"white"); // Fill with gradient ctx.fillStyle=grd; ctx.fillRect(10,10,150,80); } else { alert("Canvas Element Not Supported"); } </script> In the first part of this snippet, we used an if statement to see if the browser supports the Canvas element. If it does support canvas, then we are displaying a JavaScript alert and then filling our canvas element with a black gradient. After that, we have our else statement that will alert the user that canvas is not supported on their browser. They will also see the Your browser does not support the HTML5 canvas tag message. That wasn't so bad, was it? There's more... I highly recommend reading over the documentation on the Modernizr website so that you can see all the feature tests you can do with this library. We will do a few more practice examples with Modernizr, and of course, it will be a big component of our RESS project later on in the book. Keeping it efficient For a production environment, I highly recommend taking the build-a-package approach and only downloading a script that contains the tests you will actually use. This way your script is as small as possible. As of right now, the file we used has every test in it; some you may never use. So, to be as efficient as possible (and we want all the efficiency we can get in mobile development), build your file with the tests you'll use or may use. Summary This article provided guidelines on creating a new Web Project in Aptana Studio, creating new folder to the project named js, downloading the Development Version of Mondernizr from the Modernizr download page, and placing the downloaded file into the js folder. Resources for Article : Further resources on this subject: Let's Chat [Article] Blocking versus Non blocking scripts [Article] Building Applications with Spring Data Redis [Article]
Read more
  • 0
  • 0
  • 5445
article-image-handling-dom-dart
Packt
24 Dec 2013
15 min read
Save for later

Handling the DOM in Dart

Packt
24 Dec 2013
15 min read
(For more resources related to this topic, see here.) A Dart web application runs inside the browser (HTML) page that hosts the app; a single-page web app is more and more common. This page may already contain some HTML elements or nodes, such as <div> and <input>, and your Dart code will manipulate and change them, but it can also create new elements. The user interface may even be entirely built up through code. Besides that, Dart is responsible for implementing interactivity with the user (the handling of events, such as button-clicks) and the dynamic behavior of the program, for example, fetching data from a server and showing it on the screen. We explored some simple examples of these techniques. Compared to JavaScript, Dart has simplified the way in which code interacts with the collection of elements on a web page (called the DOM tree). This article teaches you this new method using a number of simple examples, culminating with a Ping Pong game. The following are the topics: Finding elements and changing their attributes Creating and removing elements Handling events Manipulating the style of page elements Animating a game Ping Pong using style(s) How to draw on a canvas – Ping Pong revisited Finding elements and changing their attributes All web apps import the Dart library dart:html; this is a huge collection of functions and classes needed to program the DOM (look it up at api.dartlang.org). Let's discuss the base classes, which are as follows: The Navigator class contains info about the browser running the app, such as the product (the name of the browser), its vendor, the MIME types supported by the installed plugins, and also the geolocation object. Every browser window corresponds to an object of the Window class, which contains, amongst many others, a navigator object, the close, print, scroll and moveTo methods, and a whole bunch of event handlers, such as onLoad, onClick, onKeyUp, onMouseOver, onTouchStart, and onSubmit. Use an alert to get a pop-up message in the web page, such as in todo_v2.dart: window.onLoad.listen( (e) => window.alert("I am at your disposal") ); If your browser has tabs, each tab opens in a separate window. From the Window class, you can access local storage or IndexedDB to store app data on the client The Window object also contains an object document of the Document class, which corresponds to the HTML document. It is used to query for, create, and manipulate elements within the document. The document also has a list of stylesheets (objects of the StyleSheet class)—we will use this in our first version of the Ping Pong game. Everything that appears on a web page can be represented by an object of the Node class; so, not only are tags and their attributes nodes, but also text, comments, and so on. The Document object in a Window class contains a List<Node> element of the nodes in the document tree (DOM) called childNodes. The Element class, being a subclass of Node, represents web page elements (tags, such as <p>, <div>, and so on); it has subclasses, such as ButtonElement, InputElement, TableElement, and so on, each corresponding to a specific HTML tag, such as <button>, <input>, <table>, and so on. Every element can have embedded tags, so it contains a List<Element> element called children. Let us make this more concrete by looking at todo_v2.dart, solely for didactic purposes—the HTML file contains an <input> tag with the id value task, and a <ul> tag with the id value list: <div><input id="task" type="text" placeholder="What do you want to do?"/> <p id="para">Initial paragraph text</p> </div> <div id="btns"> <button class="backgr">Toggle background color of header</button> <button class="backgr">Change text of paragraph</button> <button class="backgr">Change text of placeholder in input field and the background color of the buttons</button> </div> <div><ul id="list"/> </div> In our Dart code, we declare the following objects representing them: InputElement task; UListElement list; The following list object contains objects of the LIElement class, which are made in addItem(): var newTask = new LIElement(); You can see the different elements and their layout in the following screenshot: The screen of todo_v2 Finding elements Now we must bind these objects to the corresponding HTML elements. For that, we use the top-level functions querySelector and querySelectorAll; for example, the InputElement task is bound to the <input> tag with the id value task using: task = querySelector('#task'); . Both functions take a string (a CSS selector) that identifies the element, where the id value task will be preceded by #. CSS selectors are patterns that are used in .css files to select elements that you want to style. There are a number of them, but, generally, we only need a few basic selectors (for an overview visit http://www.w3schools.com/cssref/css_selectors.asp). If the element has an id attribute with the value abc, use querySelector('#abc') If the element has a class attribute with value abc, use querySelector('.abc') To get a list of all elements with the tag <button>, use querySelectorAll('button') To get a list of all text elements, use querySelectorAll('input[type="text"]') and all sorts of combinations of selectors; for example, querySelectorAll('#btns .backgr') will get a list of all elements with the backgr class that are inside a tag with the id value btns These functions are defined on the document object of the web page, so in code you will also see document.querySelector() and document.querySelectorAll(). Changing the attributes of elements All objects of the Element class have properties in common, such as classes, hidden, id, innerHtml, style, text, and title; specialized subclasses have additional properties, such as value for a ProgressElement method. Changing the value of a property in an element makes the browser re-render the page to show the changed user interface. Experiment with todo_v2.dart: import 'dart:html'; InputElement task; UListElement list; Element header; List<ButtonElement> btns; main() { task = querySelector('#task'); list = querySelector('#list'); task.onChange.listen( (e) => addItem() ); // find the h2 header element: header = querySelector('.header'); (1) // find the buttons: btns = querySelectorAll('button'); (2) // attach event handler to 1st and 2nd buttons: btns[0].onClick.listen( (e) => changeColorHeader() ); (3) btns[1].onDoubleClick.listen( (e) => changeTextPara() ); (4) // another way to get the same buttons with class backgr: var btns2 = querySelectorAll('#btns .backgr'); (5) btns2[2].onMouseOver.listen( (e) => changePlaceHolder() );(6) btns2[2].onClick.listen((e) => changeBtnsBackColor() ); (7) addElements(); } changeColorHeader() => header.classes.toggle('header2'); (8) changeTextPara() => querySelector('#para').text = "You changed my text!"; (9) changePlaceHolder() => task.placeholder = 'Come on, type something in!'; (10) changeBtnsBackColor() => btns.forEach( (b) => b.classes.add('btns_backgr')); (11) void addItem() { var newTask = new LIElement(); (12) newTask.text = task.value; (13) newTask.onClick.listen( (e) => newTask.remove()); task.value = ''; list.children.add(newTask); (14) } addElements() { var ch1 = new CheckboxInputElement(); (15) ch1.checked = true; document.body.children.add(ch1); (16) var par = new Element.tag('p'); (17) par.text = 'I am a newly created paragraph!'; document.body.children.add(par); var el = new Element.html('<div><h4><b>A small divsection</b></h4></div>'); (18) document.body.children.add(el); var btn = new ButtonElement(); btn.text = 'Replace'; btn.onClick.listen(replacePar); document.body.children.add(btn); var btn2 = new ButtonElement(); btn2.text = 'Delete all list items'; btn2.onClick.listen( (e) => list.children.clear() ); (19) document.body.children.add(btn2); } replacePar(Event e) { var el2 = new Element.html('<div><h4><b>I replaced this div!</b></h4></div>'); el.replaceWith(el2); (20) } Comments for the numbered lines are as follows: We find the <h2> element via its class. We get a list of all the buttons via their tags. We attach an event handler to the Click event of the first button, which toggles the class of the <h2> element, changing its background color at each click (line (8)). We attach an event handler to the DoubleClick event of the second button, which changes the text in the <p> element (line (9)). We get the same list of buttons via a combination of CSS selectors. We attach an event handler to the MouseOver event of the third button, which changes the placeholder in the input field (line (10)). We attach a second event handler to the third button; clicking on it changes the background color of all buttons by adding a new CSS class to their classes collection (line (11)). Every HTML element also has an attribute Map where the keys are the attribute names; you can use this Map to change an attribute, for example: btn.attributes['disabled'] = 'true'; Please refer to the following document to see which attributes apply to which element: https://developer.mozilla.org/en-US/docs/HTML/Attributes Creating and removing elements The structure of a web page is represented as a tree of nodes in the Document Object Model (DOM). A web page can start its life with an initial DOM tree, marked up in its HTML file, and then the tree can be changed using code; or, it can start off with an empty tree, which is then entirely created using code in the app, that is every element is created through a constructor and its properties are set in code. Elements are subclasses of Node; they take up a rectangular space on the web page (with a width and height). They have, at most, one parent Element in which they are enclosed and can contain a list of Elements—their children (you can check this with the function hasChildNodes() that returns a bool function). Furthermore, they can receive events. Elements must first be created before they can be added to the list of a parent element. Elements can also be removed from a node. When elements are added or removed, the DOM tree is changed and the browser has to re-render the web page. An Element object is either bound to an existing node with the querySelector method of the document object or it can be created with its specific constructor, such as that in line (12) (where newTask belongs to the class LIElement—List Item element) or line (15). If useful, we could also specify the id in the code, such as in newTask.id = 'newTask'; If you need a DOM element in different places in your code, you can improve the performance of your app by querying it only once, binding it to a variable, and then working with that variable. After being created, the element properties can be given a value such as that in line (13). Then, the object (let's name it elem) is added to an existing node, for example, to the body node with document.body.children.add(elem), as in line (16), or to an existing node, as list in line (14). Elements can also be created with two named constructors from the Element class: Like Element.tag('tagName') in line (17), where tagName is any valid HTML tag, such as <p>, <div>, <input>, <select>, and so on. Like Element.html('htmlSnippet') in line (18), where htmlSnippet is any valid combination of HTML tags. Use the first constructor if you want to create everything dynamically at runtime; use the second constructor when you know what the HTML for that element will be like and you won't need to reference its child elements in your code (but by using the querySelector method, you can always find them if needed). You can leave the type of the created object open using var, or use the type Element, or use the specific class name (such as InputElement)—use the latter if you want your IDE to give you more specific code completion and warnings/errors against the possible misuse of types. When hovering over a list item, the item changes color and the cursor becomes a hand icon; this could be done in code (try it), but it is easier to do in the CSS file: #list li:hover { color: aqua; font-size:20 px; font-weight: bold; cursor: pointer; } To delete an Element elem from the DOM tree, use elem.remove(). We can delete list items by clicking on them, which is coded with only one line: newTask.onClick.listen( (e) => newTask.remove() ); To remove all the list items, use the List function clear(), such as in line (19). Replace elem with another element elem2 using elem.replaceWith(elem2), such as in line (20). Handling events When the user interacts with the web form, such as when clicking on a button or filling in a text field, an event fires; any element on the page can have events. The DOM contains hooks for these events and the developer can write code (an event handler) that the browser must execute when the event fires. How do we add an event handler to an element (which is also called registering an event handler)?. The general format is: element.onEvent.listen( event_handler ) (The spaces are not needed, but can be used to make the code more readable). Examples of events are Click, Change, Focus, Drag, MouseDown, Load, KeyUp, and so on. View this as the browser listening to events on elements and, when they occur, executing the indicated event handler. The argument that is passed to the listen() method is a callback function and has to be of the type EventListener; it has the signature: void EventListener(Event e) The event handler gets passed an Event parameter, succinctly called e or ev, that contains more specific info on the event, such as which mouse button should be pressed in case of a mouse event, on which object the event took place using e.target, and so on. If an event is not handled on the target object itself, you can still write the event handler in its parent, or its parent's parent, and so on up the DOM tree, where it will also get executed; in such a situation, the target property can be useful in determining the original event object. In todo_v2.dart, we examine the various event-coding styles. Using the general format, the Click event on btns2[2] can be handled using the following code: btns2[2].onClick.listen( changeBtnsBackColor ); where changeBtnsBackColor is either the event handler or callback function. This function is written as: changeBtnsBackColor(Event e) => btns.forEach( (b) => b.classes.add('btns_backgr')); Another, shorter way to write this (such as in line (7)) is: btns2[2].onClick.listen( (e) => changeBtnsBackColor() ); changeBtnsBackColor() => btns.forEach( (b) => b.classes.add('btns_backgr')); When a Click event occurs on btns2[2], the handler changeBtnsBackColor is called. In case the event handler needs more code lines, use the brace syntax as follows: changeBtnsBackColor(Event e) { btns.forEach( (b) => b.classes.add('btns_backgr')); // possibly other code } Familiarize yourself with these different ways of writing event handlers. Of course, when the handler needs only one line of code, there is no need for a separate method, as in the following code: newTask.onClick.listen( (e) => newTask.remove() ); For clarity, we use the function expression syntax => whenever possible, but you can inline the event handler and use the brace syntax along with an anonymous function, thus avoiding a separate method. So instead of executing the following code: task.onChange.listen( (e) => addItem() ); we could have executed: task.onChange.listen( (e) { var newTask = new LIElement(); newTask.text = task.value; newTask.onClick.listen( (e) => newTask.remove()); task.value = ''; list.children.add(newTask); } ); JavaScript developers will find the preceding code very familiar, but it is also used frequently in Dart code, so make yourself acquainted with the code pattern ( (e) {...} );. The following is an example of how you can respond to key events (in this case, on the window object) using the keyCode and ctrlKey properties of the event e: window.onKeyPress .listen( (e) { if (e.keyCode == KeyCode.ENTER) { window.alert("You pressed ENTER"); } if (e.ctrlKey && e.keyCode == CTRL_ENTER) { window.alert("You pressed CTRL + ENTER"); } }); In this code, the constant const int CTRL_ENTER = 10; is used. (The list of keyCodes can be found at http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes). Manipulating the style of page elements CSS style properties can be changed in the code as well: every element elem has a classes property, which is a set of CSS classes. You can add a CSS class as follows: elem.classes.add ('cssclass'); as we did in changeBtnsBackColor (line (11)); by adding this class, the new style is immediately applied to the element. Or, we can remove it to take away the style: elem.classes.remove ('cssclass'); The toggle method (line (8)) elem.classes.toggle('cssclass'); is a combination of both: first the cssclass is applied (added), the next time it is removed, and, the time after that, it is applied again, and so on. Working with CSS classes is the best way to change the style, because the CSS definition is separated from the HTML markup. If you do want to change the style of an element directly, use its style property elem.style, where the cascade style of coding is very appropriate, for example: newTask.style ..fontWeight = 'bold' ..fontSize = '3em' ..color = 'red';
Read more
  • 0
  • 0
  • 5445

article-image-creating-convincing-images-blender-internal-renderer-part1
Packt
20 Oct 2009
9 min read
Save for later

Creating Convincing Images with Blender Internal Renderer-part1

Packt
20 Oct 2009
9 min read
Throughout the years that have passed since the emergence of Computer Graphics, many aspiring artists tried convincingly to recreate the real world through works of applied art, some of which include oil painting, charcoal painting, matte painting, and even the most basic ones like pastel and/or crayon drawings has already made it through the artistic universe of realism. Albeit the fact that recreating the real world is like reinventing the wheel (which some artists might argue with), it is not an easy task to involve yourself into. It takes a lot of practice, perseverance, and personality to make it through.  But one lesson I have learned from the art world is to consciously and subconsciously observe the world around you. Pay attention to details. Observe how a plant behaves at different environmental conditions, look how a paper's texture is changed when wet, or probably observe how water in a river distorts the underlying objects. These are just some of the things that you can observe around you, and there are a million more or even an infinite number of things you can observe in your lifetime. In the advent of 3D as part of the numerous studies involved in Computer Graphics, a lot of effort has been made into developing tools and applications that emulate real-world environment.  It has become an unstated norm that the more realistic looking an image is, the greater the impact it has on viewers.  That, in turn, is partly true, but the real essence into creating stunning images is to know how it would look beautiful amidst the criteria that are present.  It is not a general requirement that all your images must look hyper realistic, you just have to know and judge how it would look good, after all that's what CG is all about.  And believe it or not, cheating the eye is an essential tool of the trade. In 3D rendering context, there are a number of ways on how to achieve realism in your scenes, but intuitively, the use of external renderers and advanced raytracers does help a lot in the setup and makes the creation process a bit lighter as compared to manually setting up lights, shaders, etc.  But that comes at a rendering time tradeoff.  Unfortunately though, I won't be taking you to the steps on how to setup your scenes for use in external renderers, but instead I'll walk you through the steps on how to achieve slightly similar effects as to that of externals with the use of the native renderer or the internal renderer as some might call it. Hopefully in this short article, I can describe to you numerous ways on how to achieve good-looking and realistic images with some nifty tools, workarounds from within Blender and use the Blender Internal Renderer to achieve these effects. So, let's all get a cup of tea, a comfortable couch, and hop in! On a nutshell, what makes an image look real? Shading, Materials, Shadows, Textures, Transparency, Reflection, Refraction, Highlights, Contrast, Color Balance, DoF, Lens Effects, Geometry (bevels), Subtlety, Environment, Staging, Composite Nodes, Story.. Before Anything Else... Beyond anything that will be discussed here, nothing beats a properly planned and well-imagined scene.  I cannot stress enough how important it is to begin everything with deep and careful planning.  Be it just a ball on a table or a flying scaled bear with a head of a tarsier and legs that of a mouse (?), it is very vital to plan beforehand.  Believe me, once you've planned everything right, you're almost done with your work (which I didn't believe then until I did give it a try).  And of course, with your touch of artistic flavors, a simple scene could just be the grandest one that history has ever seen. This article, by any means, does not technically teach you how to model subjects for your scene nor does it detail the concepts behind lighting (which is an article on its own and probably beyond my knowledge) nor does it teach you “the way” to do things but instead it will lead you through a process by which you will be able to understand your scene better and the concepts behind. I would also be leading you through a series of steps using the same scene we've setup from the beginning and hopefully by the end of the day, we could achieve something that comprises what has been discussed here so far. I have blabbered too much already, haven't I? Yeah.  Ok, on to the real thing. Before you begin the proceeding steps, it is a must (it really really is) to go grab your copy of Blender over at http://www.blender.org/download/get-blender/. The version I used for this tutorial is 2.49a (which should be the latest one being offered at Blender.org [as of this writing]). Scene Setup With every historical and memorable piece, it is a vital part of your 3d journey to setup something on your scene.  I couldn't imagine how a 3D artist could pass on a work with a blank animated scene, hyper minimal I might say. To start off, fire up Blender or your favorite 3D App for that matter and get your scene ready with your models, objects, subjects, or whatever you call them, just get them there inside your scene so we could have something to look at for now, won't we? On the image below (finally, a graphic one!), you could see a sample scene I've setup and a quick render of the said scene. The first image shows my scene with the model, two spheres, a plane, a lamp, and a camera. The second image shows the rendered version.   You'll notice that the image looks dull and lifeless, that is because it lacks the proper visual elements necessary for creating a convincing scene.  The current setup is all set to default, with the objects having no material data but just the premade ones set by Blender and the light’s settings set as they were by default. Shading and Materials To address some issues, we need to identify first what needs to be corrected.  The first thing we might want to do is to add some initial materials to the objects we have just so we could clearly distinguish their roles in the scene and to add some life to the somewhat dry set we have here.  To do so, select one object at a time and add a material. Let’s first select the main character of the scene (or any subject you wish for that matter) by clicking RMB (Right Mouse Button) on the character object, then under the Buttons Window, select Shading (F5), then click the Material Buttons tab, and click on “Add New” to add a new material to our object. Adding a New Material After doing so, more options will show up and this is where the real fun begins. The only thing we’ll be doing for now is to add some basic color and shading to our objects just so we could deviate from the standard gray default.  You’ll notice on the image below that I’ve edited quite a few options.  That’s what we only want for now, let’s leave the other settings as they are and we’ll get back to it as soon as we need to. Character Initial Material Settings   Big Sphere Initial Material Settings Small sphere Initial Material Settings   Ground Initial Material Settings If we do a test render now, here’s how it will look like: Render With Colors Still not so convincing, but somehow we managed to add a level of variety to our scene as compared to the initial render we’ve made.  Looking at the latest render we did, you’ll notice that the character with the two spheres still seem to be floating in space, creating no interaction whatsoever with the ground plane below it. Another thing would be the lack of diffuse color on some parts of the objects, thus creating a pitch black color which, as in this case, doesn’t seem to look good at all since we’re trying to achieve a well-lit, natural environment as much as possible. A quick and easy solution to this issue would be to enable Ambient Occlusion under the World Settings tab. This will tell Blender to create a fake global illumination effect as though you have added a bunch of lights to create the occlusion.  This would be a case similar to adding a dome of spot lights, with each light having a low energy level, creating a subtle AO effect. But for the purposes of this article, we’d be settling for Ambient Occlusion since it is faster to setup and eliminates the additional need for further tweaking. We access the AO (Ambient Occlusion) menu via the World Buttons tab under Shading (F5) menu then clicking the Amb Occ subtab.  Activate Ambient Occlusion then click on Use Falloff and edit the default strength of 1.00 to 0.70, doing so will create further diffusion on darker areas that have been hidden from the occlusion process.  Next would be to click Pixel Cache, I don’t know much technically what this does but what I know from experience is this speeds up the occlusion calculation.   Ambient Occlusion Settings Below, you’ll see the effects of AO as applied to the scene.  Notice the subtle diffusion of color and shadows and the interaction of the objects and the plane ground through the occlusion process.  So far we’ve only used a single lamp as fill light, but later on we’ll be adding further light sources to create a better effect. Render with Ambient Occlusion Whew, we’ve been doing something lately, haven’t we? So far what we did was to create a scene and a render image that will give us a better view of what it’s going to look like.  Next stop, we’ll be creating a base light setup to further create shadows and better looking diffusion. Soon we go!
Read more
  • 0
  • 0
  • 5440
Modal Close icon
Modal Close icon