Quantcast
Channel: Infragistics Community
Viewing all 2223 articles
Browse latest View live

Infragistics Silverlight Release Notes – December: 13.1, 13.2 Service Releases

$
0
0

Release notes reflect the state of resolved bugs and new additions from the previous release. You will find these notes useful to help determine the resolution of existing issues from a past release and as a means of determining where to test your applications when upgrading from one version to the next.

Release notes are available in both PDF and Excel formats. The PDF summarizes the changes to this release along with a listing of each item. The Excel sheet includes each change item and makes it easy for you to sort, filter and otherwise manipulate the data to your liking.

In order to download release notes, use the following links:

Infragistics Silverlight 2013 Volume 1 Service Release

PDF - Infragistics Silverlight 2013 Volume 1 (Build 13.1.20131.2241)
Excel - Infragistics Silverlight 2013 Volume 1 (Build 13.1.20131.2241)

Infragistics Silverlight 2013 Volume 2 Service Release

PDF - Infragistics Silverlight 2013 Volume 2 (Build 13.2.20132.2041)
Excel - Infragistics Silverlight 2013 Volume 2 (Build 13.2.20132.2041)


Infragistics WPF Release Notes – December: 13.1, 13.2 Service Releases

$
0
0

Release notes reflect the state of resolved bugs and new additions from the previous release. You will find these notes useful to help determine the resolution of existing issues from a past release and as a means of determining where to test your applications when upgrading from one version to the next.

Release notes are available in both PDF and Excel formats. The PDF summarizes the changes to this release along with a listing of each item. The Excel sheet includes each change item and makes it easy for you to sort, filter and otherwise manipulate the data to your liking.

In order to download release notes, use the following links:

Infragistics WPF 2013 Volume 1 Service Release

PDF - Infragistics WPF 2013 Volume 1 (Build 13.1.20131.2256)
Excel - Infragistics WPF 2013 Volume 1 (Build 13.1.20131.2256)

Infragistics WPF 2013 Volume 2 Service Release

PDF - Infragistics WPF 2013 Volume 2 (Build 13.2.20132.2036)
Excel - Infragistics WPF 2013 Volume 2 (Build 13.2.20132.2036)

Infragistics Windows UI Release Notes – December: 13.2 Service Release

$
0
0

Release notes reflect the state of resolved bugs and new additions from the previous release. You will find these notes useful to help determine the resolution of existing issues from a past release and as a means of determining where to test your applications when upgrading from one version to the next.

Release notes are available in both PDF and Excel formats. The PDF summarizes the changes to this release along with a listing of each item. The Excel sheet includes each change item and makes it easy for you to sort, filter and otherwise manipulate the data to your liking.

In order to download release notes, use the following links:

Windows UI 2013 Volume 2 Service Release

PDF - Infragistics Windows UI 2013 Volume 2 (Build 13.2.20132.1043)
Excel - Infragistics Windows UI 2013 Volume 2 (Build 13.2.20132.1043)

5 Great Blogs for UX and UI Inspiration

$
0
0

The great thing about being a UX or UI designer is there are always new challenges to face and new things to learn. The web, and specifically the wide variety of blogs available for consumption, offer a great way to learn new skills, keep up with the latest trends, or simply find inspiration. With that in mind here are 5 great blogs that all UX and UI designers need to know about:

Boxes and Arrows

The Boxes and Arrows site has been around for a long time now, certain in terms of the web. Since 2001 in fact. It features a wide range of well written and researched articles on the topics of graphic design, interaction design and information architecture. Articles are submitted by a range of contributors from across a number of industries. Check out the Boxes and Arrows site when you are looking for serious indepth articles that push forward the practice of UI and UX.

A List Apart

A List Apart is another old school site that has managed to keep relevant and interesting since it first got going in 1997 (initially as a mailing list). The site accepts submissions from writers in a range of professions, and as a result features a wide range of content exploring web design and content. A bit like ‘Boxes and Arrows’ in that it generally focuses on longer form in depth articles, this is a must for any UI or UX designer serious about their profession.

iA

Information Architects is the blog of the company of the same name. The company design and build various web products and services, and got a lot of attention when they launched ‘iA Writer’ for the Mac and iOS. The style of the blog tells you everything you need to know about their ethos (it is very sparse indeed) but it also includes a ton of useful material and design and user experience.

Little Big Details

We covered UI pattern websites in a previous post. Little Big Details isn’t quite one of those, but it does include a wealth of useful screenshots and snippets of user design goodness. What is especially nice about this site is the stripped back commentary, the team simple let the UI do the talking..

The Nielsen Norman Group

Whilst the principles expressed over the years by Jakob Nielsen and Don Norman don’t always meet with universal acclaim, most UX and UI designers would admit they have both had a huge influence on their field in the last 10-20 years. The Nielsen Norman Group blog features a ton of articles covering everything from tablet usability, to the use of the web by senior citizens.

Navigation in the modern web. In-page navigation and state management with Ignite UI.

$
0
0

After reading this blog, you will be able to integrate the Ignite UI igGrid control with history.js, a popular library for browser history manipulation and navigation. This will allow you to navigate through igGrid states and to directly access a certain state. With the following configuration, the igGrid control will be adapted to respond to the needs of the modern browsers’ history navigation. At the same time, using the rich event set of the Ignite UI controls, you will be able to use the same configuration and integration with the rest of the Ignite UI widgets. Firstly I will provide some background on the functionality the browsers provide for page navigations and possible issues you may experience. 

HTML5 History and Navigation

Building a web site, where a site entity or a site resource is identified with individual address in the address bar, is not something new, but with HTML5 and SPA applications on track, the methods for achieving this have changed. The HTML5 Session history and navigation functionality proposes new API and flexibility, and of course some new challenges that need to be addressed.

Instead of rendering a new page on each user navigation action, the websites today, are making asynchronous requests to load the desired content within the same page the user has already loaded – data transfer is smaller, performance is better and the overall user experience is more complete. In a Single Page Application (SPA), when the asynchronous request is made, everything happens “behind the scenes”, and most of the time the user will not even notice that a request to the server has been made. If we don’t manipulate the browser URL, then it also will stay the same, even after our users perform some navigation. For example if you open a page and after that you have several asynchronous requests for data initiated by user actions, then when the user presses the back button they will leave the page, because the browser has remembered only the state when the page has been loaded, and the previous browser state is the previous page. This means that the back and forward buttons are useless in our application and the only entrance to the page will be the home page. The solution for this is to use the HTML5 Session history and navigation functionality. Its API provides functionality that allows you to manually add entities (some object representation of a current state) to the browser history and in addition to change the page URL and title without the need of request to the server. This will allow the developer of a SPA or any asynchronous application to have navigation and identification of the application’s resources and states.

Following the HTML5 specifications, the usage of browser history API seems pretty straightforward:

  • window.history– the browser history object that holds all the functionality.
  • go(), back(), forward()– methods that allows to navigate through the browser history (available in the HTML4)
  • popstate– event that is fired, when navigation in the browser happens (when back or forward buttons are pressed)
  • pushState(), replaceState() – methods that allows you to add new or replace existing state in the browser history stack.
  • state– get current state
  • length– get length of the browser history stack

Before explaining the browser history workflow, I want to point out the pushState() method and its parameters, because it’s “the man” that do most of the work. The following pictures depicts what the results will be when the pushState() method is executed:

JavaScript
  1. history.pushState({ page: 2 }, "Page 2", "?page=2");

As you see the URL and the title of the page are new and the achieved result is the same as loading a new page, even though it’s only JavaScript executed on the client. Below is a more detailed description of the method parameters:

  • State object– a representation of the current state. In our case it’s an object with one property “page” – { page: 1 }. Here you can save all the parameters that will help you to describe and recognize the current state. Note that later, when the browser is back at that state of the history, you will be able to get it using history.state.
  • Title - the new page title that appears on the page tab.
  • URL– the suffix that is added to the URL, after the domain name. This URL is the identifier of the current state/page. In this tutorial we are using the old query approach, with the parameters encoded in the URL. This may not be the best approach, but is good for easily presenting and distinguishing the several states in the URL.

Let’s imagine that user loads the initial page of your SPA by typing in the address bar of the browser. A full request is made, the page is loaded and the page state information is added to the browser history stack – all that is performed by the browser. Then the user clicks an item on the page, asynchronous request is made and some new content is loaded. Now comes the place where you can use the pushState() method. You decide, what the appropriate representation that describes the currents state would be, you give the page new title and URL and you add it to the browser history stack. What you have as a result is a “fake new page load” – the page content, title and URL have changed, but the request itself is asynchronous – faster and lighter. Your new page state is identified in the web and added to the browser history. It can be saved to browser favorites and the URL link can be sent. In addition the page will be easily indexed by the search engines.

What can eat your time, in some of the cases, is to assemble a more complicated URL. If you want to encode a lot information in the URL, then you will need some more logic to create that. Note that pushState() method will work also if you don’t have URL as a parameter. In this case you will be able to navigate back and forward in the browser, but page will not be identified with its own URL, which means it cannot be directly accessed from the browser.

What happens when the back button is pressed? Then the browser returns the previous page URL and title, and fires the popstate event. What you need to do is to attach to that event and inside the handler to try to recover the previous page content. This can happen by using the information of the current state (taken from history.state property), that you previously saved with pushState() in the state object. Let’s put some overview and see if this is enough to start using the browser history navigation functionality.

Third-party Browser History Libraries and history.js

As I already said, navigating in a web page and identifying its resources is a straightforward task using HTML5. But what about the old browsers that don’t support HTML5? This appears to be a problem. Following the official Mozilla document: Chrome 18+, Firefox 4.0+, IE 10+, Opera 11.5+, Safari 6.0 are the browser that support history functionality. This means that we should search for some third-party library that will provide us with backward compatibility and will help us to create navigation in SPA even in the old browsers that don’t support HTML5 features.

What I can add as another alert is that inside the history object, we have access only to the current state – it is not possible to take the state at two or three steps behind. We will need this functionality if our application support more complex navigation. In addition to that we need to distinguish if the back or forward button is pressed. These concerns, along with the backward computability integration, are the most important that needs to be taken into account, when we decide to choose a third-party library. We decided to choose history.js for couple of reasons – it is available for both pure JavaScript and jQuery (this fits the Ignite UI needs) as well as other popular libraries like Dojo, ExtJS, MooTools; it’s API is almost the same as the native browser API for the history – the history object is replaced with History and there are several additional methods; following the commitment in GitHub, there are recent commits and it’s community managed. Here is a broader list of popular libraries:

  • history.js
  • HTML5 History API
  • jQuery BBQ
  • Sammy.JS
  • YUI 2 - integrated
  • Angular.js - integrated

I want to note that some of the libraries are especially made for navigation and routing – history.js, HTML5 History API, jQuery BBQ or Sammy.js. On other hand most of the SPA frameworks, like Angular.js, have their own navigation or routing and if you want to start your application from scratch then these are most probably the better choice for you. But if you have already implemented most of the page, then using history.js can be better choice. And if you are still asking yourself “Which framework should I choose?” – I can answer you – “It depends”. Maybe the right choice in 10 years will be only one – choose the native browser history API, but now it really depends on your needs. For example there is a problem with jQuery BBQ and jQuery 1.10, which I’m sure will be fixed, but if you’re using jQuery 1.10 in your application then BBQ is probably not the best choice for you. When you look at the commits in the GitHub for history.js and BBQ, you will see recent commits for the one and not so recent for the other. Another thing that I think is a history.js plus, is that the main idea behind it is that it “fakes” the HTML5 history navigation feature, while jQuery BBQ and Sammy.js use the hash technique and use the “hashchange” event. The history.js library is really closer to the native browser behavior, with the following differences:

  • History is the main object (history, with small “s”, is the native one).
  • statechange event fires instead of popstate.
  • statechange fires also when a new element is added using pushState() state. In native API, popstate is fired only when back or forward button is pressed.
  • new methods for accessing all the saved history states - savedStates.
  • instead of moving the reference back/forward in the stack, a new element is pushed on the stack every time the back or forward button is pressed.

Next I will show how to recover the state of the igGrid. I will show you how to add the current igGrid paging state to the browser history and then how to recover it when the back button is pressed. In addition we will look at the difference when the forward button is pressed. To achieve complete navigation experience we will parse a given URL and will “read” a current igGrid state and will load it.

Add igGrid State to Browser History

I will skip the igGrid initialization part. If you want to get familiar with that subject, you can take look at the sample that I am using as a reference - History.js integration.  Our start point is the pageIndexChanged event, where we can get the information about the current page:

JavaScript
  1. pageIndexChanged: function (e, args) {
  2.     var pageIndex = args.pageIndex + 1,
  3.         state = { key: "page", value: pageIndex };
  4.     pushToBrowserHistory(state, null, "?page=" +  pageIndex));
  5. }

To change a page, the grid either performs an asynchronous request to get the data for the next page (remote paging) or takes the page data from the client (local paging). When the pager is interacted with the pageChaning event is fired, and when the page is changed – pageChanged is fired. We can choose either one of the events, and the only reason for choosing the one with “ed” suffix, is that it ensures that the operation has completed – the current state will be added to the browser history stack, only when it is fully finished. As you see from the code you already changed the title to “Page 2” and the URL to “?page=2”. In the sample and in this topic the parameters are encoded in the URL in a familiar manner – query string.

It’s becomes a bit more complicated when we have several igGrid features we want to push the state of to the history stack with several parameters. For example paging with multiple sorting requires multiple parameters for one state and multiple states for one feature. This is one of the ways to be implemented – we use ampersand as a feature separator, semi-colon as state separatory, and underscore as a parameter delimiter:

?page=2&sort=id_descedning;name_descending

Looking inside the grid events we see that, each event parameters represents some state of the feature. In some of the features, like paging, it’s one parameter – the current page. In features like sorting, there are parameters for the name of the column and for the sorting direction. For some features we may need three or more parameters. It seems that saving the parameters in an array is one good solution.

Recover igGrid State on Browser Navigation

Having the state in the history stack, now we should care to recover the state when the back button is pressed. What we do is to attach to the history.js “statechange” event and inside we recover the grid state by calling the appropriate API method of the current feature.

JavaScript
  1. window.History.Adapter.bind(window, "statechange", function (e, args) {
  2.     state = window.History.getState().data;
  3.     $("#grid1").igGridPaging("pageIndex", value);
  4. }

As you can see from the code, the paging feature exposes a method that allows us to change the page. It accepts the same parameters that were taken from the grid paging event. This shows some advantages of the igGrid design and for every feature we have such a design – event with arguments that represent the current state of the grid feature and corresponding API method that accepts the same parameters as the arguments. But is this enough to recover properly the igGrid state?

Let’s imagine that we change the grid page from 1 to 4. Then the state of 4 will be added to the browser history. Then we sort a grid column and sorting state object will be added to the browser history too. What we will happen if you press the back button? The previous state will return the grid to page 1. But in addition to that we should unsort the column that we previously sorted. The problem however is that we cannot concurrently access the current state and the preceding sorting one – all this information should be already embedded in the current paging state. This is achieved by adding the sort current state, before we add the page current state:

JavaScript
  1. columnSorting: function (e, args) {
  2.     var currState = window.History.getState();
  3.     undoData = { key: "sort", value: [ args.column, args.oldValue ], undo: true };
  4.     currState.data.undoData = undoData;
  5.     window.History.replaceState(currState.data);
  6. }

Because the columnSorting event happens before the columnSorted one, then when we take the current state, it will still be the paging one. In this way we will in addition add the sorting undo state to the paging state, and when we reach a stage when a back button is pressed and we recover the page state, we will have information about the sorting too.  This will happen using the following code:

JavaScript
  1. window.History.Adapter.bind(window, 'statechange', function (e, args) {
  2.     undoState = window.History.getState().data.undoState;
  3.     if(undoState.undo) {
  4.         $("#grid1").igGridSorting("unsortColumn", column);
  5.     }
  6. }

This is the way we handle more complex cases with multiple features integrated with each other. Of course this logic is needed, because we are trying to recover different states, when navigation happens, by using information from browser history stack. There is another option – when the back or forward button is pressed, to parse the URL and load the grid state from scratch. But this approach is not recommended and can create performance issues, due to the fact that we will call several grid methods which will likely re-render the igGrid several times.

Till now we talked only about the back button, but the same functionality is valid when the forward button is pressed. For security reasons, there is no way to distinguish the two in any browser. This means that the same logic will be done either on back or forward action. This may create some overhead, because when the forward button is pressed, even we have undoState we don’t need to recover it. This is the main difference from clicking the back button. So we should either leave it executed twice or search for alternative way. Such solution can be to check if this functionality is already implemented and step over it.

Loading igGrid State from URL Data

Of course we can add more details on the way the gird state is recovered, but these are the most important things that needs to be taken into account. One last thing that is left to be done is to try to load the grid state directly from the URL. Even though we cover this at the end, this is supposed to happen after the grid initialization. Imagine that you are receiving a URL that contains some encoded state, but at that stage you don’t have a state in the history stack. What you can do is to parse that URL, get the current state and using the grid API to recover that state. It is similar implementation to the one that is executed when the grid state is recovered in the statechage event, with the only difference that the state is taken from the URL instead of the browser history stack.

Summary

Let’s summarize the steps to implement browser history navigation with the igGrid control:

  1. Include history.js script.
  2. Configure the igGrid to meet the needs of your scenario.
  3. Ensure to load the initial state of the grid, by preliminary parsing the URL.
  4. Inside the –ing event handler save the current undo state, if this is necessary.
  5. Inside the –ed event handler, push the state to the browser history stack – current state, page title, page URL.
  6. Attach to the history.js statechange event and inside the handler, recover the grid state.

You can see all those steps implemented in the igGrid History.js integration sample. In this sample several grid features are enabled and you can see how it’s implemented – how the URL is formed, how undo and previous states are created, which grid methods are used for recovering the control state.

Have fun using the history.js framework and the Ignite UI toolbox.

Special thanks to Konstantin Dinev, who helped me with editing and constructing the blog.

Resources

Session history and navigation specification

History.js on GitHub

Manipulating the browser history - MDN

Manipulating History for fun & profit

Ignite UI History.js integration

Column Fixing in Ignite UI jQuery Grid

$
0
0

The Ignite UI Grid control is jQuery based client-side grid that provides the ability to represent and manipulate data in tabular form. It supports many features like Paging, Column Resizing,Column Moving, Column Hiding, Sorting, Updating, Column Fixing and etc. Thanks to those features the end user can rearrange the table in a way suitable for their needs. The function we will take a look at in the current blog will be Column Fixing. It allows you to fix particular columns, so that they won’t get out of the user view while he is scrolling horizontally through the unfixed columns.

 

Getting started

To create a basic Grid with column fixing function you should set the width of the Grid.  When you activate this feature, the fixed and unfixed columns will be marked with a pin icon at their right corner or if you are using more features of the grid, the feature chooser will appear and you will find the icon listed among the other functions.

Column Fixing pin icon

Column Fixing supports properties which help you configure the grid. For example you can choose where to position the fixed columns using the fixingDirection property. By default they are positioned on the left side of the grid. When you choose to use the column fixing feature the grid will be separated in two parts by a thick line. On the one side you will have the stationary fixed columns and on the other side you will have the non-fixed area, containing a scrollbar, which allows you to scroll vertically through the unfixed columns. The Fixed and unfixed columns are represented by two different table DOM elements. When you are configuring the column settings, you can make a column fixed by using the isFixed option and setting it to true. You can also disable a column from being fixed with the allowFixing property. You just have to assign it a “false” value. You can choose what is the width of the non-fixed column area and that way you will be able to fix columns until you reach the width required for the non-fixed area. This can happen if you use the minimalVisibleAreaWidth property.

MVC:

  1. @(Html.Infragistics().Grid(Model)
  2.     .ID("grid")
  3.     .Width("600px")
  4.     .AutoGenerateColumns(false)
  5.     .Caption("Employees")
  6.     .Columns(column =>
  7.     {
  8.         column.For(x => x.firstName).HeaderText("First Name").Width("150px");
  9.         column.For(x => x.lastName).HeaderText("Last Name").Width("150px");
  10.         column.For(x => x.age).HeaderText("Age").Width("150px");
  11.         column.For(x => x.income).HeaderText("Income").Width("150px");
  12.         column.For(x => x.jobPosition).HeaderText("Position").Width("150px");
  13.         column.For(x => x.workExperience).HeaderText("Years of previous Experience").Width("150px");
  14.         column.For(x => x.currentJobExperience).HeaderText("Experience at current position").Width("150px");
  15.  
  16.     })
  17.     .Features(feature =>
  18.     {
  19.         feature.ColumnFixing().ColumnSettings(col =>
  20.         {
  21.             col.ColumnSetting().ColumnKey("Id");
  22.         }).ScrollDelta(100);
  23.         feature.Updating();
  24.         feature.Paging();
  25.     })
  26.     .DataBind()
  27.     .PrimaryKey("Id")    
  28.     .Render()
  29. )

Image:

Grid with column fixing and metro theme

The fixNondataColumns option changes the selectors’ column behavior. By default it is set to true, which means that if you have row selectors they will be fixed while you are scrolling through the columns and if you assign it a false value it will move along with the other columns when scrolling.

Grid with column fixing and eow selectors features

Another way to manipulate the row selectors is with the unfixDataSkippedColumns method. It place the row selectors after the thick line separating the fixed and non-fixed areas.

Unfix data skipped columns method

You can find more information about the properties of the Column Fixing Feature in the API or the documentation.

What is supported

Currently the Column Fixing functionality support integration with most of the igGrid features like Filtering, Multi-column Headers, Paging, Updating, Sorting and other. But there are some exceptions:

Non-Supported features

  • Column Moving
  • Group By
  • Hiding
  • Responsive Web Design Mode
  • Virtualization
  • Unbound Columns

When you use the multi-column header feature , you can fix the whole group of headers together - you can’t pin individual columns from the inner-groups.

Multi-header grid with column fixing

More information about the supported and non-supported features can be found in the documentation.

Tips and Tricks

There are some specifications and particularities that you should take under consideration when you work with this feature of the Grid. As we said the main idea of this function is to allow the user to fix particular columns from the table so that they won’t move when he is scrolling vertically through the other columns. You can fix all of the columns apart from the last visible unfixed one - meaning that if you have ten columns, but the set width for the grid allows you to see only four of them at a time, you will be able to fix three and the remaining space will contain a scrollbar allowing you to scroll through the other unfixed columns. Pay attention that it is important to set a width value to the columns, otherwise they will be represented by percentage and the columns will crush in order to fit the width of the grid. By setting a width to the columns a scrollbar will be visualized and you will be able to view the column in a normal size and scroll vertically through them.

grid with three fixed columns

The children of the Hierarchical Grid are normal Grids that is why they support Column Fixing, but of course all of the restrictions apply to them as well.  If the children of the grid has children of their own, the column fixing feature can be set to the inner-most layout. The example image below demonstrates the usage of the function. You can check out the demo in jsFiddle, which represents the XML Binding sample with added column fixing feature and width for the columns.

Image:

Hierarchical grid with column fixing

Another way of making one column fixed apart from user interaction or configuration is by using the API. You can use the fixColumn method which fixes columns by specified column identifier like column index or key.  The opposite method is unfixColumn. It unfix columns by specified column identifier as column key or index. By using the isFixedColumn method you can see whether a particular column is fixed or not. You can find that property in the Grid’s options list in the API. The method takes as an argument the column’s key. For the implementation of our sample we will use the igCombo control and list the columns’ headers and in addition to the above mentioned methods we will call the columnByText method of the grid, which returns the column by its header text, to create a toggle button for fixing and unfixing columns.

  1. $(document).ready(function () {
  2.     $("#text").igCombo({
  3.         dataSource: $("#grid").igGrid("option", "columns"),
  4.         valueKey: "headerText"
  5.     });
  6.     var key;
  7.     function isFixedColumn() {
  8.         key = $("#grid").igGrid("columnByText", $("#text").igCombo("value")).key;
  9.         return $("#grid").igGrid("isFixedColumn", key);
  10.     }
  11.     $("#check").click(function () {
  12.         if (isFixedColumn() == true) {
  13.             $("#result").text("The column is fixed.")
  14.         }
  15.         else {
  16.             $("#result").text("The column is not fixed.");
  17.         }
  18.  
  19.     });
  20.     $("#fix").click(function () {
  21.         if (isFixedColumn() == false) {
  22.             $("#grid").igGridColumnFixing("fixColumn", key, false);
  23.         }
  24.         else {
  25.             $("#grid").igGridColumnFixing("unfixColumn", key, false);
  26.         }
  27.                
  28.     });
  29. });

 

Conclusion

When you have tabular data it is useful to be able to monitor the information in the different columns, but if the number of the columns is bigger this can become a difficult job. Here comes in handy the column fixing feature, which allows the user to fix particular columns and thus make them stationary while going through the other columns. This function makes it easy for the user to compare and trace the data.

 

You can see a live demo in jsFiddle or download the ASP.NET MVC Grid sample with Column Fixing.

You can follow us on Twitter @Infragistics and stay in touch on Facebook, Google+ and LinkedIn!

Coding in our Backyard – Interview with the Founders of Philly Code Camp

$
0
0

The first Philly Code Camp was hosted 8 years ago, so if you’ve ever wondered how it all got started, check out this interview with the founders, Bill Wolfe and Andy Schwam. PhillyDotNet hosts 2 code camps per year, and Fall 2013 was their 18th code camp! Make sure you go to phillydotnet.org for more information on their next event or how you can get involved in the community.

[youtube] width="560" height="315" src="http://www.youtube.com/embed/j3qZbAxE-XY" [/youtube]

NucliOS Release Notes - November: 13.1.262, 13.2.146 Service Release

$
0
0

Introduction

With every release comes a set of release notes that reflects the state of resolved bugs and new additions from the previous release. You’ll find the notes useful to help determine the resolution of existing issues from a past release and as a means of determining where to test your applications when upgrading from one version to the next.

Release Notes: NucliOS 2013 Volume 1 Build 262 and NucliOS 2013 Volume 2 Build 146

ComponentProduct ImpactDescriptionService Release
AllEnhancement

iOS 64-bit support was added for IG.framework and IGChart.framework.

Note: NucliOS is supported on iOS 6+.

13.2.146
IGChartViewEnhancement

Custom markers feature allowing non-interactive and interactive markers.

Note: The IGChartViewDelegate method for custom markers has changed to:

-(UIView *)chartView:(IGChartView *)chartView viewForMarkerInSeries:(IGSeries *)series withItem:(NSObject *)item index:(NSInteger)index originalSourceItem:(NSObject *)originalSourceItem displayOptions:(IGMarkerDisplayOptions *)options

The marker display options include displayAsImage to designate the marker as non-interactive or as interactive when set to YES, showOriginalMarker that shows the original maker under the custom marker, and bringOriginalMarkerToFront which places the original marker in front of the custom marker.

13.2.146
IGPieChartViewEnhancement

Rotate pie slice to a specified angle programmatically.

Note: Two method were added the IGPieChartView to allow rotating the pie slice to an angle given the slice index or data point.

rotateSliceWithIndex:toAngle:duration:alignment:

rotateSliceWithDataPoint:toAngle:duration:alignment:

13.2.146
IGPieChartViewEnhancement

Exploded slice that extends past pie radius instead of separating from the pie.

Note: A new property was added to the IGPieChartView named explodedDisplayStyle. This property accepts the following enumerations.

IGPieSliceExplodedDisplayStyleExtendRadius - Exploded slices extend past the pie radius.

IGPieSliceExplodedDisplayStyleAwayFromCenter - Default display style, separates slices away from the pie when exploded.

Both enumerations use the explodedRadius property to determine the amount to extend or separate from the pie.

13.2.146
IGChartViewBug Fix

Y-Axis Labels get clipped from rotation.

Note: The clipping is averted by repositioning the label and anchoring the end of the label when the angle is between 90 and 270 degrees. Clipping can still occur for the top and bottom labels at the top/bottom of the label panel. This is currently a limitation of the chart.

13.2.146
IGPieChartViewBug Fix

Labels on the right are truncated.

Note: Fixed pie chart labels to display ellipsis when they collide with slices or go outside of the control's bounds.

13.1.262, 13.2.146
IGPieChartViewBug Fix

ItemTapped method doesn't occur if there is only one slice.

Note: Fixed pie chart with a single slice that did not respond to tap and long press gestures.

13.1.262, 13.2.146
IGChartViewBug Fix

Tooltip support for multi-columns in chart.

Note: Added findSeriesAtPoint:(CGPoint)point method to IGChartView. This will help determine which series to display the tooltip for, in case of multiple series in the chart.

13.1.262, 13.2.146
IGRangeSelectorViewBug Fix

IGRangeSelector does not raise the IGChartView delegate methods for chartViewDidScroll / chartViewDidZoom.

Note: When using the IGRangeSelectorView the following IGChartViewDelegate methods were being suppressed:

-(void)chartViewDidScroll:(IGChartView *)chartView
-(void)chartViewDidZoom:(IGChartView *)chartView

Product changed so that these can be registered and used when using the IGRangeSelectorView.

13.2.146
IGChartViewBug Fix

Very high transient memory usage when displaying IGChartView around CFStrings and CFArray.

Note: Added new property to the datasource helper,  autoGenerateLabels.

The datasource helper will avoid creating labels for each data point when autoGenerateLabels is set to NO and there's no labelsPath or labels array provided. Labels can still be placed on the category axis via the chartView:labelForAxis:withItem: method.

13.1.262, 13.2.146
IGTreemapViewBug Fix

IGTreemapView API documentation does not appear in the docset.

Note: The IGChart framework was updated to ensure that the API documentation for tree map is included in the API docset.

13.2.146

By Torrey Betts


IGGridView : Using a custom datasource helper to swap rows and columns.

$
0
0

Introduction 

We recently had a question in the forums about using the IGGridView to show columns as rows and rows as columns which can be accomplished using a custom IGGridViewDataSourceHelper.

IGGridViewDataSourceHelper Customization


So let's hop right in.  The default datasource helper renders what we could consider a common row / column grid.    But we want the rows and columns to be flipped. 

The first part of that process is overriding the informative information that the datasource helper is going to provide the IGGridViewControl. 

// the number of columns in this case will be the number of rows for a normal grid (since we are flipping the two).
-(NSInteger)numberOfColumnsInGridView:(IGGridView *)gridView
{
  return [super gridView:gridView numberOfRowsInSection:0];
}
// And similarly the number of rows in this case will be the number of columns in a normal grid
-(NSInteger)gridView:(IGGridView *)gridView numberOfRowsInSection:(NSInteger)section
{
return [super numberOfColumnsInGridView:gridView];
}
// Since we are flipping the columns and the rows when we want this method call to flip them for us
-(IGCellPath *)normalizePath:(IGCellPath *)path {
return [IGCellPath pathForRow:path.columnIndex inSection:path.sectionIndex inColumn:path.rowIndex];
}
// And this reverses the change made in normalizePath.
-(IGCellPath *)deNormalizePath:(IGCellPath *)path
{
return [IGCellPath pathForRow:path.columnIndex inSection:path.sectionIndex inColumn:path.rowIndex];
}

The first two methods : numberOfColumnsInGridView:(IGGridView *)gridView and numberOfRowsInSection:(NSInteger)section will tell the IGGridView how many columns and rows will appear. So we reverse the call slightly . For the number of rows we give the expected number of columns, for the number of columns we give the number of rows. The trickiest part in that code is the section number. Sections are groups of data, a group by type feature. Since this example isn't grouping, everything is going to be in section zero.

So the other two methods help map data between the underlying data array and how the cells and rows  were displayed.  In a normal rendering, a single data object is in its own row.  Here we have to accommodate that a data object is now rendering up and down.

So now the datasource helper will tell the view it's row and column layout information.  Pretty easy.

Next we will have the view add a "HeaderRow" and the column headers which will lay out our view area.  

We want to give the view a column full of row headers.  We want that to always be visible.  So we can use a FixedColumn.  

// We will use the fixed left column to hold the column headers now moved to be row headers.  So mark a single column as fixed.

-(NSInteger)numberOfFixedLeftColumnsInGridView:(IGGridView *)gridView

{

    return1;

}

// When the fixed column cells are being rendered, we will want to take control of that process to show the row headers for the row.  We will put the column header text into the cell.

-(IGGridViewCell *)gridView:(IGGridView *)gridView fixedLeftCellAt:(IGCellPath *)path

{

    IGGridViewCell* c = [gridView dequeueReusableCellWithIdentifier:@"fc"];

    if (!c)

    {

        c= [[IGGridViewCellalloc]initWithReuseIdentifier:@"fc"];

    }

    NSString* columnHeader = ((IGGridViewColumnDefinition*) self.columns[path.rowIndex]).headerText;

    c.textLabel.text = columnHeader;

    c.backgroundColor = [UIColorgreenColor];

    return c;

}

Since there is only a single fixed column in this layout, we can hard set the data source helper to return a single fixed column. We then grab the Column.headerText for the column header that will be displayed and render that in our fixed column.

After that, we will render a custom column header cell.  And that code is easy as well.

// We created a custom headerCell to show the image of the person whose data is being displayed.  Override this method to get the data

-(IGGridViewHeaderCell *)gridView:(IGGridView *)gridView headerCellAt:(NSInteger)column

{

    MyCustomHeaderCellWithImageCell* hc = [gridView dequeueReusableCellWithIdentifier:@"hc"];

    if(!hc)

    {

        hc =[[MyCustomHeaderCellWithImageCellalloc]initWithReuseIdentifier:@"hc"];

    }

    // Gets the "real" row of data from the data source

    IGCellPath* path = [IGCellPathpathForRow:0inSection:0inColumn:column];

    path = [selfdeNormalizePath:path];

    

    // then gets the data object

    igSalesmanItem* item = self.data[path.rowIndex];

    

    // and finds the image associated with that data object.

    hc.image = item.image;

    

    return hc;

}

And that's it for the datasource helper. In the sample code we override another method or two, but those are cosmetic. We also define a custom header cell, but that is so we can show and image. We now have a datasource helper that will swap columns and rows. That is the important part.

So how do we use it? Well just like any datasource helper.

- (void)viewDidLoad

{

    [superviewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

    grid = [[IGGridViewalloc]init];

    grid.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;

    grid.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

    grid.columnWidth = [IGColumnWidthCreateWithFixedWidth:150];

    grid.headerHeight = 150;

    [self.viewaddSubview:grid];

    

    helper = [[RowColumnReversedDataSourceHelperalloc]init];

    

    helper.autoGenerateColumns = false;

    

    IGGridViewColumnDefinition *firstNameColumn = [[IGGridViewColumnDefinitionalloc]initWithKey:@"firstName"];

    

    IGGridViewColumnDefinition *lastNameColumn = [[IGGridViewColumnDefinitionalloc]initWithKey:@"lastName"];

    

        IGGridViewColumnDefinition *territoryColumn = [[IGGridViewColumnDefinitionalloc]initWithKey:@"territory"];

    

    IGGridViewColumnDefinition *yearToDateColumn = [[IGGridViewColumnDefinitionalloc]initWithKey:@"yearToDateSales"];

    

    [helper.columnDefinitionsaddObject:firstNameColumn];

    [helper.columnDefinitionsaddObject:lastNameColumn];

    [helper.columnDefinitionsaddObject:territoryColumn];

    [helper.columnDefinitionsaddObject:yearToDateColumn];

    

    

    NSMutableArray* myData = (NSMutableArray*)[igSalesmanItemgenerateData:10];

    helper.data = myData;

    grid.dataSource = helper;

}

We define some column definitions, add them to the DataSourceHelper so we can limit the columns we want, hook it up to some data, and give it to a igGridView to render.

So I hope you enjoyed learning a bit about how to customize your datasource helper and how it can be used to make different UIs for your application.

Attached to this article is a sample showing this datasource helper in action in Objective-C.  

By Darrell Kress

Why Early Usability Testing?

$
0
0

Usability testing is observing how users interact with a technical system, a product or a service in order to learn how this system can be optimized for a better user experience. While usability tests should be run at various phases during a system’s lifecycle, they’re especially valuable in the early stages - before the design is complete and before we do any development. At this point there’s no prototype built in code on the actual target development platform, but that’s OK. Usability tests can be run with paper prototypes showing static screen states. I personally prefer something that is more interactive, like linked PowerPoint slides or Indigo Studio mockups. The goal of this kind of mockup is not to be fully functional and real, but to mimic, to some extent, what the envisioned product would be like. We put as much in the mockup as necessary to make the underlying design tangible for users and as little as possible in order to keep the time and costs low. What we want to discover through the testing are things like:

· Do end users understand what they’re looking at?

· Do they understand the labels we use?

· Do they understand how to find their way around in the product?

· Is it clear what to enter in specific text boxes?

· Does the UI support the tasks sufficiently?

· Is the level of user guidance appropriate?

The mockup is only built to support these types of issues. It’s not meant to be complete, either horizontally (range of features) or vertically (feature depth). It’s also not meant to investigate nuanced things like animations between screen states. It does not have to allow execution of complete work flows. Since the users are instructed to complete certain specific tasks only, it becomes the role of the moderator to steer test participants to those mockup areas we’re most interested in and away from areas that are incomplete.

Would it be great to test a 360 degree view of the whole product? Yes it would, but to accomplish that we’d pretty much have to build the real thing. User acceptance testing would cover that, but only very late in the development process. At this point, when we’re still in the early stages of this process, we need to focus on the most important things. And of course, it’s an option to run further usability tests later, that focus on other areas of interest and that allow more granular interactivity.

What we learn from testing is very valuable for the whole development process. For the first time we get feedback from the only group of persons that is actually qualified to rate the usability of the product under construction –the end users. The usability tests allow us to assess the validity of our concept: we understand what works well and we’re able to pinpoint areas where the usability should be improved. Thus, usability testing is not a waste of time and money. Quite the opposite: it helps save money because we identify issues early and fix them now rather than later, after development, when changes are much more costly. The table below provides some numbers substantiating this claim.

 

Image showing estimates of relative Cost of Rework

Remember: there are a lot of shapes and flavors of usability testing (formative vs. summative, remote vs. onsite, moderated vs. unmoderated, etc.), but the most important thing is to actually do it.

Common Questions About Indigo Studio License & Pricing

$
0
0

Do I need to buy a separate license for the Mac and Windows Version?

No. The license key you purchased will work both for both. You don't have to purchase a separate license for Windows if you bought the mac version, and vice versa.

I split my work across two computers. Can I install on both using my single-user license?

The Indigo Studio license is tied to the user, and not the computer. Install and use Indigo Studio on any computer "you" use. However, if we notice a large number of activations using the same license, we may contact you to verify this behavior.

What is a perpetual license and how is better than a regular license?

An Indigo Studio license enables you as a user to unlock and use all product features beyond the standard 30-day trial period. It is sold to you as a perpetual license. That means the product you buy is yours to keep and use FOREVER!

With the perpetual license, however, you get more! In addition to the product, the license qualifies you for any product updates we ship during that year (could even be a new major version of the product) and a year of free customer support. Updates may include new features, bug fixes or both.  

Let's use the following graphic to understand this licensing model better.

Explaining the perpetual license model

Say for instance, when you purchased the license key, the most current version of Indigo Studio was version 4 (Update 1). With the perpetual license model, you also get free updates all way till version 5 (update X).

Another way to say this is that you will get all updates for the last major version released during your active year of subscription. If you wish to get version 6 of the product, you will have to renew your subscription. Renewing will also extend customer support for an additional year. If you do not renew, the product is still yours, and you can keep using Version 5 (update X) forever. It does not stop working :).

In a nutshell, a perpetual license usually implies what you bought plus more! So don't worry. It's a good thing!

Please note that the version numbers I'm using in this graphic are only to help explain better the concept of our perpetual license. It does not signify the exact number of updates or our roadmap for the product.

Does my license include unlimited free sharing of prototypes on Infragistics Servers?

As stated in the software license agreement, prototypes will be available via its URL for a minimum of 12 months from the date of posting on Infragistics Servers. You can read our most up-to-date license agreement here. Prototype hosting is discussed in more detail under section III.A.

How long will I be able to receive product updates and what does that include?

We have tried to explain this under the question "What is a Perpetual License".

Are there any discounts available for for academic/educational use?

We are delighted that you wish to use Indigo Studio in the classroom! While we currently don't have formal academic pricing or an educational license, we can work out something with you. Every institution is a bit different in terms of how software is made available. Just get in touch with us and let us know what you plan to do with Indigo Studio. Send your inquiries to indigo@infragistics.com

Can I get a discount if I buy more than a certain number of licenses?

Do get in touch with our Sales team, and they will be able to answer questions related to bulk discounts. Contact Sales

How do I convert from a trial version to a full version of the product?

To convert, you will first need to purchase a license key from the product website http://www.infragistics.com/products/indigo-studio.

With key in hand, launch Indigo Studio, and look for the "Convert to Licensed Version" option in main menu. Paste in the key, and activate! If your trial has expired, you will see a way to enter the key on the product launch screen.

Entering your product Key

We encourage you to register this key with us so that you can retrieve/manage your key at any time.

Can I still download Indigo Lite, the free version?

That depends on whether you had downloaded version 1 in the past. Indigo Lite is available for re-download for those users upon request. Send us an email at Indigo@Infragistics.com.

Save Time and Build Higher Quality Products with Infragistics Test Automation

$
0
0

Testing takes time. But, with Infragistics Test Automation, it doesn’t have to!

As a developer, you create stunning applications every day. And if you’re already using HP’s Unified Functional Testing software (UFT) or IBM’s Rational Functional Tester (RFT) then you only need Infragistics Test Automation to complete your toolset.

With Test Automation, you can record your WPF or Windows Forms application’s user experience and play it back after you modify your app.

To make things even easier, we’ve created a set of how-to videos for you to follow along with, no matter what tool you use!

If you use IBM Rational Functional Tester, check out our getting started video here:

Or, to test Windows Forms applications using HP UFT, take a tour of some simple first steps here:

And if you’re testing WPF applications with HP UFT, see how easy it is to get started here:

Why Use Infragistics Test Automation?

  • Gain better coverage and a higher quality product through test automation.
  • Reduce your costs with an automated testing process that requires less manual testing.
  • Increase productivity by decreasing the time needed for testing your software.

Check out our website to learn more about how Infragistics Test Automation Tools can help you save time, reduce your testing costs, increase your productivity, and build higher-quality apps, faster.


Also be sure to subscribe to our YouTube channel to stay up-to-date with the latest how-to videos and more!

Exclusive Interview: Tim Huckaby

$
0
0

We recently had the opportunity to chat with InterKnowlogy founder, Tim Huckaby about NUI, interaction design, Grandma Huckaby, fly fishing and more. Read on to get inside the mind of “The Pioneer of the Smart Client Revolution”:

OK, so you have been at this for a while – how did you get into this field?

Well, I have some grey hair, so the digital native generation may not understand this, but it is relatively amusing. I went to Crespi Carmelite High School, an all-boys Catholic high school in Encino, CA and graduated in 1980. We didn’t have programming classes or computers; we had Latin and a mandatory full year of typing. And to avoid getting hit with Father Mike’s ruler for slacking, I learned to keep my elbows in and became a machine gun on the keyboard. When you can type faster than you can write, you have a distinct advantage in programming.

It wasn’t until I got to the University of San Diego that I was exposed to programming. At USD you fill out a profiling questionnaire to get your 1st semester freshman classes. Well, they gave me a PASCAL programming class and I fell in love with it. I fully remember something Dr. Dwight Bean taught me way back in September of 1980: “a program is never done; it can always be improved.” And that one statement is still so true today. I ended up taking every programming class that USD offered and talked my way into two programming electives.

I didn’t come from wealth. My parents were English teachers. I worked a lot. I paid my own way through college. You could do that back then. I saved to buy my first Apple II+. I pilfered every compiler I could get my hands on. Back then we didn’t have the internet. We had BBSs. Like many programmers I was fascinated by computer languages. I was fascinated by the software games I could hack into and change for my friend’s amusement.

My first job was at EDS back when Ross Perot still ran the company. By day I wrote COBOL and JCL to allocate resources to the COBOL. By night I worked on the $5,000 IBM XT that EDS had in the office with its 10MB hard drive! It was an awesome computer – way ahead of its time. The first real microcomputer with a hard drive; the first legit PC. That is when I found Turbo Pascal from Borland, an awesome compiler for the PC, and became a Turbo Pascal god [laughs].

Ultimately I found my way to Microsoft. In the late 90’s, I worked with some pretty famous product teams - and some bad ones, too! Did you know Windows NT had 65 million lines of code? I bombed the heap with some code me and my team wrote on the first real webserver from Microsoft (IIS 4.0). It was at Microsoft that l learned the difference between programming and building good software. I worked very hard. 12-14 hour days. My kids were babies and I commuted from San Diego to Seattle, only home for 32 hours each weekend for over a year. It was a huge sacrifice that my wife Kelly and I made, but it launched my career. It was shortly after my time at Microsoft that I stated InterKnowlogy.

Tim Huckaby

Is there any one programming tip or trick you use, regardless of the platform?

“You are not the user”. I say this all the time, especially now that I am so focused on NUI (natural user interface) and interaction design. It means us programmers and technologists don’t represent the user we are building software for. We are the technology elite. If you build software for yourself, the usability for a regular user is typically pretty bad. At InterKnowlogy we have what I call the “Grandma Huckaby test”. It means if Grandma Huckaby can walk up to software we build and become engaged and immediately effective in using it, we have done a good job.

If you could go back in time and rewrite any application out there, what would it be and why?

Well, like I quoted Dr. Bean earlier, “A program is never done.” But, if you truly mean “rewrite”, I can give you two perfect examples of software we were forced to build that we’d rewrite in a heartbeat if we had the chance. Both are InterKnowlogy customers and both applications were built for Fortune 50 companies. And they both basically had the same issue. Simply stated, the problem is this: creative agencies, no matter how big and famous, are just as in the dark as most technologists in terms of touch-enabled applications and the interaction design needed to create a truly engaging application.

So even though we built beautiful wireframes and comps and implemented the user interaction design needed for multi user large screen format touch enabled apps, the big agency came in and basically said, “We’ll take over the design”. And what came back was essentially the design for a web app that runs on an interactive table for multiple users where touch is the only input. We were forced to build it but the usability was awful. Although I cannot use these apps as demos I’m proud of in a typical keynote, I definitely use them in a lessons learned or guidance in NUI design keynote.

What would you consider to be the next big thing in programming?

Well, the next big thing in programming has got to be the bold promise of multi-platform. Unfortunately we had that same bold promise 20 years ago and it never came true. And now the problem is even worse than it was in the browser wars of the late 90’s. Of course the term “next big thing” is relative. Many developers would say the next big thing is Python or F# or HTML5 or the next programming language to be popular. I like to look at it in a more holistic way.

I’d love to live in a world where software architecture was part of the platform and not something you have to code or even think about every time you do a software project. I know that is going to freak out the pure software architects, but really, why do we continue having to deal with it? We should get software architecture for free and be able to focus on the business problems and the design of the application.

I will tell you one thing: the passion in engineers has not changed in 20 years. For some reason, programmers are religious about their tools and programming languages and platforms. If I took the InterKnowlogy engineering team out for beers and asked them what they would consider the next best thing in programming to be, they would be arguing within 5 minutes, shouting after 10 and deep in an all-out bar fight in 30 minutes… all because of programming languages.

You’ve met a lot of interesting people and done a lot of great interviews on Bytes by MSDN! If you were to resurrect that series, who would you want to interview and what would you want to talk about?

Well, as far as I’m concerned Bytes is not dead – I’d love to do it at Build this year! But one thing I always wanted to do on Bytes is have Bill Gates and Steve Ballmer at the same time. We tried. You have no idea how crazy these guys’ schedules are alone. Getting them in the same place outside a MSFT board meeting is almost impossible. But, what a great idea that would be, don’t you think? With Microsoft platform developer share waning and many still upset over the “Silverlight thing”, you could really fix some things and install some confidence with a 5 minute Bytes interview with those two. I haven’t talked to Bill Gates in years, but I can tell you that Steve Ballmer still gets the developers and the Microsoft app platform. And he’s a genuinely great guy. It would be awesome if he could do a Bytes segment at Build before he steps down as CEO.

How would you encourage someone to break out of their coding comfort zone?

I do it all the time. I did it yesterday. One of our very talented young engineers wanted to talk with me about his “career”. I started the conversation with something I have said a thousand times: “Smart engineers are a dime a dozen. Smart engineers that are leaders are rare and extremely valuable. Smart engineers who are leaders that can engage in conversation with a non-technical customer are invaluable.” I call them “walk and talk” engineers. Leads get paid more money; plain and simple. So what do you do to break out of you comfort zone? Study leadership. Study the roles of a developer lead. Tell your company you’d like to work towards leadership in your career path and see where it takes you!

Do you have any interesting hobbies?

Well, I don’t know if it’s interesting, but it is “different”. I’m a fly fisherman. It’s the only place where I can get true focus; it really is my passion. When I’m fly fishing I don’t think about family or work or stress of every day life; it’s just me in the wilderness and the river. And I get lost in it for hours. I have been hardcore, extreme catch and release fly fishing for over a decade. I didn’t grow up doing it, I fell in love with it mid-career. It’s also a pretty rare sport; not too popular. So, not many people know about it or what it entails. It’s very physical. I’ll often cover 20 miles in a day, and lose and gain 2000 feet in altitude. It’s constant action whether you are wading the river casting constantly or hiking or climbing to get to that perfect spot to enter the river. It’s usually in the middle of the wilderness and frequently dangerous. I’m so obsessed by it I even ties flies in my garage. Some of my creations, like the “Huck-Hopper” are even used by the fly fishing guides in Montana. I’m a lot safer now, but some of my earlier years I got into some pretty hairy situations: lost in the wilderness; hiking up a cliff to get out of the canyon in total darkness. My animal encounter stories are epic. I had bears break into my truck just a couple months ago and drink all my beer and eat all my food; not kidding!

To learn more about Tim – and his adventures in programming and in the wilderness – check out http://www.timhuckaby.com/ or visit http://www.interknowlogy.com/TimHuckaby/.

Getting Started Using NucliOS IGCalendarView with Xamarin.iOS

$
0
0

The 13.2 release of NucliOS introduced some new controls for iOS developers. In this post I’m going to focus on the IGCalendarView widget which combines the similar look and feel of the iOS7 calendar with the power and flexibility of Infragistics. This 3 in 1 calendar allows you to navigate between year, month, and day views as well as connect to the events stored on the device. I’ll show you how to use the IGCalendarView with Xamarin.iOS to display the events stored on your iPhone and also show you how to use EventKit to modify events.

nuclios-xamarin-3

Using IGCalendarView with Xamarin.iOS

IGCalendarView is a themeable calendar control that allows you to display both the calendar events on the device as well as custom calendar events you can create in code that do not need to be stored on the device. In this tutorial, we’ll create a single view iPhone application that displays the calendar events that are stored on the device and allow the user to edit them using EventKit. The final application will look like this:

final

Step 1: Creating the project

Start by creating a Single View iPhone application by clicking on “New…” under Solution and configure the project as shown in the following screenshot:

newproject

This will set up a project that uses a single view (i.e. no navigation) which is all we need for this simple sample. A ViewController with a XIB file will be created to represent the view. We won’t need actually customize the XIB file. Since we only need the IGCalendarView, we will add our user interface from code.

Step 2: Adding and configuring the IGCalendarView

The first thing we need to do is add a reference to the IG.dll which is found in /Developer/Infragistics/NucliOS 2013 Volume 2/MonoTouch on your machine. To do this, right-click on References and chose “Edit references…”. Go to the .NET Assembly tab and navigate to the IG.dll as shown here:

references

Now open up the IGCalendarViewXamarinViewController.cs file and add the following using statement:

using Infragistics;  

Add a field for the calendar view:

IGCalendarView _calendar;

Add the following code to the ViewDidLoad override in IGCalendarViewXamarinViewController.cs to initialize an IGCalendarView and add it to the view:

// Create the calendar
_calendar = new IGCalendarView();

// Set the Frame to be the size of the View
_calendar.Frame = this.View.Bounds;

// Set up auto-resizing for rotation purposes
_calendar.AutoresizingMask = UIViewAutoresizing.FlexibleWidth|UIViewAutoresizing.FlexibleHeight;

// Add the calendar to the view
this.View.Add (_calendar);

If you run the application at this point, you should see the following:

statusbar

You probably noticed that the status bar at the top of the screen is overlapping our calendar. This is because of a change in the way the status bar is treated in iOS7. Working around this issue in a way that integrates the status bar is outside of the scope of this tutorial so add the following code to the view controller to hide the status bar:

public override bool PrefersStatusBarHidden ()
{
    return true;
}

You’re free to consider alternative workarounds in your own application.

Step 3: Displaying the device’s calendar events

The calendar is functional as is, but it doesn’t contain any data. Let’s change that by loading up the events from the device. To do this we’ll need to use the EventKit APIs provided by Apple. Xamarin has a very good introduction to EventKit that’s worth reading. Start by adding the following using statements to the top of the view controller file:

using MonoTouch.EventKit;
using MonoTouch.EventKitUI;

We will need a list of NSObjects to manage the data sources for our IGCalendarView so add the following code above the constructor (you’ll need to resolve the reference for System.Collections.Generic as well):

List _dataSources;

Initialize the list in the constructor:

public IGCalendarTestViewController () : base ("IGCalendarTestViewController", null)
{
    _dataSources = new List ();
}

In order to access the calendar objects through EventKit we will need to create an EventStore object that we can access in our app. This object can be expensive to create and teardown so it is recommended that it be created as a long-lived object. This is the perfect scenario for a singleton pattern. Create a new class called App and modify the contents of App.cs to include the following:

using System;
using MonoTouch.EventKit;

namespace IGCalendarViewXamarin
{
    public class App
    {
        public static App Current {
            get { return current; }
        }
        private static App current;

        public EKEventStore EventStore {
            get { return eventStore; }
        }
        protected EKEventStore eventStore;

        static App ()
        {
            current = new App();
        }
        protected App () 
        {
            eventStore = new EKEventStore ( );
        }
    }
}

Now we will be able to access the EventStore at any time in our application by calling App.Current.EventStore.

Next, we need to request permission to access the user’s events. Add the following code just before the calendar view creation code:

var eventStore = App.Current.EventStore;
var accessGranted = await eventStore.RequestAccessAsync(EKEntityType.Event);

Now if we have access we can access the calendars in the event store. For each EKCalendar object we will create an IGCalendarEKDataSourceHelper and add it to our _dataSources array:

if (accessGranted) {
    EKCalendar[] cals = eventStore.GetCalendars (EKEntityType.Event);
    foreach (EKCalendar cal in cals) {
        IGCalendarEKDataSourceHelper ds = new IGCalendarEKDataSourceHelper (cal, App.Current.EventStore);
        _dataSources.Add (ds);
    }
}

Right after the line that sets the AutoresizingMask, add the following line to set the IGCalendarView’s AppointmentDataSources:

_calendar.AppointmentDataSources = _dataSources.ToArray();

Now if you run the code you should be able to see any events that are on the device or simulator. (If you are using the simulator you should launch the Calendar application and add some events to work with in your testing.)

Step 4: Editing an event

Displaying calendar events is great, but what’s even better is responding to taps on those events and allowing the user to edit them! Let’s enable that for our users. To respond to a tap on an event we need to implement a subclass of IGCalendarDelegate and override its AppointmentTapped method. We’ll also pass in an instance of our view controller so that we can present an EKEventEditViewController from within the delegate. To do all of this, add a class called MyCalendarDelegate that extends from IGCalendarViewDelegate. Add the following to the class:

UIViewController _viewController;

public MyCalendarDelegate (UIViewController viewController)
{
    _viewController = viewController;
}

Next, override the AppointmentTapped method and add the following code:

public override void AppointmentTapped (IGCalendarView calView, IGCalendarAppointment appt, IGCalendarAppointmentDataSource dataSource, RectangleF rect, NSDate date)
{
    var ds = dataSource as IGCalendarEKDataSourceHelper;
    var ekEvent = ds.ResolveEventFromAppointment(appt);

    var eventController = new EKEventEditViewController ();
    eventController.EventStore = App.Current.EventStore;
    eventController.Event = ekEvent;
    
    _viewController.PresentViewController (eventController, true, null);
}

This code accesses the EKEvent object for the appointment the user tapped and creates and presents an EKEventEditViewController to display the event. Only thing left to do is handle the event controller’s Completed event and save any edits that the user might have made. Add this code after the “eventController.Event = ekEvent;” line:

eventController.Completed += (sender, e) => {
    switch (e.Action) {
    case EKEventEditViewAction.Canceled:
        break;
    case EKEventEditViewAction.Deleted:
        break;
    case EKEventEditViewAction.Saved:
        NSError err;
        var ev = eventController.Event;

        App.Current.EventStore.SaveEvent (eventController.Event, EKSpan.ThisEvent, out err);

        appt.AllDay = ev.AllDay;
        appt.EndTime = ev.EndDate;
        appt.Location = ev.Location;
        appt.StartTime = ev.StartDate;
        appt.Title = ev.Title;
        break;
    }

    _viewController.UpdateCalendar();
    eventController.DismissViewController(true, null);
};

The key code here is in the case for EKEventEditViewAction.Saved. First we save the event to the EventStore. This updates it in the device calendar. Then we update the IGCalendarView appointment based on the edits to the event. This makes sure the view is in sync with the newly updated calendar appointment.

Back in the IGCalendarViewXamarinViewController’s ViewDidLoad method, set the calendar’s Delegate property:

calendar.Delegate = new MyCalendarDelegate(this);

We also need to add the UpdateCalendar() method to the view controller:

public void UpdateCalendar ()
{
    _calendar.Invalidate ();
}

This causes the calendar to redraw itself to reflect the changes the user made.

And that’s it. The application is ready to go. Run it and you should be able to tap on an event and edit it in the built-in event editor and see the changes reflected on the device.

Summary

This tutorial showed you how to add an IGCalendarView to your iOS application. I also showed you how to use an IGCalendarViewDelegate to handle editing events.

You can download the solution here: IGCalendarViewXamarin.zip

Contact

If you want to comment or reach out to me, the best place to do that is on Twitter @brentschooley. I can also be reached via email at bschooley@infragistics.com.

Infragistics' D3 is Hosting a World IA Day Event at HQ!

$
0
0

I just wanted to take a quick moment to spread the news about an awesome (and free!!) event that D3, the Consulting Services department of Infragistics, will be hosting here at our Cranbury, NJ HQ on February 15th!

World IA Day 2014

Saturday, February 15th, 2014 at the D3 / Infragistics headquarters in NJ.

Please join us and celebrate World IA Day 2014 with the Infragistics team and special guests on February 15, 2014. The annual event, which takes place in cities around the world “brings together the international community of academics, practitioners, technologists, and business leaders for a global conversation about ‘the architecture part’ of information architecture.” Infragistics is pleased to invite you to their ultra-sleek, central NJ-based headquarters for an official World IA Day event that will highlight the roles of UX, interaction design, and development in information architecture.

Remember, it's Free, so Register Now!

 

When:
February 15, 2014 from 12:00-5:00pm ET

Where: 
Infragistics World Headquarters
2 Commerce Way
Cranbury, NJ 08512

 

Centrally located off Exit 8A off the NJ State Turnpike (one hour south of NYC and one hour north of Philadelphia).

Space is limited, so Register Now to reserve your spot!

 

The agenda is still to be announced, but the speakers and content are sure to be top notch! In addition, Lunch, beer and wine will be served on-premises. It is requested that all attendees be at least 18 years old (21 to drink). 


How to get started with Windows UI Radial Menu for WinRT

$
0
0

Header image for xamRadialMenu

The Radial Menu is a circular menu that provides a fast navigation for users. This control is new in the 13.2 release of Windows UI and it is inspired by the Microsoft’s OneNote MX 2013 radial menu. This kinds of menus are very useful and  convenient for touch devices. Although the control is released as CTP it supports a wide range of features and has build in tools like numeric items and gauges, lists, color well and etc. . It’s design and functionalities are similar to those of the OneNote menu, so it is able to operates not only just like it but even it can be further customized based on your needs. In the 13.2 release of Infragistics this controls is build under more than one platforms. It is part of the Windows Forms package as well as WPF and Silverlight. You can read my post about Windows Forms radial menu to learn more about its functionalities.

Overview and features

The radial menu can be separated in three main parts – outer ring, inner area with items and center button. It supports unlimited levels of hierarchy. When you create an item with children  you will have an outer ring button automatically generated above that item. As we said there are few build in tools for this control and we will take a look at some of them. Creating a OneNote like menu means that it should have text edit tools like size, font type, list, font color and other. To start with we will need the Infragistics references. Once you have installed the Infragistics package you will find a list of its controls in the toolbox in Visual Studio. Drag the xamRadialMenu to the designers view an the needed references will be added automatically.

  1. xmlns:Menus="using:Infragistics.Controls.Menus"
  2.       xmlns:local="using:xamRadialMenu"
  1. <Menus:XamRadialMenu Height="300" Width="300"/>

Now that we have our radial menu we can add as many items in it as we need. Pay attention that there is a slight difference in this control compared to the one for Windows Forms. In Win Forms we always have a fixed number of items, while here we have the minWedgeCount property which allows you to specify the  minimum number of items for the entire menu.

If you want to create a numeric item you have to add RadialMenuNumericItem which will act as a button to the numeric gauge. Visually the slice will contain a custom image or header if any and an associated numeric value above them. The child item should be a RadialMenuNumericGauge which will allow to select a numeric value.

  1. <Menus:RadialMenuNumericItem>
  2.     <Menus:RadialMenuNumericItem.Icon>
  3.         <Image Source="Assets/font_size.png" Width="30" Height="30" />
  4.     </Menus:RadialMenuNumericItem.Icon>
  5.     <Menus:RadialMenuNumericGauge
  6.             Value="{Binding ElementName=textBox, Path=FontSize, Mode=TwoWay}"
  7.             Ticks="8 9 10 11 12 13 14 16 18 20 22 24 26 28 36 48 72" />
  8. </Menus:RadialMenuNumericItem>

Radial Menu's numeric item and numeric gauge

When it comes to colors the situation is similar. First you have to add a RadialMenuColorItem which will display custom image and header if any and an associated color. The child items should be RadialMenuColorWell. This item is specialized item that displays associated color in the item area and the outer ring. If you navigate to a child item of a color well item you will see a palette of hues of the selected color. To create the whole palette of colors you need to add a hierarchy of  color well children. The snippet below demonstrates how to do that for the yellow color.

  1. <Menus:RadialMenuColorItem Header="Color" >
  2.     <Menus:RadialMenuColorWell Color="#FFFF00">
  3.         <Menus:RadialMenuColorWell Color="#FFD55F"></Menus:RadialMenuColorWell>
  4.         <Menus:RadialMenuColorWell Color="#FFEB9C"></Menus:RadialMenuColorWell>
  5.         <Menus:RadialMenuColorWell Color="#FFFF00"></Menus:RadialMenuColorWell>
  6.         <Menus:RadialMenuColorWell Color="#AC4D25"></Menus:RadialMenuColorWell>
  7.         <Menus:RadialMenuColorWell Color="#D16227"></Menus:RadialMenuColorWell>
  8.         <Menus:RadialMenuColorWell Color="#EB7C23"></Menus:RadialMenuColorWell>
  9.         <Menus:RadialMenuColorWell Color="#F6901E"></Menus:RadialMenuColorWell>
  10.         <Menus:RadialMenuColorWell Color="#FFC000"></Menus:RadialMenuColorWell>
  11.     </Menus:RadialMenuColorWell>
  12. </Menus:RadialMenuColorItem>

Radial Menu's color well items

Another type of items is the RadialMenuList that represents a list of strings in an appropriate UI list box. We use it to make a fonts type selector.  

  1. <Menus:RadialMenuList Header="Font Type" Name="font">
  2.     <Menus:RadialMenuList.Items>
  3.         <x:String>Arial</x:String>
  4.         <x:String>Calibri</x:String>
  5.         <x:String>Consolas</x:String>
  6.         <x:String>Comic Sans MS</x:String>
  7.         <x:String>Courier New</x:String>
  8.         <x:String>Segoe UI</x:String>
  9.         <x:String>Tahoma</x:String>
  10.         <x:String>Times New Roman</x:String>
  11.         <x:String>Verdana</x:String>
  12.     </Menus:RadialMenuList.Items>
  13. </Menus:RadialMenuList>

Radial Menu list item - fonts

You can also have normal RadialMenuItem slices which wont have a build in functionality but can be customized according to your needs. The radial menu is build in such a way that you can style it as you like. You can change the center button icon, the brushes of the outer ring, the brushes of the inner item area. You can also add images and header text for the items. Another thing that you can control is the rotation of the main gauge. Using the RotationInDegrees property you can specify from which degree should it start to rotate.

This control is optimized for touch but it works as well with mouse and keyboard interaction. It even supports key tips. If you want to see what key tips are active for your menu and use them you should first press the Alt button of your keyboard. Then you will see all of the tips visualized and you can manipulate the menu by using them. By default if the center icon’s key tip is “0”. If you haven’t assigned a header to the items their key tips will be numbers, but if you have headers then the key tips will be the first letter of the header. You can always use the KeyTip property and make your own shortcuts. To dismiss the key tips and enter keyboard navigation mode you can press the escape key or a navigation key.

Radial Menu with key tips

 

Functionality

There is no doubt that the control’s design is attractive and desirable but we should make it functional to become a completed application. As we are making a menu that looks  and acts like the OneNote one, we need to add interaction between the selection of a particular item of the menu and the text that we are going to change. To do that we are going to use the header property of the control to distinguish the different items. Then we will take the selected text and apply a custom function to it. Using this pattern you can make all of the items interactive.

  1. if ((sender asRadialMenuItem).Header.ToString() == "Bold")
  2. {
  3.     ITextCharacterFormat format = this.textBox.Document.Selection.CharacterFormat;
  4.     format.Bold = FormatEffect.Toggle;
  5. }

xamRadialMenu interaction with text

Summary

The main idea behind the radial menu is to be simple and easy to work with. It should present small numbers of items and distribute them in a circular arrangement. It provides fast access to the inner – child items and it is perfect for a touch based applications.  Although it is designed to look and behave like OneNote’s radial menu, you can customize it and make your own creation.

Custom xamRadialMenu

A Win UI xamRadialMenu sample.

 

 

You can follow us on Twitter @Infragistics and stay in touch on Facebook, Google+ and LinkedIn!

Loading GeoJSON geometry into IgniteUI igMap

$
0
0

Introduction

I was asked recently if IgniteUI’s igMap supported the loading of GeoJSON data. The answer is that igMap supports loading geometry from a JavaScript object graph, and GeoJSON, when parsed or executed, also results in a JavaScript object graph, but the map expects the objects to be arranged in a subtly different way than you will receive them from GeoJSON.

The fact that the expectations are subtly different from what GeoJSON provides, though, does not present a difficult problem to surmount. In fact, it’s pretty simple to get things up and running. So, let’s do it!

TL;DR; version:

If you only want to know how to adapt some GeoJSON data for use with the symbol series please see the method flattenFeed below! Articles on how to adapt GeoJSON to fit polyline and shape series to follow.

Getting the Data

For this example, we will load earthquake data from the USGS, since they provide some convenient GeoJSON feeds for examining the locations of recent earthquakes.

The feed I decided to try was for all 4.5 magnitude and above earthquakes in the past month, which is located here: http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_month.geojsonp

We will use jQuery to make a jsonp AJAX call to retrieve this json data and parse it into a JavaScript object graph for our use. To do that we will make this call:

$.ajax({
        url: "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_month.geojsonp",
        dataType: "jsonp",
        jsonpCallback: "eqfeed_callback",
        success: render
    });

Here we are performing the following:

  • Requesting that jQuery make an asynchronous call to retrieve the required GeoJSON feed from the USGS.
    • Note that the url ends with geojsonp, while most of the API doc on USGS will point you at geojson (with no p). The p at the end makes sure that USGS will respond with a result in jsonp format so that the appropriate callback method will be called when the json is loaded. For more details read up on jsonp.
  • Specifying to jQuery that we expect the response type to be jsonp.
  • Specifying what callback function jQuery will need to define in order that the jsonp request can notify us on load.
  • Specifying the callback function that we want called once the jsonp resource has been successfully downloaded and parsed for our use.

We will define this method later.

Creating the igMap

Next, lets create the igMap that will display the GeoJSON data once downloaded:

$("#map").igMap({
        width: "100%",
        height: "90%",
        horizontalZoomable: true,
        verticalZoomable: true,
        windowRectMinWidth: 0.001,
        overviewPlusDetailPaneVisibility: "visible"
    });

Here we are finding the DOM element with id “map” and initializing the igMap component within it with the following options:

  • The map will fill 100% of the width of the container.
  • The map will fill 90% of the height of the container.
  • The map can zoom in both directions.
  • The map currently does not have any series.
  • We are expressing the maximum zoom scale that the map can reach (Open Street Map imagery only goes so deep).
  • We are enabling the navigation pane in the corner of the map.

Note, we are not yet actually specifying any series content for the map. In this case, things are simpler if we wait until we have downloaded the required data, and then load some series content on demand.

Dynamically Adding a Series To igMap

Once the AJAX call has returned and we have our parsed GeoJSON data, we need to create a map series and bind it to that data. In this way we will make it possible to navigate through our data and interact with it. Above, we referred to a method called “render” as the success handler for the AJAX call. Let’s define that method now:

function render(res) {
        res = flattenFeed(res);

        $("#map").igMap("option", "series", [{
            type: "geographicSymbol",
            name: "earthquakes",
            title: "earthquakes",
            markerBrush: "red",
            markerOutline: "black",
            latitudeMemberPath: "latitude",
            longitudeMemberPath: "longitude",
            dataSource: res,
            showTooltip: true,
            tooltipTemplate: "<table><tr><td>Magnitude: </td><td>${item.properties.mag}</td></tr><tr><td>Place: </td><td>${item.properties.place}</td></tr><tr><td>Time: </td><td>${item.dateTimeString}</td></tr></table>"
        }]);
    }

In the above we:

  • Specified that the type of series that we want is the symbol series.
    • This series will place markers at the provided geographic coordinates.
    • We can style and customize these markers to convey other characteristics about the data.
    • We could also load polyline/polygon geometry from GeoJSON into some of the other available series types, but we’ll save that for next time.
  • Call a method that will rearrange certain aspects of the GeoJSON object graph to make it easier to load them into our desired series.
  • Provide a name and title to the series.
  • Set some colors to use for the earthquake markers.
  • Indicated which properties on our data items will contain the latitude and longitude information for the current series.
  • Assigned the data source we have flattened earlier in the method.
  • Assigned a tooltip that will display interesting information about the magnitude and location of the earthquake.

Given this, the only piece we are missing is how we have adapted the GeoJSON object graph to easily load it into the symbol series.

Adapting the GeoJSON Data

The symbol series in the map expects to be able to find two properties on each data item that represent the latitude and longitude position of each point. The GeoJSON format buries this information rather deep in the returned object graph, so one of the steps we will perform is to surface it to an easily discoverable place on each item.

Here is the definition of the flatten feed method:

function flattenFeed(res) {
        var curr;
        res = res.features;
        for (var i = 0; i < res.length; i++) {
            curr = res[i];
            if (curr.geometry && curr.geometry.type == "Point" && curr.geometry.coordinates) {
                curr.latitude = curr.geometry.coordinates[1];
                curr.longitude = curr.geometry.coordinates[0];
            }
            if (curr.properties && curr.properties.time) {
                curr.time = new Date(curr.properties.time);
                curr.dateString = curr.time.toLocaleDateString();
                curr.timeString = curr.time.toLocaleTimeString();
                curr.dateTimeString = curr.dateString + " " + curr.timeString;
            }
        }
        return res;
    }

In the above we:

  • Extract the features collection from the GeoJSON response. This is what holds the data we would like to bind to the series.
  • Check our assumptions to make sure we are being fed GeoJSON style point coordinates, and then copy them to be top level values on each data item.
  • Convert the integer time offsets associated with each earthquake to a readable string to refer to in our tooltips.
  • Return the resulting flattened collection.

Combining all of the above we have the following full code for the sample:

$(function () {
    var data = [];

    function flattenFeed(res) {
        var curr;
        res = res.features;
        console.log(res.length);
        for (var i = 0; i < res.length; i++) {
            curr = res[i];
            if (curr.geometry && curr.geometry.type == "Point" && curr.geometry.coordinates) {
                curr.latitude = curr.geometry.coordinates[1];
                curr.longitude = curr.geometry.coordinates[0];
            }
            if (curr.properties && curr.properties.time) {
                curr.time = new Date(curr.properties.time);
                curr.dateString = curr.time.toLocaleDateString();
                curr.timeString = curr.time.toLocaleTimeString();
                curr.dateTimeString = curr.dateString + " " + curr.timeString;
            }
        }
        data = res;
        return res;
    }

    function render(res) {
        res = flattenFeed(res);

        $("#map").igMap("option", "series", [{
            type: "geographicSymbol",
            name: "earthquakes",
            title: "earthquakes",
            markerBrush: "red",
            markerOutline: "black",
            latitudeMemberPath: "latitude",
            longitudeMemberPath: "longitude",
            dataSource: res,
            showTooltip: true,
            tooltipTemplate: "<table><tr><td>Magnitude: </td><td>${item.properties.mag}</td></tr><tr><td>Place: </td><td>${item.properties.place}</td></tr><tr><td>Time: </td><td>${item.dateTimeString}</td></tr></table>"
        }]);
    }

    $("#map").igMap({
        width: "100%",
        height: "90%",
        horizontalZoomable: true,
        verticalZoomable: true,
        series: [],
        windowRectMinWidth: 0.001,
        overviewPlusDetailPaneVisibility: "visible"
    });


    $.ajax({
        url: "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_month.geojsonp",
        dataType: "jsonp",
        jsonpCallback: "eqfeed_callback",
        success: render
    });


});

Which produces this output:

You can visit the fiddle for this sample here.

Notice that if you hover over the markers, you will get more information about the earthquake in question:

Pretty neat, huh? This is up to date information from USGS that gets refreshed every 15 minutes. We could update our code to re-poll the service periodically and introduce additional points.

Tailoring Our Markers To the Data

Next, why don’t we improve the information slightly that we are conveying with our markers. Wouldn’t it be neat if we could increase the size based on the magnitude? The igMap actually includes a series that makes this very simple for you, but since it is currently in the preview quality band, instead, I will show you how to achieve this by providing a custom marker template for the symbol series.

First, lets track the minimum and maximum magnitude readings we are getting from the GeoJSON service. In this way, we will know how to decide on a size for the markers:

 var data = [], currMinMag, currMaxMag;

    function flattenFeed(res) {
        currMinMag = 100;
        currMaxMag = 0;
        var curr;
        res = res.features;
        console.log(res.length);
        for (var i = 0; i < res.length; i++) {
            curr = res[i];
            if (curr.geometry && curr.geometry.type == "Point" && curr.geometry.coordinates) {
                curr.latitude = curr.geometry.coordinates[1];
                curr.longitude = curr.geometry.coordinates[0];
            }
            if (curr.properties && curr.properties.time) {
                curr.time = new Date(curr.properties.time);
                curr.dateString = curr.time.toLocaleDateString();
                curr.timeString = curr.time.toLocaleTimeString();
                curr.dateTimeString = curr.dateString + " " + curr.timeString;
            }
            if (curr.properties && curr.properties.mag) {
                currMinMag = Math.min(currMinMag, curr.properties.mag);
                currMaxMag = Math.max(currMaxMag, curr.properties.mag);
            }
        }
        data = res;
        return res;
    }

This is a modified version of our flattenFeed function that will read out the magnitude value from each data item, and update the current seen max and min values. We’ll use these values in our custom marker template:

quakeTemplate = {
        measure: function (measureInfo) {
            var propMag = (measureInfo.data.item().properties.mag - currMinMag) / (currMaxMag - currMinMag),
            size = (14 + propMag * 30);
            measureInfo.width = size;
            measureInfo.height = size;
        },
        render: function (renderInfo) {
            var ctx = renderInfo.context,
                propMag = (renderInfo.data.item().properties.mag - currMinMag) / (currMaxMag - currMinMag),
                size = (14 + propMag * 30),
                halfSize = size / 2.0;

            if (renderInfo.isHitTestRender) {
                ctx.fillStyle = renderInfo.data.actualItemBrush().fill();
                ctx.beginPath();
                ctx.arc(renderInfo.xPosition, renderInfo.yPosition, halfSize, 0, 2.0 * Math.PI);
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
            } else {
                ctx.globalAlpha = .3;
                ctx.fillStyle = "rbga(200,34,35,.35)";
                ctx.strokeStyle = "rgba(200,34,35,.89)";
                ctx.beginPath();
                ctx.arc(renderInfo.xPosition, renderInfo.yPosition, halfSize, 0, 2.0 * Math.PI);
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
                ctx.globalAlpha = 1.0;

                ctx.fillStyle = "rgba(111,7,7,.84)";
                ctx.beginPath();
                ctx.arc(renderInfo.xPosition, renderInfo.yPosition, 3.5, 0, 2.0 * Math.PI);
                ctx.closePath();
                ctx.fill();
            }
        }
    };

If you don’t know much about the HTML5 canvas some of the above may seem arcane. Under the covers the map is doing most of its rendering in the canvas, and when you assign a custom marker template you are offering to intercede and render some content into the canvas for a marker based on the parameters that the map specifies to you. In the above we:

  • Respond to the map with a size our marker wants to be, when asked.
    • We calculate this based on where the magnitude of the current quake falls between the min and max value.
  • Respond to the map when our marker needs to be rendered by:
    • Determining the size we want for the marker as above (this could be pulled into a separate method).
    • Rendering a shape that represents the “hit area” of the marker so that the map knows when to display tooltips for the marker, if this is the hit test pass.
      • Note, a very particular color needs to be used when rendering the hit area.
    • Rendering two concentric circles with the outer radius size related to the magnitude.

The final piece is to assign that custom marker template to the series, so we change the series addition to look like this:

$("#map").igMap("option", "series", [{
            type: "geographicSymbol",
            name: "earthquakes",
            title: "earthquakes",
            markerBrush: "red",
            markerOutline: "black",
            markerTemplate: quakeTemplate,
            latitudeMemberPath: "latitude",
            longitudeMemberPath: "longitude",
            dataSource: res,
            showTooltip: true,
            tooltipTemplate: "<table><tr><td>Magnitude: </td><td>${item.properties.mag}</td></tr><tr><td>Place: </td><td>${item.properties.place}</td></tr><tr><td>Time: </td><td>${item.dateTimeString}</td></tr></table>"
        }]);

Put it all together and you get this:

Again, you can go here for the jsfiddle.

Lets Put In More Data!

Below is how we can display a much larger GeoJSON resource from USGS using the high density scatter series, which will use higher heat values to tell you where more quakes have been happening. You’ll see all we’ve really done it to change the series type and to switch to a much larger feed. Please note, that the GeoJSON file involved is actually quite large, so takes a while to download. You’ll see the status change from GeoJSON Downloading to Download Completed when the download has finished.

$(function () {
    var data = [], currMinMag = 0, currMaxMag = 10;

    function flattenFeed(res) {
        currMinMag = 10;
        currMaxMag = 0;
        var curr;
        res = res.features;
        console.log(res.length);
        for (var i = 0; i < res.length; i++) {
            curr = res[i];
            if (curr.geometry && curr.geometry.type == "Point" && curr.geometry.coordinates) {
                curr.latitude = curr.geometry.coordinates[1];
                curr.longitude = curr.geometry.coordinates[0];
            }
            if (curr.properties && curr.properties.time) {
                curr.time = new Date(curr.properties.time);
                curr.dateString = curr.time.toLocaleDateString();
                curr.timeString = curr.time.toLocaleTimeString();
                curr.dateTimeString = curr.dateString + " " + curr.timeString;
            }
            if (curr.properties && curr.properties.mag) {
                currMinMag = Math.min(currMinMag, curr.properties.mag);
                currMaxMag = Math.max(currMaxMag, curr.properties.mag);
            }
        }
        data = res;
        return res;
    }

    function render(res) {
        $("#downloading").text("Download Complete!");
        res = flattenFeed(res);

        $("#map").igMap("option", "series", [{
            type: "geographicHighDensityScatter",
            name: "earthquakes",
            title: "earthquakes",
            latitudeMemberPath: "latitude",
            longitudeMemberPath: "longitude",
            dataSource: res,
            mouseOverEnabled: true,
            showTooltip: true,
            pointExtent: 2,
            tooltipTemplate: "<table><tr><td>Magnitude: </td><td>${item.properties.mag}</td></tr><tr><td>Place: </td><td>${item.properties.place}</td></tr><tr><td>Time: </td><td>${item.dateTimeString}</td></tr></table>"
        }]);
    }

    $("#map").igMap({
        width: "100%",
        height: "90%",
        horizontalZoomable: true,
        verticalZoomable: true,
        series: [],
        windowRectMinWidth: 0.001,
        overviewPlusDetailPaneVisibility: "visible"
    });


    $.ajax({
        url: "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojsonp",
        dataType: "jsonp",
        jsonpCallback: "eqfeed_callback",
        success: render
    });


});

Here’s the result:

And the associated fiddle.

Note, this series type can actually display MUCH more data. The above is roughly 7000 points, which is really on the low end of what you would be displaying with this series type. Unfortunately GeoJSON is pretty verbose, so a larger file would take even longer to download. Fortunately there are more compressed ways to get data to the map, but we’ll save that for another time!

-Graham

Infragistics Windows Forms - January 2014 Release Notes: 13.1, 13.2 Service Releases

$
0
0

With every release comes a set of release notes that reflects the state of resolved bugs and new additions from the previous release. You’ll find these notes useful to help determine the resolution of existing issues from a past release and as a means of determining where to test your applications when upgrading from one version to the next.

Release notes are available in both PDF and Excel formats. The PDF summarizes the changes to this release along with a listing of each item. The Excel sheet includes each change item and makes it easy for you to sort, filter and otherwise manipulate the data to your liking.

In order to download release notes, use the following links:

WinForms 2013 Volume 2 Service Release (Build 13.2.20132.2016)

PDF - Infragistics WinForms 2013 Volume 2
Excel - Infragistics WinForms 2013 Volume 2

WinForms 2013 Volume 1 Service Release (Build 13.1.20131.2100)

PDF - Infragistics WinForms 2013 Volume 1
Excel - Infragistics WinForms 2013 Volume 1

 

Infragistics User Group Contest 2014

$
0
0

It’s time to start the third annual Infragistics User Group Contest for 2014.  This contest started as a way to help break the ice and loosen up the attendees during my sessions at the user groups I would present at.  Once the groups learned they would be competing with other like-minded groups of people from around the country, the competition was on!  Now, this contest has grown beyond the user groups I present at, beyond the user groups in the US, and has now been expanded to ALL user groups in ALL countries, and ALL Infragistics sponsored user groups!  That’s right!  Any user group sponsored by Infragistics can submit their own photo into the contest.

Let’s cover the rules.

The Rules

The rules are simple.  The user group that has the most eye catching, fun, exciting, smile producing, feel good, or laugh inducing picture will win.  The picture must be taken the day/night of the presentation.  The picture must be taken between Jan 1, 2014 and Dec 31, 2014.  Only the user group leader can submit the photo. One entry per user group allowed.

The Contestants

Any user group, in any country, that is sponsored by Infragistics can participate in the contest.  Your user group can only be entered once for the 2014 contest.  No other event presentations qualify for this contest.

The Prize

MONEY!  The winner of the Infragistics User Group Contest 2014 will win a $500 gift card for their user group.

The Timeframe

The contest will run from Jan 1, 2014 to  December 31, 2014.  At the end of the year, we will choose the best photo to decide the winner.  The winner will be announce on the Infragistics blog.

How to Enter

To enter the Infragistics User Group Contest, send and email that contains the following information with the subject “User Group Contest 2014” to community@infragistics.com.  

  • the name of your user group
  • the date of the meeting
  • the name of the presenter
  • the user group website link
  • the image you want to submit

Submissions can only be made by the user group leader or co-leader.

If your user group is not currently sponsored by Infragistics, no problem.  Just send an email to community@infragistics.com and ask for your user group to be sponsored.  Need a speaker?  No problem.  You can request a speaker, and if we have one available, we will send them your way.  If you would like to request me to speak at your group personally, feel free to contact me.

As always, Feel free contact me on my blog, connect with me on Twitter (@brianlagunas), or leave a comment below for any questions or comments you may have.

SB VIZ: Creating a New Visualization and iOS App in under 3 Days using NUCLiOS

$
0
0
I'm going to walk you through how my colleague Tommy Rausch, our Chief Creative Officer, and I came up with a brand new visualization and created an iOS application to show case it in under 3 days! Before we get started, if you have an iPhone and/or an iPad, GO GET IT NOW!! (It's 100% Free) Now, if you want to follow along and use the amazing controls we used to make this app, you should grab them as well! It's also worth noting that while i'm going to talk about the code in objective...(read more)
Viewing all 2223 articles
Browse latest View live


Latest Images