官术网_书友最值得收藏!

Consuming application

We now have two parts of the solution: the collected data and the web service to publish it. The next step is to build a client application that will talk to the web service. Initially, we will have a details grid view (or table for the HTML-minded) of the ten latest incoming data.

Rather than having the user update the page, the screen will auto-update periodically with the latest earthquake information.

Packaging the grid

The grid display may be useful for other applications, so it will be split off into its own project as the package webgridview, as shown here:

name: 'GridViewer'
version: 0.0.1
description: A grid viewer for GeoJSON data.
environment:
  sdk: '>=1.0.0 <2.0.0'
dependencies:
  browser: '>=0.10.0 <0.11.0'
  intl: any
  webgridview:
    path: ../webgridview/

The package can be referenced in the pubspec.yaml as a local package.

Initiating the real-time updates

The main function in main.dart will perform an initial update of the grid and then initiate a Timer that will update the page on a periodic basis:

void main() {
  performUpdate(null);
  updater = new Timer.periodic(new Duration(seconds: 10), performUpdate);
}

The periodic timer handler performUpdate is provided a Timer object as a parameter when it is triggered every 10 seconds. When we are directly calling it, null is provided instead of the Timer instance.

Performing the update

The two elements being updated are the current time, with a countdown to the next refresh, and the grid of the data. Let's have a look at the following code snippet:

void performUpdate(Timer triggerTimer) {
  DivElement outputDiv = querySelector('#timestatus');

  DateTime currentDateTime = new DateTime.now();
  DateFormat timeStamp = new DateFormat("hh:mm a");

  if (triggerTimer != null) {
    secondsToUpdate -= 10;

        } else updateDataView();

  if (secondsToUpdate == 0) {
    updateDataView();
    secondsToUpdate = 60;
  }

  outputDiv.text =
      "${timeStamp.format(currentDateTime)} - $secondsToUpdate seconds until refresh.";
}

The secondsToUpdate variable is decremented from 60 to 0 and triggers an update every six calls so that the display changes every minute.

Fetching the JSON

The updateDataView function in the main.dart file covers fetching the data and updating the grid view:

...
HttpRequest.getString(jsonSrc).then((String data) {
  outputDiv.children.clear();

  List items;
  try {
    items = JSON.decode(data);
  } catch (exception, stackTrace) {
    print(exception);
    print(stackTrace);
  }
...

The DivElement outputDiv is the container for the dynamically updating content, which is entirely cleared at each update. The incoming JSON data is decoded and stored in the List object named items.

Configuring the grid view control

The data for the grid is provided as a structure of a list of lists. The first list in the structure forms the header of the table. Let's have a look at the following code snippet:

...
if (items != null) {
  List allQuakeData = [];
  allQuakeData.add(
      ['Time', 'Magnitude', 'Type', 'Tsunami', 'Place', 'Sig', 'Link']);

  items.forEach((String post) {
    Map decodedData = JSON.decode(post);

    List quakeData = [];
    quakeData.add(convertTime(decodedData['properties']['time']));
    quakeData.add(decodedData['properties']['mag']);
    quakeData.add(decodedData['properties']['type']);
    quakeData.add(decodedData['properties']['tsunami']);
    quakeData.add(decodedData['properties']['place']);
    quakeData.add(decodedData['properties']['sig']);
    quakeData.add(decodedData['properties']['url']);

    allQuakeData.add(quakeData);
  });

  outputDiv.append(Gridview.getTable(allQuakeData));
}
...

The JSON items are iterated over and the values for the grid are extracted. The only value not used directly is the time field, which requires formatting.

Formatting the time

The time provided for each feature in the JSON is an integer number. This is the time recorded as the number of milliseconds since a point in time, usually called the epoch (which is the start of the year 1970 at exactly 00:00:00 1970-01-01). Let's have a look at the following code snippet:

String convertTime(int milliTime) {
  DateTime dt = new DateTime.fromMillisecondsSinceEpoch(milliTime);
  DateFormat timeStamp = new DateFormat("hh:mm:ss a");
  return timeStamp.format(dt);
}

The DateTime format provides the named constructor fromMillisecondsSinceEpoch, which returns a regular DateTime object. This can be converted to a string and added to the table for display in the data grid.

Working with date and time

Dates and times are very important data types in all kinds of applications, and the Dart intl package has functionality for parsing and formatting dates. Countries have specific formatting and ordering preferences, and, of course, everyone is different and uses multiple formats.

The format used in the grid view may not be to your liking and may be better displayed as a 24-hour format. The project timesdate in the sample code for this chapter explores the different date formats that are available. This short command-line program shows some of the options available; the list is quite long, and it is fully documented in the intl package documentation. Let's have a look at the following code snippet:

  DateTime currentTime = new DateTime.now();

  print("\nDate and Time Demo");
  printTime(currentTime, "hh:mm a");
  printTime(currentTime, "HH:MM");
  printTime(currentTime, "y");
  printTime(currentTime, "d");
  printTime(currentTime, "M");
  printTime(currentTime, "EEEE");
 …

The preceding code renders the following output display, which will vary according to the time at which it is executed:

  Date and Time Demo
  hh:mm a      04:12 PM
  HH:MM        16:06
  y            2015
  d            13
  EEEE         Saturday

The function printTime formats the input DateTime to the desired style. The padRight method on the String object is used to make a simple table by adding spaces to pad out the string to 12 characters, as shown here:

void printTime(DateTime dt, String format) {
  DateFormat timeStamp = new DateFormat(format);
  print("\t${format.padRight(12)} ${timeStamp.format(dt)}");
}

The second part of the program allows a date to be entered by using the stdin readlineSync method. The user can enter a blank line to exit. The string is parsed according to the format yyyy-MM-dd, and the weekday is displayed if it is successfully parsed:

 while (true) {
  String userDate = "";
  print("\nPlease enter a date (yyyy-MM-dd):");

  try {
    DateFormat timeStamp = new DateFormat("yyyy-MM-dd");
    DateFormat outputFmt = new DateFormat("EEEE");

    userDate = stdin.readLineSync();
    if (userDate.length == 0) exit(0);

    print(outputFmt.format(timeStamp.parse(userDate)));
  } catch (exception, stacktrace) {
    print('Error parsing the entered date.');
    print(exception);
    print(stacktrace);
  }
}

The parsing is wrapped in try catch to deal with an exception raise with a failed parse of a date string.

Building the table

The class GridView, located in the file lib/src/webgridview_base.dart, prepares a table from the list of lists provided by the calling web page. The static method getTable performs the task. As it is static, an instance of the class is not required to call this function. Let's have a look at the following code snippet:

  static TableElement getTable(List rows) {
    TableElement te = new TableElement();
    rows.forEach((row) => addRow(te, row));
    return te;
  }

The addRow function iterates over the columns in the results. The header row is added as a regular row as the CSS will take care of the special formatting of the first row, as shown here:

  static addRow(TableElement table, List cols) {
  TableRowElement tableRow = table.addRow();

  cols.forEach((column) {
    TableCellElement tableCell = tableRow.addCell();
    String content = column.toString();
    if (content.startsWith('http')) {
      content = "<a href=\"$content\">Link</a>";
      tableCell.appendHtml(content);
    } else tableCell.text = content;
  });
}

The content is added as text to the table cell, with one special case of strings that start with http. These URLs are formatted into HTML with a generic link text, and the appendHtml method is used to ensure that the text is not sanitized before being added to the page.

Showing the page

Launching the application in Dartium will show the index.html page:

Showing the page

Keep this page open over a period of time and the table will update smoothly as new data becomes available. Events from outside the USA do appear, though less often. It is fairly rare, but the Type column does not always read 'earthquake'.

主站蜘蛛池模板: 台北县| 文登市| 宜昌市| 黔西县| 来宾市| 海城市| 囊谦县| 怀来县| 泌阳县| 芜湖市| 镇沅| 陵川县| 龙口市| 江永县| 三门峡市| 上栗县| 英吉沙县| 台中市| 洱源县| 琼海市| 辉县市| 上犹县| 石嘴山市| 荃湾区| 临朐县| 富蕴县| 宁武县| 简阳市| 沙坪坝区| 余干县| 岫岩| 汽车| 平南县| 金秀| 克东县| 镇远县| 永和县| 汕头市| 石屏县| 明水县| 开平市|