Using Leaflet in a Power BI Custom Visual

For some of the spatial visualisations I’ve been working with in Power BI, I’ve had to create Custom Visuals as the out-of-the-box and visuals in the AppSource don’t quite hit the mark. I’m quite fond of Leaflet for map rendering. Here’s how I got it working with a Power BI Custom Visual.

Create a new Custom Visual via the Command Line:

pbiviz new LeafletCustomVisual

In the newly created directory, install Leaflet via npm:

npm install --save leaflet

You need the geojson as the typings for Leaflet (in the next step), depends on the package being available.

Install typings for Leaflet:

npm install --save-dev @types/leaflet

As Power BI Custom Visuals don’t currently support modules, you will need to grab the Leaflet object from the window. Create an inject.js file with the contents:

var L = window.L;

Add the Leaflet package and inject.js file to pbiviz.json in the externalJS key:

"externalJS": [
    "node_modules/leaflet/dist/leaflet.js",
    "inject.js",
    "node_modules/powerbi-visuals-utils-dataviewutils/lib/index.js"
  ],

Import the Leaflet stylesheet to style/visual.less :

@import (less) "node_modules/leaflet/dist/leaflet.css";

In src/visual.ts, change the constructor to:

private map: L.Map;

constructor(options: VisualConstructorOptions) {
    console.log('Visual constructor', options);
    this.target = options.element;
    // Fill the target element with the Leaflet map
    this.target.style.width = "100%";
    this.target.style.height = "100%";

    if (typeof document !== "undefined") {
        this.map = L.map(this.target).setView([0, 0], 2);
        L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(this.map);
    }
}

You can find an example project on GitHub.

SecurePay SecureFrame example

I recently had to debug an application that uses SecurePay as an online payment system. Rather than using API integration, the application used SecureFrame, where SecurePay provides the payment page (e.g. via an iframe). I couldn’t find an example in the SecureFrame documentation, so here’s a minimal working example:

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/core-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/sha1-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js"></script>
<script>
$(function() {
  var merchantId = "ABC0001";
  var password = "abc123";
  var txnType = "0";
  var primaryRef = "Test Reference";
  var amount = "100";
  var timestamp = moment.utc().format("YYYYMMDDHHMMSS");
  var fingerprint = CryptoJS.enc.Hex.stringify(
    CryptoJS.SHA1([merchantId, password, txnType, primaryRef, amount, timestamp].join("|"))
  );
  $('input[name="merchant_id"]').val(merchantId);
  $('input[name="txn_type"]').val(txnType);
  $('input[name="primary_ref"]').val(primaryRef);
  $('input[name="amount"]').val(amount);
  $('input[name="fp_timestamp"]').val(timestamp);
  $('input[name="fingerprint"]').val(fingerprint);
  $("form").submit();
});
</script>
</head>
<body>
<form action="https://payment.securepay.com.au/test/v2/invoice" method="post">
  <input type="hidden" name="bill_name" value="transact">
  <input type="hidden" name="merchant_id">
  <input type="hidden" name="txn_type">
  <input type="hidden" name="primary_ref">
  <input type="hidden" name="amount">
  <input type="hidden" name="fp_timestamp">
  <input type="hidden" name="fingerprint">
</form>
</body>
</html>

Financial Comparison of Air Conditioners

I’ve been looking to get ducted AC installed at my residence and have had a few quotes come in. As the AC units, zoning and controls came with a similar set of features, I investigate the decision from an objective financial standpoint by ranking the offerings by comparing both the capital and operating costs. The rank* is calculated by:

ac_equation

where
capital_cost is the total installation price in dollars
number_of_years is the number of years the AC will be in operation
cost_per_unit_capacity is the electricity price (e.g. cents per kWh)
max_cooling_usage is the number of hours per year the AC will run on max cooling capacity
min_cooling_usage is the number of hours per year the AC will run on min cooling capacity
max_heating_usage is the number of hours per year the AC will run on max heating capacity
min_heating_usage is the number of hours per year the AC will run on min heating capacity
cooling_input_power is the rated input power in kW for cooling
heating_input_power is the rated input power in kW for heating
min_cooling_capacity is the minimum cooling capacity in kW
min_cooling_capacity is the minimum heating capacity in kW
min_eer is the min EER (Energy Efficiency Ratio) out of all the ACs being compared
current_eer is the EER of this particular AC
min_cop is the min COP (Coefficient Of Performance) out of all the ACs being compared
current_cop is the COP of this particular AC

I use the term rank rather than Total Cost of Ownership since I don’t bother discounting future cashflows nor take into account maintenance (since I couldn’t get a hold of spare parts price lists).

Most spec sheets also don’t provide an input power at min capacity, so the calculation tries to make an estimate based on the EER/COP, input power and min capacity. For those that do provide an input power at min capacity, the 2nd and 4th components within the parentheses can be made similar to the 1st and 4th components.

Ironically, I ended up choosing the AC ranked second, because of a qualitative aspect – the brand value that would have a bearing on price and availability of spare parts required outside the warranty period.