Archive

Posts Tagged ‘Javascript’

HowTo: round a number up to N decimal digits in Javascript

Was just trying to round-off some Google Maps coordinates for display in Javascript up to 3 decimal digits and that was a bit like a blast from the past (the end of the ‘90s to be more accurate)…

So here’s my contributed answer at:
https://stackoverflow.com/questions/2221167/javascript-formatting-a-rounded-number-to-n-decimals

This works for rounding to N digits (if you just want to truncate to N digits remove the Math.round call and use the Math.trunc one):

function roundN(value, digits) {
   var tenToN = 10 ** digits;
   return /*Math.trunc*/(Math.round(value * tenToN)) / tenToN;
}

Had to resort to such logic at Java in the past when I was authoring data manipulation E-Slate components. That is since I had found out that adding 0.1 many times to 0 you’d end up with some unexpectedly long decimal part (this is due to floating point arithmetics).

A user comment at Format number to always show 2 decimal places calls this technique scaling.

Some mention there are cases that don’t round as expected and at http://www.jacklmoore.com/notes/rounding-in-javascript/ this is suggested instead:

function round(value, decimals) {
  return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}

image

HowTo: remove Javascript imports from OpenLayers map examples

OpenLayers is a fine alternative to the map visualization part of Google Maps Platform, however many of its examples sometimes use features from future and server-side Javascript versions, like “imports”.

Based on lou’s answer at https://stackoverflow.com/questions/51093964/why-examples-dont-work-a-struggle-with-imports/56549364, here’s a fix I just did to make the Marker animation example work when you just copy-paste the example code in an .html file without any pre-processing:

<head>
<meta charset="UTF-8">
<title>Marker Animation</title>
<link rel="stylesheet" href=https://openlayers.org/en/v5.3.0/css/ol.css 
type="text/css"> <!-- The line below is only needed for old environments like
Internet Explorer and Android 4.x --> src="https://cdn.polyfill.io/v2/polyfill.min.js?
features=requestAnimationFrame,Element.prototype.classList,URL">
MAKE THE ABOVE A SINGLE ROW
http://br

MAKE THE ABOVE A SINGLE ROW
</head> <body>
<label for="speed"> speed:&nbsp; <input id="speed" type="range" min="10" max="999" step="10" value="60"> </label> <button id="start-animation">Start Animation</button> <script> var Feature = ol.Feature; //import Feature from 'ol/Feature.js';
var Map = ol.Map; //import Map from 'ol/Map.js';
var View = ol.View; //import View from 'ol/View.js';
var Polyline = ol.format.Polyline;
//import Polyline from 'ol/format/Polyline.js';
var Point = ol.geom.Point; //import Point from 'ol/geom/Point.js';
var {Tile, Vector} = ol.layer;
//import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer.js'; var TileLayer = Tile; var VectorLayer = Vector;
//var BingMaps = ol.source.BingMaps;
//import BingMaps from 'ol/source/BingMaps.js';
var VectorSource = ol.source.Vector;
//import VectorSource from 'ol/source/Vector.js';
var {Circle, Fill, Icon, Stroke, Style} = ol.style;
//import {Circle as CircleStyle, Fill, Icon, Stroke, Style}
// from 'ol/style.js'; var CircleStyle = Circle; // This long string is placed here due to jsFiddle limitations. // It is usually loaded with AJAX. var polyline = [ ...

and to use an ESRI sattelite map or OpenStreetMap (plain) map instead of Bing Maps one (which requires a key), do this extra edit to the Marker animation example:

  var map = new Map({
    target: document.getElementById('map'),
    loadTilesWhileAnimating: true,
    view: new View({
      center: center,
      zoom: 10,
      minZoom: 2,
      maxZoom: 19
    }),
    layers: [
      new TileLayer({
        source:
            //new ol.source.OSM()

            new ol.source.XYZ({
              attributions: ['Powered by Esri',
                             'Source: Esri, DigitalGlobe, GeoEye, \
Earthstar Geographics, CNES/Airbus DS, USDA,\
USGS, AeroGRID, IGN, and the GIS User Community'], attributionsCollapsible: false,
url:
'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/
MapServer/tile/{z}/{y}/{x}',

MAKE THE ABOVE A SINGLE ROW
maxZoom: 23 }) /* new BingMaps({ imagerySet: 'AerialWithLabels', key: 'Bing Maps Key from http://www.bingmapsportal.com/ here' }) */ }), vectorLayer ] });

Here’s the modified result:

image

Gotcha: JS replace on document.location fails, use document location.href

This is my contribution to:
http://stackoverflow.com/questions/2652816/what-is-the-difference-between-document-location-href-and-document-location

Here is an example of the practical significance of the difference and how it can bite you if you don’t realize it (document.location being an object and document.location.href being a string):

We use MonoX Social CMS (http://mono-software.com) free version at http://social.ClipFlair.net and we wanted to add the language bar WebPart at some pages to localize them, but at some others (e.g. at discussions) we didn’t want to use localization. So we made two master pages to use at all our .aspx (ASP.net) pages, in the first one we had the language bar WebPart and the other one had the following script to remove the /lng/el-GR etc. from the URLs and show the default (English in our case) language instead for those pages

<script>
  var curAddr = document.location; //MISTAKE
  var newAddr = curAddr.replace(new RegExp("/lng/[a-z]{2}-[A-Z]{2}", "gi"), "");
  if (curAddr != newAddr)
    document.location = newAddr;
</script>

But this code isn’t working, replace function just returns Undefined (no exception thrown) so it tries to navigate to say x/lng/el-GR/undefined instead of going to url x. Checking it out with Mozilla Firefox’s debugger (F12 key) and moving the cursor over the curAddr variable it was showing lots of info instead of some simple string value for the URL. Selecting Watch from that popup you could see in the watch pane it was writing "Location -> …" instead of "…" for the url. That made me realize it was an object

One would have expected replace to throw an exception or something, but now that I think of it the problem was that it was trying to call some non-existent "replace" method on the URL object which seems to just give back "undefined" in Javascript.

The correct code in that case is:

<script>
  var curAddr = document.location.href; //CORRECT
  var newAddr = curAddr.replace(new RegExp("/lng/[a-z]{2}-[A-Z]{2}", "gi"), "");
  if (curAddr != newAddr)
    document.location = newAddr;
</script>
Categories: Posts Tags: , , , , , , ,

Gotcha: must set document.location.hash only at end of page in Mozilla

I just came across a different behaviour between IE and Mozilla Firefox: scripts at the former seem to execute after the page has fully rendered, while the later they seem to execute when they’re met by the page parser or something like that.

The HTML script tag has a defer attribute for running scripts after page has rendered, but that is available only for script tags that load an external script, not for embedded scripts in the HTML page. So this seems like one of those different interpretations that usually plague "standards". 

So, at the following JSP code, I was creating a table of student entries with a named anchor (bookmark) at each of the entries (each named per student id), so that when coming back from another page to that one I could tell it to scroll down to a given student automatically.

The issue was that if I placed the script that set document.location.hash to the student id, then at IE it worked OK, but at Mozilla Firefox it just moved to the top of the page even though the URL at the address bar of the browser had the hash entry (e.g. #55555) at the end and would scroll down correctly if I pressed Refresh button there.

Moving the script to the end of the page made it work for both IE and Mozilla Firefox. Don’t you love HTML’s "debug everywhere"?

 

<%@ page contentType="text/html" session="true" pageEncoding="UTF-8" %>

<%
response.setHeader("Cache-Control", "no-cache, no-store"); //HTTP 1.1
response.setHeader("Pragma", "no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", -1); //prevents caching at the proxy server
%>

<%@ page import="javax.portlet.*" %>
<%@ page import="java.util.ResourceBundle" %>

<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

<%
  RenderRequest renderRequest = (RenderRequest) request.getAttribute("javax.portlet.request");
  RenderResponse renderResponse = (RenderResponse) request.getAttribute("javax.portlet.response");
          

  String studentId = (String)renderRequest.getAttribute(Constants.JSP_RENDER_STUDENTID);
  if (studentId == null) studentId = "";

  <%
       for(int i = 0; i < proposalsCount_supervisor; i++) {
        IProposalListItem proposal = proposals_supervisor.getProposalListItem(i); 
   %>
  <a name="<%=proposal.getStudentId()%>"></a>
   <div class="dissertation_subsection<%=(i%2)%>">

     <div>
     ….

   <%}%>

….

<script type="text/javascript"> <%– MAKE SURE THIS IS PLACED AT THE END, ELSE IT WON’T WORK AT MOZILLA –%>
document.location.hash="<%=studentId%>"; //scroll to previously examined student
<%– alert(document.location.hash); –%>
</script>

Gotcha: var x = x() in Javascript gives “Object Expected” error

At ClipFlair Studio (a Silverlight app), I had some time ago implemented a confirmation warning upon user trying to close the webpage (when it was running inside the web browser), which then had stopped functioning. It seems at some refactoring I had added code like the following:

var activityView = activityView();

and it was failing with error “Object Expected” (and even worse this was done silently – had to use browser’s debugging tools to catch it – because the respective code was running at onbeforeunload browser window event).

Such code would be fine in C#, but in Javascript it seems that a local variable with name x hides a function named x (with any number of parameters in its definition). This is obviously because functions are first-class objects in Javascript and can be treated like variables themselves too.

All started working again fine after changing that code to:

var a = activityView();

Below is the respective block of Javascript code included in a script tag at the webpage that hosts the Silverlight control. Note the “control.content.activityWindow”, where “activityWindow”  is accessed via the Silverlight HTMLBridge (that object – that has to be marked with ScriptableType class attribute – is registered using that key via HtmlPage.RegisterScriptableObject at the Silverlight app side).

function silverlightControl() {
  return document.getElementById("silverlightControl");
}

function onSilverlightLoad(sender, args) {
  var control = silverlightControl();
  if (control != null)
    control.focus();
}

function activityWindow() {
  var control = silverlightControl();
  if ( (control != null) && (control.content != null) )
    return control.content.activityWindow;
  else
    return null; //need this so that it doesn't return undefined
}

function activityView() {
  var a = activityWindow();
  if (a != null)
    return a.GetView();
  else
    return null; //need this so that it doesn't return undefined
}

function onClosing() {
  var a = activityView();
  if ( (a != null) && (a.WarnOnClosing) )
    return "Do you want to exit ClipFlair Studio?";
//else return undefined is implied (no onClosing message that is) } function onClosed() { var a = activityView(); if (a != null) a.WarnOnClosing = false; } function installEventHandlers() { window.onbeforeunload = onClosing; window.onunload = onClosed; } installEventHandlers();
%d bloggers like this: