morzel.net

.net, js, html, arduino, java... no rants or clickbaits.

[OoB] Sonar with Arduino, C#, JavaScript and HTML5 (Part 2)

Part 1 described the general idea behind Sonar project, hardware components used and Arduino sketch... This second post in "Out of Boredom" series is about C# and JavaScript programs that make it possible to display ultrasonic range sensor data in web browsers. The role of .NET application is to receive messages from Arduino over serial port and broadcast it to clients using SignalR library. JS/HTML5 clients use jquery.signalR lib to obtain information about servo position with distance to obstacles and use this data to render sonar image on canvas:

Sonar client image... Click to enlarge...

These links are in previous post, but just to remind you:

 

1. SonarServer 

SonarServer is a .NET 4.5 console app created in Visual Studio Express 2013 for Windows Desktop. It uses Microsoft.AspNet.SignalR.SelfHost and Microsoft.Owin.Cors NuGet packages to create self-hosted SignalR server. ASP.NET SignalR is a library designed to make it easy to create applications that are able to push data to clients running in web browsers. This is in contrast to normal web pages/apps behavior where the client (browser) asks server for action by issuing a request (such as GET or POST). SignalR allows clients to listen for messages send by a server... If possible SignalR will use WebSockets to enable efficient bi-directorial connection. If that option is not available due to either browser or server limitations, it will automatically switch to other push techniques like long polling or Server-Sent Events. When I tested the code on my laptop with Windows 7 Home Premium SP1, long polling was used on IE 11 and SSE in Chrome 37. Server was sending about 20 messages per second and clients didn't have any problems with handling that load (communication was on localhost). Self-hosting means that SignalR server doesn't have to be run on a web server such as IIS - it can exist in plain old console project! If you are completely new to SignalR check this tutorial... 

This is SonarServer project structure:

SonarServer solution...

SonarData.cs file contains such struct:

namespace SonarServer
{
    public struct SonarData
    {
        public byte Angle { get; set; }
        public byte Distance { get; set; }
    }
}

Server will send a list of such objects to clients.

SonarHub.cs contains a class derived form Hub. It doesn't declare any methods but is nonetheless useful. Library will use it to generate JavaScript proxy objects...

using Microsoft.AspNet.SignalR;

namespace SonarServer
{
    public class SonarHub : Hub
    {

    }
}

Startup.cs file looks like this:

using Microsoft.Owin.Cors;
using Owin;

namespace SonarServer
{
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);
            app.MapSignalR();
        }
    }
}

It configures the SignalR server, letting it support cross-domain connection thanks to UseCors call.

Below are the most important bits of Program.cs file. This code:

using (SerialPort sp = new SerialPort())
 {
     sp.PortName = "COM3";
     sp.ReceivedBytesThreshold = 3;
     sp.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

     sp.Open();

     Console.WriteLine("Serial port opened!");

     using (WebApp.Start<Startup>("http://localhost:8080/"))
     {
         Console.WriteLine("Server running!");
         Console.ReadKey();
     }
 }

is responsible for opening a connection with Arduino over serial port named "COM3" and starting SignalR server on localhost:8080ReceivedBytesThreshold property allows us to control the amount of bytes received from Arduino before DataReceivedHandler is called. You can increase this value if you want bigger packages of data to be broadcasted by server and rendered by clients. This is the part of DataReceivedHandler method that loads serial port data into a byte array:

int count = sp.BytesToRead;
[] data = new byte[count];
sp.Read(data, 0, count);

Such array of bytes is latter on added to custom buffer and processed to create a list of SonarData objects sent to SignalR clients. Part 1 mentioned that Arduino sends data to PC in bytes (array) packages containing three elements: [255, angle, distance]. The purpose of special 255 value is to separate angle-distance pairs of values which are used to create sonar image. We can't just send [angle, distance] stream from Arduino to PC, because the Server could easily loose track of which value is angle and which is distance. This might happen due to delays, buffering etc. Sure it's not a bulletproof protocol but it work well when I tested it. Lot's not get crazy with that - it's a hobby project, remember? :) Check ProcessSonarData method in repository if you want to see how an array of bytes is turned into SonarData list (with buffering taken into account)... 

The last missing piece of SonarServer puzzle is SendSonarDataToClients method:

private static void SendSonarDataToClients(List<SonarData> sonarDataForClients)
{
    var hub = GlobalHost.ConnectionManager.GetHubContext<SonarHub>();
    hub.Clients.All.sonarData(sonarDataForClients);

    Console.WriteLine("Sonar data items sent to clients. Samples count=" + sonarDataForClients.Count);
}

This is the thing that actually broadcasts data to clients running in web browsers. You may be wondering why SonarHub instance is not created directly with new operator and instead GetHubContext method is used. This is because SignalR is responsible for its hubs life cycle. Such code:

SonarHub sonarHub = new SonarHub();
sonarHub.Clients.All.sonarData(sonarDataForClients);

would result in the exception: System.InvalidOperationException: Using a Hub instance not created by the HubPipeline is unsupported." .

 

2. SonarClient

SonarClient is the subproject responsible for drawing sonar image. It's not a Visual Studio solution - just a few files:

SonarClient files...

I've tested SonarClient code in IE 11 and Chrome 37 and it worked really well. The assumption is that you run modern browser too. I didn't bother with any feature detection, it's enough for me that I have to write for IE9 at work - well, at least it's not IE 6, huh? ;) But if you want to do such thing I can recommend Modernizr library...

This is content of index.html file (with some boring parts removed for brevity):

<!DOCTYPE html>
<html>
<head>
    <title>Sonar - sample code from morzel.net blog post</title>
    <style>
        /* more */
    </style>
</head>
<body>
    <div>
        <canvas id="sonarImage" width="410" height="210"></canvas>

        <table>
              <!-- more -->            
        </table>
    </div>

    <a href="http://morzel.net" target="_blank">morzel.net</a>

    <script src="lib/jquery-1.6.4.js"></script>
    <script src="lib/jquery.signalR-2.1.1.js"></script>
    <script src="http://localhost:8080/signalr/hubs"></script>
    <script src="sonarStats.js"></script>
    <script src="sonarImage.js"></script>
    <script src="sonarConnection.js"></script>

    <script>
        $(function () {          
            sonarImage.init('sonarImage');
            sonarConnection.init('http://localhost:8080/signalr');
        });
    </script>
</body>
</html>

Most important bit of this HTML5 markup is the canvas element used to create sonar image. The page imports jquery and jquery.signalR libraries that make it possible to communicate with the Server. That line is particularly interesting:

 <script src="http://localhost:8080/signalr/hubs"></script>

SingalR automatically creates JavaScript proxy objects for server-client messaging, that line lets us load them into page. Last three script references are for JS modules responsible for: displaying info about data received from SonarServer, rendering sonar image and communication with server, respectively. Later there's a short script which initializes the modules after pages DOM is ready.

I will skip the description of sonarStats.js file (nothing fancy there - just filling some table cells). But sonarConnection.js should be interesting for you. This is the whole content:

var sonarConnection = (function () {
    'use strict';

    var sonarHub, startTime, numberOfMessages, numberOfSamples;

    var processSonarData = function (sonarData) {
        numberOfMessages++;
        $.each(sonarData, function (index, item) {
            numberOfSamples++;
            sonarImage.draw(item.Angle, item.Distance);
            sonarStats.fillTable(item.Angle, item.Distance, startTime, numberOfMessages, numberOfSamples);
        });
    };

    return {
        init: function (url) {
            $.connection.hub.url = url;

            sonarHub = $.connection.sonarHub;

            if (sonarHub) {
                sonarHub.client.sonarData = processSonarData;
                               
                startTime = new Date();
                numberOfMessages = 0;
                numberOfSamples = 0;

                $.connection.hub.start();
            } else {
                alert('Sonar hub not found! Are you sure the server is working and URL is set correctly?');
            }
        }
    };
}());

The init method sets SignalR hub URL along with sonarData handler and starts a connection with the .NET app. There is also some very basic hub availability check (jquery.signalR library has extensive support for connection related events but lets keep things simple here). processSonarData is invoked in response to Server calling hub.Clients.All.sonarData(sonarDataForClients). The processSonarData function receives an array of objects containing information about servo angle and distance to obstacles. SignalR takes care of proper serialization/deserialization of data - you don't have to play with JSON yourself. $.each function (part of jQuery) is used to invoke sonarImage.draw and sonarStats.fillTable methods for every item in sonarData array...

And here comes the module that changes pairs of angle-distance values into o nice sonar image (whole code of sonarImage.js):

var sonarImage = (function () {
    'use strict';

    var maxDistance = 100;
    var canvas, context;

    var fadeSonarLines = function () {
        var imageData = context.getImageData(0, 0, canvas.width, canvas.height),
            pixels = imageData.data,
            fadeStep = 1,
            green,
            fadedGreen;

        for (var i = 0; i < pixels.length; i += 4) {
            green = pixels[i + 1];

            fadedGreen = green - fadeStep;
            pixels[i + 1] = fadedGreen;
        }

        context.putImageData(imageData, 0, 0);
    };

    return {
        init: function (canvasId) {
            canvas = document.getElementById(canvasId);
            context = canvas.getContext('2d');

            context.lineWidth = 2;
            context.strokeStyle = '#00FF00';
            context.fillStyle = "#000000";

            context.fillRect(0, 0, canvas.width, canvas.height);

            context.translate(canvas.width / 2, 0);
            context.scale(2, 2);
        },

        draw: function (angle, distance) {
            context.save();

            context.rotate((90 - angle) * Math.PI / 180);
            context.beginPath();
            context.moveTo(0, 0);
            context.lineTo(0, distance || maxDistance); // Treat 0 as above range
            context.stroke();

            context.restore();

            fadeSonarLines();
        }
    };
}());

Again we have an init method. It obtains 2d drawing context from canvas and uses it to set line width and color (green). It also sets inner color (black) and fills the whole canvas with it. context.translate call is used to move origin of coordinate system to the middle of canvas (horizontally). By default it sits in upper left corner. context.scale is used to make image two times bigger than it would be drawn in default settings. Read this post if you want to know more about canvas coordinates.

The draw method is invoked for each data sample (angle-distance pair) produced by Arduino and broadcasted with SonarServer. The distance to obstacles measured by HC-SR04 sensor is represented as a line. The bigger the distance the longer the line. This happens thanks to beginPath, moveTo, lineTo, and stroke calls. context.rotate method is responsible for showing the angle in which the sensor was pointing while measuring distance (angle of servo arm). As the servo moves around we want to change the direction in which distance line is drawn. Notice that code responsible for drawing the line is surrounded by context.save and context.restore calls. These two ensure that rotation transformation doesn't accumulate between draw method calls...

fadeSonarLines function is responsible for creating the effect of older sonar lines disappearing in a nice gradual way. context.getImageData method returns an array of RGBA values representing the pixels that create current canvas image. The function loops through image data and progressively reduces the intensity of green color component. This way sonar lines fade to black.

And viola - sonar image can be rendered in a browser :)

Isn't it amazing what is now possible on the web platform? I'm not exactly a dinosaur but I remember when displaying a div overlay on a page required use of hidden iframe (because select elements were otherwise rendered above the overlay)... Crazy times ;)

[OoB] Sonar with Arduino, C#, JavaScript and HTML5

This post marks the beginning of "Out of Boredom" series. It will be about creating stuff with my recently purchased Arduino Uno. Let's have a break from chores of professional programming and create something just for fun :)

My first Arduino based project is Sonar. It utilizes ultrasonic range sensor, servo, SignalR and canvas to create sonar image:

Sonar at work... Click to enlarge...

I am splitting the description into two posts. First post will focus on hardware components and Arduino sketch and the second will be about .NET and JavaScript applications. You can get complete code in this GitHub repository. You can also click here to see short video of the whole thing working.

Here are hardware elements used:

Element Role
Arduino Uno R3 Handling HC-SR04, controlling servo and communicating with PC
HC-SR04 Ultrasonic Ranging Module Measuring time it takes sound to bounce back from objects
9g Tower Pro Micro Servo Moving sensor to get 180 degree view
Red LED Signalling ready state
330 Ohm resistor Limiting current going through diode
Breadboard and few jumper wires Connecting components without soldering 

That's it, just a few cheap components! Virtually no electronics skills are required to complete this project. I assume, however, that you have basic Arduino knowledge and you know a bit about C# and JavaScript.

Here is the software stack:

Element Role
Arduino sketch (firmware) Measuring distance, moving servo and sending data to PC over serial port 
.NET/C# 4.5 console application with SignalR library  Receiving data from Arduino using SerialPort class and broadcasting angle and distance information to clients
HTML5 page with JavaScript SignalR library Receives data from server and creates sonar image using canvas element

Above might sound a bit overwhelming but I assure you that the code is short and not that complicated.

The basic idea goes like this: HC-SR04 sensor measures time it takes an ultrasonic signal to bounce from obstacles and this gives as a chance to calculate distance to these obstacles. Position of the sensor is controlled by servo. Information about distance to objects and direction in which the sensor is pointing is sent to PC that is running console application with SignalR sever. PC receives the data and sends it to JavaScript clients that are capable of presenting sonar data in nice visual way using HTML5 canvas element...

More details!

The main component (except for the Arduino of course) is the HC-SR04 Ultrasonic Ranging Module. This sensor works by sending sound signal at 40 kHz (so above human perception limits) and detecting the echo. That's why this project is called "Sonar" and not "Radar" - it uses sound waves (not radio waves) do detect objects. The sensor should work in ranges from 2cm up to 400cm at accuracy of few millimetres. But keep in mind that the shape an material of objects might affect performance. I tested it at maximum distance of about 2 meters and was happy with the results. You can use this sensor without any libraries. That requires doing things like putting HIGH value on Trig pin for 10uS to emit ultrasonic signal, measuring duration of HIGH pulse on Echo pin and calculating distance knowing that speed of sound in the air is around 340m/s... But there's a better way: you can use NewPing lib (link) to get the distance. If you don't know how to include new library in your Arduino sketch click here.

The second important component is the servo. HC-SR04 sensor has measuring angle of about 15 degrees. But if we move it around by attaching it to servo's arm we can easily get 180 degree view. I won't get into details on how servo works and how it is controlled in this post. I plan to make another post about shooting paintball marker with Arduino+laptop and I will describe it then. For now all you need to know is that Arduino comes with Servo library which makes it very easy to move servo into desired position (angle)... I utilized 9g Tower Pro Micro Servo in this project. It's powerful enough to move the sensor yet can be powered directly from Arduino's +5V pin.

Last physical components are LED used to signal the ready state (that is when setup function had completed) with its accompanying resistor. Making a diode shine is electronics equivalent of "Hello World!" so I'm sure you know how to handle LED. Even if not, you can always use the tiny built-in LED connected to pin 13 of Arduino Uno...

This diagram shows how hardware components should be connected:

Fritzing breadboard diagram

Here's the whole code that should be uploaded to Arduino:  

#include <NewPing.h>
#include <Servo.h>  

const byte setupReadyLedPin = 8;
const byte triggerPin = 10;
const byte echoPin = 11;
const byte servoPin = 12;

const byte maxDistanceInCm = 100;

byte angle;
byte angleStep;
byte angleStepDelayInMs = 50;

NewPing sonar(triggerPin, echoPin, maxDistanceInCm); 
Servo servo; 

void setup() {  
    pinMode(setupReadyLedPin, OUTPUT);
    
    angle = 0;
    angleStep = 1;
    
    servo.attach(servoPin);   
    servo.write(angle); 
    
    Serial.begin(9600); // Open connection with PC
    
    digitalWrite(setupReadyLedPin, HIGH);
}

void loop() {      
    alterServoMoveDirection();    
    
    measureAndSendDistance();
    
    angle += angleStep;
    servo.write(angle); // Move servo
    
    delay(angleStepDelayInMs);   
}

void alterServoMoveDirection() {
    if (angle == 180) {
       angleStep = -1; 
    } else if (angle == 0) {
       angleStep = 1;
    }
}

void measureAndSendDistance() {
    byte distanceInCm = sonar.ping_cm(); // Use ultrasound to measure distance   
      
    byte sonarData[] = {255, angle, distanceInCm};
    Serial.write(sonarData, 3); // Send data to PC
}

As stated before, I assume that you know something about Arduino programming and things like const, pinMode, delay, setup and loop don't require explanation...

First lines which should capture your attention are:

#include <NewPing.h>
#include <Servo.h>  

NewPing sonar(triggerPin, echoPin, maxDistanceInCm); 
Servo servo;

Above lines let us use NewPing and Servo classes to measure distance and move the sensor. Notice also that setup function has such lines:

servo.attach(servoPin);   
servo.write(angle);

These exist to set the pin used to control the servo and to move the servo into initial position at 0 degrees.

This line:

Serial.begin(9600);

allowes Arduino to talk to PC (in my case a laptop with Windows 7) over serial port. That's right, even though Arduino Uno is connected to computer via USB cable it actually uses COM port to communicate. On my machine its called "COM3" (screen shown below comes from Device Manager - my Windows is in Polish):

COM port for Arduino... Click to enlarge...

The value passed to begin method determinates baud rate (communication speed). It's important to have the same value used in software that communicats with Arduino.

The loop function moves servo and invokes measureAndSendDistance function which uses NewPing to calculate distance and Serial to send data to PC. This is how easy it is to get distance in cm thanks to NewPing lib:

byte distanceInCm = sonar.ping_cm()

If measured distance exceeds the maximum value specified as last parameter to NewPing constructor the value of 0 is returned. Check NewPing docs to see other useful functions of this lib.

And finally this is how Arduino sends data to PC:

byte sonarData[] = {255, angle, distanceInCm};
Serial.write(sonarData, 3); // Send data to PC

The first array element (255) is used as a marker/separator to easily distinguish pairs of angle-distance values. Its role will become clear in the second post which will describe SignalR server and clients... I assume that maxDistanceInCm const will never be set above 200 so distanceInCm will never have value of 255. 255 will never be sent as an angle too because our servo moves in 0..180 degrees range. Sure it might be a good idea to create const and avoid 255 magic number. Some validation would be useful too... But screw it, this project is just for fun! :)

Ok, you survived to the end of the first post about Arduino/.NET/JS/HTML sonar. The second post should be ready in about a week.

Update 2014-09-29: Here's the Part 2.

jQuery UI Autocomplete in MVC 5 - selecting nested entity

Imagine that you want to create edit view for Company entity which has two properties: Name (type string) and Boss (type Person). You want both properties to be editable. For Company.Name simple text input is enough but for Company.Boss you want to use jQuery UI Autocomplete widget*. This widget has to meet following requirements:

  • suggestions should appear when user starts typing person's last name or presses down arrow key;
  • identifier of person selected as boss should be sent to the server;
  • items in the list should provide additional information (first name and date of birth);
  • user has to select one of the suggested items (arbitrary text is not acceptable);
  • the boss property should be validated (with validation message and style set for appropriate input field).

Above requirements appear quite often in web applications. I've seen many over-complicated ways in which they were implemented. I want to show you how to do it quickly and cleanly... The assumption is that you have basic knowledge about jQuery UI Autocomplete and ASP.NET MVC. In this post I will show only the code which is related to autocomplete functionality but you can download full demo project here. It’s ASP.NET MVC 5/Entity Framework 6/jQuery UI 1.10.4 project created in Visual Studio 2013 Express for Web and tested in Chrome 34, FF 28 and IE 11 (in 11 and 8 mode). 

So here are our domain classes:

public class Company
{
    public int Id { get; set; } 

    [Required]
    public string Name { get; set; }

    [Required]
    public Person Boss { get; set; }
}
public class Person
{
    public int Id { get; set; }

    [Required]
    [DisplayName("First Name")]
    public string FirstName { get; set; }
    
    [Required]
    [DisplayName("Last Name")]
    public string LastName { get; set; }

    [Required]
    [DisplayName("Date of Birth")]
    public DateTime DateOfBirth { get; set; }

    public override string ToString()
    {
        return string.Format("{0}, {1} ({2})", LastName, FirstName, DateOfBirth.ToShortDateString());
    }
}

Nothing fancy there, few properties with standard attributes for validation and good looking display. Person class has ToString override – the text from this method will be used in autocomplete suggestions list.

Edit view for Company is based on this view model:

public class CompanyEditViewModel
{    
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public int BossId { get; set; }

    [Required(ErrorMessage="Please select the boss")]
    [DisplayName("Boss")]
    public string BossLastName { get; set; }
}

Notice that there are two properties for Boss related data.

Below is the part of edit view that is responsible for displaying input field with jQuery UI Autocomplete widget for Boss property:

<div class="form-group">
    @Html.LabelFor(model => model.BossLastName, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.TextBoxFor(Model => Model.BossLastName, new { @class = "autocomplete-with-hidden", data_url = Url.Action("GetListForAutocomplete", "Person") })
        @Html.HiddenFor(Model => Model.BossId)
        @Html.ValidationMessageFor(model => model.BossLastName)
    </div>
</div>

form-group and col-md-10 classes belong to Bootstrap framework which is used in MVC 5 web project template – don’t bother with them. BossLastName property is used for label, visible input field and validation message. There’s a hidden input field which stores the identifier of selected boss (Person entity). @Html.TextBoxFor helper which is responsible for rendering visible input field defines a class and a data attribute. autocomplete-with-hidden class marks inputs that should obtain the widget. data-url attribute value is used to inform about the address of action method that provides data for autocomplete. Using Url.Action is better than hardcoding such address in JavaScript file because helper takes into account routing rules which might change.

This is HTML markup that is produced by above Razor code:

<div class="form-group">
    <label class="control-label col-md-2" for="BossLastName">Boss</label>
    <div class="col-md-10">
        <span class="ui-helper-hidden-accessible" role="status" aria-live="polite"></span>
        <input name="BossLastName" class="autocomplete-with-hidden ui-autocomplete-input" id="BossLastName" type="text" value="Kowalski" 
         data-val-required="Please select the boss" data-val="true" data-url="/Person/GetListForAutocomplete" autocomplete="off">
        <input name="BossId" id="BossId" type="hidden" value="4" data-val-required="The BossId field is required." data-val-number="The field BossId must be a number." data-val="true">
        <span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="BossLastName"></span>
    </div>
</div>

This is JavaScript code responsible for installing jQuery UI Autocomplete widget:

$(function () {
    $('.autocomplete-with-hidden').autocomplete({
        minLength: 0,
        source: function (request, response) {
            var url = $(this.element).data('url');
   
            $.getJSON(url, { term: request.term }, function (data) {
                response(data);
            })
        },
        select: function (event, ui) {
            $(event.target).next('input[type=hidden]').val(ui.item.id);
        },
        change: function(event, ui) {
            if (!ui.item) {
                $(event.target).val('').next('input[type=hidden]').val('');
            }
        }
    });
})

Widget’s source option is set to a function. This function pulls data from the server by $.getJSON call. URL is extracted from data-url attribute. If you want to control caching or provide error handling you may want to switch to $.ajax function. The purpose of change event handler is to ensure that values for BossId and BossLastName are set only if user selected an item from suggestions list.

This is the action method that provides data for autocomplete:

public JsonResult GetListForAutocomplete(string term)
{               
    Person[] matching = string.IsNullOrWhiteSpace(term) ?
        db.Persons.ToArray() :
        db.Persons.Where(p => p.LastName.ToUpper().StartsWith(term.ToUpper())).ToArray();

    return Json(matching.Select(m => new { id = m.Id, value = m.LastName, label = m.ToString() }), JsonRequestBehavior.AllowGet);
}

value and label are standard properties expected by the widget. label determines the text which is shown in suggestion list, value designate what data is presented in the input filed on which the widget is installed. id is custom property for indicating which Person entity was selected. It is used in select event handler (notice the reference to ui.item.id): Selected ui.item.id is set as a value of hidden input field - this way it will be sent in HTTP request when user decides to save Company data.

Finally this is the controller method responsible for saving Company data:

public ActionResult Edit([Bind(Include="Id,Name,BossId,BossLastName")] CompanyEditViewModel companyEdit)
{
    if (ModelState.IsValid)
    {
        Company company = db.Companies.Find(companyEdit.Id);
        if (company == null)
        {
            return HttpNotFound();
        }

        company.Name = companyEdit.Name;

        Person boss = db.Persons.Find(companyEdit.BossId);
        company.Boss = boss;
        
        db.Entry(company).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(companyEdit);
}

Pretty standard stuff. If you've ever used Entity Framework above method should be clear to you. If it's not, don't worry. For the purpose of this post the important thing to notice is that we can use companyEdit.BossId because it was properly filled by model binder thanks to our hidden input field.

That's it, all requirements are met! Easy, huh? :)

* You may be wondering why I want to use jQuery UI widget in Visual Studio 2013 project which by default uses Twitter Bootstrap. It's true that Bootstrap has some widgets and plugins but after a bit of experimentation I've found that for some more complicated scenarios jQ UI does a better job. The set of controls is simply more mature...

Coordinate system in HTML5 Canvas, drawing with y-axis value increasing upwards

Coordinate system in HTML5 Canvas is set up in such a way that its origin (0,0) is in the upper-left corner. This solution is nothing new in the world of screen graphics (e.g. the same goes for Windows Forms and SVG). CRT monitors, which were standard in the past, displayed picture lines from top to bottom and image within a line was created from left to right. So locating origin (0,0) in the upper-left corner was intuitive and it made creating hardware and software for handling graphics easier.

Unfortunately sometimes default coordinate system in canvas is a bit impractical. Let’s assume that you want to create projectile motion animation. It seems natural that for ascending projectile, the value of y coordinate should increase. But it will result in a weird effect of inverted trajectory:

Default coordinate system (y value increases downwards)

You can get rid of this problem by modifying y value that is passed to drawing function:

context.fillRect(x, offsetY - y, size, size);

For y = 0, projectile will be placed in a location determined by offsetY (to make y = 0 be the very bottom of the canvas, set offsetY equal to height of the canvas). The bigger the value of y the higher a projectile will be drawn. The problem is that you can have hundreds of places in your code that use y coordinate. If you forget to use offsetY just once the whole image may get destroyed. 

Luckily canvas lets you make changes to coordinate system by means of transformations. Two transformation methods will be useful for us: translate(x ,y) and scale(x, y). The former allows us to move origin to an arbitrary place, the latter is for changing size of drawn objects, but it may also be used to invert coordinates.

Single execution of the following code will move origin of coordinate system to point (0, offsetY) and establish y-axis values as increasing towards the top of the screen:

context.translate(0, offsetY);
context.scale(1, -1);

Translation and scaling of coordinate system. Click to enlarge...

But there’s a catch: the result of providing -1 as scale’s method second argument is that the whole image is created for inverted y coordinate. This applies to text too (calling fillText will render letters upside-down). Therefore before writing any text, you have to restore default y-axis configuration. Because manual restoring of canvas state is awkward, methods save() and restore() exist. These methods are for pushing canvas state on the stack and popping canvas state from the stack, respectively. It is recommended to use save method before doing transformations. Canvas state includes not only transformations but also values such as fill style or line width...

context.save();
 
context.fillStyle = 'red';
context.scale(2, 2);
context.fillRect(0, 0, 10, 10);
 
context.restore();
 
context.fillRect(0, 0, 10, 10);

Above code draws 2 squares: 

First square is red and is drawn with 2x scale. Second square is drawn with default canvas settings (color black and 1x scale). This occurs because right before any changes to scale and color, canvas state was save on the stack, later on it was restored before second square drawing.

How to close pop-ups upon main window closure or logout?

Imagine you have to provide support for some really old web application. The app has one main window and pop-up windows that show some sensitive information (for example payroll list). Client wants to ensure that all pop-ups are closed when user leaves main window or clicks “logout” button in this window...

So... how to close all the windows opened with window.open?

On the web this question comes up very often. Unfortunately, most common answer is really naive. Proposed solution is based on keeping references to opened pop-ups and subsequent invocation of close method: 

var popups = []; 
 
function openPopup() {
    var wnd = window.open('Home/Popup', 'popup' + popups.length, 'height=300,width=300');
     
    popups.push(wnd);
}
 
function closePopups() {
    for (var i = 0; i < popups.length; i++) {
        popups[i].close();
    }
 
    popups = [];
}

In practice this doesn’t work because the array of references is cleared at full page reload (for example after clicking on a link or upon postback)...

Other suggested solution is to give the pop-up a unique name (using the second parameter of the open method) and later acquisition of a reference to the window:

var wnd = window.open('', 'popup0');
wnd.close();

This is based on the fact, that window.open method works in two modes:

  1. If a window with a given name doesn’t exist, it is created.
  2. If a window with a given name does exist, it will not be recreated, instead a reference to that window will be returned (if non empty URL is passed to the open method pop-up will be reloaded).

The problem lies at point no. 1. If pop-up window with given name wasn’t previously opened, the call to open and close methods will cause the pop-up to be briefly visible. It sucks…

But maybe a reference to pop-up can be retained between page reloads?

If there is no need to support older browsers (unlikely for the old application) we can try to put reference to the pop-up window into localStorage. However, this will not work:

var popup = window.open('http://morzel.net', 'test');
localStorage.setItem('key', JSON.stringify(popup)); 
 
TypeError: Converting circular structure to JSON

Old tricks for keeping page state between reloads that are based on cookies or window.name will not work too.

 

So… what to do?

Even if you can’t afford to have a major change such as introducing frames, don’t give up :)

Pop-up windows have opener property that points to parent window (that is the window in which the call to window.open was placed). Pop-ups can therefore periodically check whether the main window still remains open. Additionally, pop-ups can also access variables from parent window. This can be used to enforce pop-ups closure when main window is closed or when user clicks on “logout” button in parent window. When user is logged-in (and only then!), a marker variable (i.e. loggedIn) should be set in main window.

Here is the JS code that should be placed on a page displayed in a pup-up:

window.setInterval(function () {
    try {
        if (!window.opener || window.opener.closed === true || window.opener.loggedIn !== true) {
            window.close();
        }
    } catch (ex) {
        window.close(); // FF may throw security exception when you try to access loggedIn (for external site)
    }
}, 1000);

Checking variable from the opener window has another advantage. If user moves away from our application in main window (for example by clicking back button or a link to an external website), then the pop-up window will detect the lack of monitored variable in window.opener and close automatically.

Well, it's not the kind of code you enjoy to write but it achieves the desired result despite the painful gaps in the browsers API. If only they provide us with window.exists('name') method...