--------------------------------------------------------------------------------
problems:

--------------------------------------------------------------------------------
working on:

--------------------------------------------------------------------------------
to do:

-- simplify niceScale() and niceScaleFitting() after octave m-files scaletick_*.m
   -- note that real2eng() can take care of harmonisation for the display of a series of numbers
   -- remove formatReal() and formatRealSplit() in favour of real2eng()
      or: simplify input/output records so that formatReal() output directly corresponds with output of real2eng()
   -- improve accordingly formatRealOrDatetime()

-- easy boolean to switch on/off automatic selection of linestyles and/or markers (in a default ordre)
  data["fig"][ifig]["tab"][itab][field]
  data["fig"][ifig][field] ifnot:
  data[field] ifnot:
  defaults[field] = 0 or 1;
  
  field = "autolinestyle" or "automarkerstyle"
  
   implement this in hplot.m too!

-- possible simplification:
   -- restrict "commondatakey", "commondatacolumn" and "datetimecommon" only for common data which is not on x axis
   -- introduce "commondataonxaxis" (instead of ...commondatakey = "=xdata") when x axis data is also common data

-- ensure null, NaN/false for x data points in js function plot()
   bisnan = ( isNaN(bx) || isNaN(by) || (bx === false) || (by === false) )
   bisnull = ( (bx === null) || (by === null) )

-- apply simplifications from hplot() used for autocolour etc. 

-- filled x data & empty y data --> ensure that nothing is plotted (apart from title)

-- implement markernumber

-- fast read of data by reading it as json by a json string read function: object = JSON.parse(code)
   -- note that NaN, Inf are not allowed, but null, false and true are!
   -- no single quotes are allowed, only "
   ==> line break indicated by Inf in octave, null in js
       ignoring   indicated by NaN in octave, NaN or false in js

-- button panel
   -- preference zoom, given by data["fig"][ifig]["xlimpref"] = [1,2] and data["fig"][ifig]["ylimpref"] = [2,3]

-- switch to put display values in legend off

-- fast write of matrices hplot_to_html()
   -- hplot_to_html(p1,p2,...) in p2.matrix1 = [...]
   -- or: p.fig{2}.matrix1 = [...]
          p.fig{2}.ismatrix = {"matrix1"}
   -- or: p.fig{3}.matrix1__m = [...] <-- special suffix is kept!
   -- or: use switch and ismatrix() in var2json() and print matrix at once without indentation!
      -- rename value2json()

-- atg plot 
   -- data["fig"][ifig]["overlay"] = "atl" (atg) --> just extra graphical lines (overlay) and fields (underlay !)
   -- data["fig"][ifig]["atl_count"] = true
      --> table next to figure:
           D- C- B A C+ D+ outside D C B A
           10                              ser0 all
           %
           10                              ser0 select
           %
      --> calculation at init: data["fig"][ifig]["_atl_count"] = [1, 2, 3;...] --> reference to fields in graph per series

-- mollier
   -- add rho lines
   -- print (X,F,H,...) values at mouse pointer below legend

-- mouse pointer -> closest based on sqrt( (delta x)^2 + (delta y)^2 )
                         --> may cause problems if one realy wants to find by x first!
                         ==> extra checkbox (take delta y into account, or not) in button panel

-- legend:
   -- colspan for first two rows: <th colspan="2">headline 1</th>
   
-- check and improve markerskip

-- implement second transformation: from converted data axis system and units
                                    to projected data axis system and units
                 (xp,yp) := projectionfunction(xc,yc)
   --> log-log, ln-ln, lin-log, etc.

-- visibility of series does not affect y axis range --> as an option !

-- visibility does affect drawing of pointer circle

-- pointed x axis value --> nearest x axis value --> show corresponding y axis value
   problem: sometimes line goes flat/horizontal
   but: -- better: nearest two x axis values (before _and_ after pointed x axis value)
                   to determine y axis range and better display
        -- interpolation?

-- add new possible value for xlim1 in scaleFigures(igrp,ifig1,xlim1,xlim2)
   if isNaN(xlim1) --> all data
   if xlim1 == null --> redraw for actual/previously xlim1,xlim2 values 
                        --> practical when series are set to visible again

-- prepareFigureTable(): is a check for same address when commononxaxis == true needed?
   if so, add it.

-- move defaults to data["_defaults"] ?
   -- apply simplifications from hplot.m used for getdata(), getdataaddress() etc. 

--------------------------------------------------------------------------------
there are three types of figure groups:

-1- figures with xdatakey="c", ydatakey="y", commondatakey="c",      commononxaxis=true,  commongiven=true
      ==> x axis range change influences all figures in the same figure group
      data["_grp"][igrp]["csorted"]
      data["_grp"][igrp]["ysorted"]
      data["_grp"][igrp]["xminmax"]
      data["fig"][ifig]["_yminmax"]

    figures with xdatakey="x", ydatakey="y", commondatakey="c",      commononxaxis=false, commongiven=true
      ==> x axis range change at this figure has no effect on other figures in the figure group
      ==> x axis range change at another figure of c,y-type influences displayd points
      data["fig"][ifig]["_xminmax"]
      data["fig"][ifig]["_yminmax"]
      
      also series with xdatakey="x", ydatakey="y", commondatakey="", commononxaxis=false, commongiven=false

-2- figures with xdatakey="c", ydatakey="y", commondatakey="c",      commononxaxis=true,  commongiven=true
      ==> x axis range change influences all figures in the same figure group
      data["_grp"][igrp]["csorted"]
      data["_grp"][igrp]["ysorted"]
      data["_grp"][igrp]["xminmax"]
      data["fig"][ifig]["_yminmax"]

      also series with xdatakey="x", ydatakey="y", commondatakey="", commononxaxis=false, commongiven=false

-3- figure with xdatakey="x", ydatakey="y", commondatakey="",        commononxaxis=false, commongiven=false
      ==> figure group contains only one figure !
      data["fig"][ifig]["_xminmax"]
      data["fig"][ifig]["_yminmax"]

--------------------------------------------------------------------------------
structure of global variable data:

  data["fig"][ifig]["title"] = "<b>abc</b>";
    -- string of html code
    -- if not given, defaults["title"] = ""
  data["fig"][ifig]["caption"] = "<b>abc</b>";
    -- string of html code
    -- if not given, defaults["caption"] = ""

  data["fig"][ifig]["group"] = "abc";
    -- string
    -- if not given, defaults["group"] = ""
    -- if empty string, the figure constitues its own group

  data["fig"][ifig]["xdatakey"] = "x"
  data["fig"][ifig]["tab"][itab]["xdatakey"] = "x"
    -- string
    -- if not given, defaults["xdatakey"] = "x"

  data["fig"][ifig]["ydatakey"] = "y"
  data["fig"][ifig]["tab"][itab]["ydatakey"] = "x"
    -- string
    -- if not given, defaults["ydatakey"] = "y"

  data["fig"][ifig]["commondatakey"] = "c"
  data["fig"][ifig]["tab"][itab]["commondatakey"] = "c"
    -- string
    -- if "=xdata", data....["xdatakey"] and data....["xdatacolumn"] are taken instead
    -- if not given, defaults["commondatakey"] = ""

  data["fig"][ifig]["datetimeonxaxis"] = true/false
  data["fig"][ifig]["datetimecommon"] = true/false
  data["fig"][ifig]["tab"][itab]["datetimecommon"] = true/false
    -- boolean
    -- false by default
    -- must be set to true, if x axis or common data are in ms since 1970-01-01 00:00:00.0000 (unix epoch)
    -- may be set to true, if x axis or common data are given by separate columns for year, month etc.
    -- in the latter case, it is needed to input: 
         data[...]["xdatacolumn"] = { ye: icol, mo: icol, ... }
       or
         data[...]["commondatacolumn"] = { ye: icol, mo: icol, ... }

  data["fig"][ifig]["xdataconversion"] = ""
  data["fig"][ifig]["tab"][itab]["xdataconversion"] = ""
    -- string with values "" or "temp<temp", ...
    -- if not given, defaults["xdataconversion"] = ""

  data["fig"][ifig]["ydataconversion"] = ""
  data["fig"][ifig]["tab"][itab]["ydataconversion"] = ""
    -- string with values "" or "hum<rehum", ...
    -- if not given, defaults["ydataconversion"] = ""

  data["fig"][ifig]["xaxisprojection"] = "lin"
    -- string with values "" or "lin"
    -- if not given, defaults["xaxisprojection"] = "lin"
  data["fig"][ifig]["yaxisprojection"] = "lin"
    -- string with values '' or "lin"
    -- if not given, defaults["yaxisprojection"] = "lin"

  data["fig"][ifig]["rotated"] = true/false
    -- boolean
    -- if not given, defaults["rotated"] = false

  data[j]                           = [ [...], [...], ...]
  data["fig"][ifig][j]              = [ [...], [...], ...]
  data["fig"][ifig]["tab"][itab][j] = [ [...], [...], ...]
    -- needed
    -- two-dimensional array with data for x axis, y axis and common
    -- let j = data["fig"][ifig]["xdatakey"] or data["fig"][ifig]["ydatakey"] or data["fig"][ifig]["commondatakey"], respectively
    -- searched for in priority

  data["fig"][ifig]["tab"][itab]["legend"] = [ "abc", "abc", ...];
    -- array of strings
  data["fig"][ifig]["tab"][itab]["style"] = [ {...}, {...}, ...];
    -- array of records with (optional) fields "colour", "line", "linewidth", "isstep", "marker", "markerskip", "markerscale"

  data["xdatacolumn"] = [ 0 ];
  data["commondatacolumn"] = [ 0 ];
  data["fig"][ifig]["xdatacolumn"] = [ 0 ];
  data["fig"][ifig]["commondatacolumn"] = [ 0 ];
  data["fig"][ifig]["tab"][itab]["xdatacolumn"] = [ 0 ];
  data["fig"][ifig]["tab"][itab]["ydatacolumn"] = [ 0 ];
  data["fig"][ifig]["tab"][itab]["commondatacolumn"] = [ 0 ];
    -- optional (only needed when x axis, y axis and/or common data are all in the same data array)
    -- array of indices for refering to column(s) in the data array contained in the respective field j
    -- searched for in priority

  data["xdatacolumn"] = { ye: icol, mo: icol, da: icol, ho: icol, mi: icol, se: icol, ms: icol };
  data["commondatacolumn"] = { ye: icol, mo: icol, da: icol, ho: icol, mi: icol, se: icol, ms: icol };
  data["fig"][ifig]["xdatacolumn"] = { ye: icol, mo: icol, ... };
  data["fig"][ifig]["commondatacolumn"] = { ye: icol, mo: icol, ... };
  data["fig"][ifig]["tab"][itab]["xdatacolumn"] = { ye: icol, mo: icol, ... };
  data["fig"][ifig]["tab"][itab]["commondatacolumn"] = { ye: icol, mo: icol, ... };
    -- needed if x axis data or common data are given by separate columns for year, month etc.
    -- if icol is an integer number, the value of the date-time element will found in column icol
    -- if icol is a string, the number obtained by parsing the string will be filled in as fixed value for the respective date-time element

--------------------------------------------------------------------------------
window.onload = function()

  set global variable use_svg_symbol

  for ifig ---> ensureSvgElem(ifig)
  for ifig ---> prepareFigure(ifig)
  for ifig ---> drawFigure(ifig)
  for igrp ---> analyseSeries(igrp)
                drawSeries(igrp)
  for igrp ---> scaleFigures(igrp,-1,NaN,NaN)

--------------------------------------------------------------------------------
function prepareFigure(ifig)

  setting:
    data["fig"][ifig]["_numero"] = numero;
    data["fig"][ifig]["_special"] = special;
    data["fig"][ifig]["_air"] = airprop;
    data["fig"][ifig]["_xaxisprojection"] = xaxisprojection;
    data["fig"][ifig]["_yaxisprojection"] = yaxisprojection;
    data["fig"][ifig]["_group"] = group;
    data["fig"][ifig]["_igrp"] = igrp;
    
    data["fig"][ifig]["_xlabel"] = getdata(ifig,-1,["xlabel"]).value;
    data["fig"][ifig]["_ylabel"] = getdata(ifig,-1,["ylabel"]).value;
    data["fig"][ifig]["_xunit"] = getdata(ifig,-1,["xunit"]).value;
    data["fig"][ifig]["_yunit"] = getdata(ifig,-1,["yunit"]).value;

  for itab --> prepareFigureTable(ifig,itab)

--------------------------------------------------------------------------------
function prepareFigureTable(ifig,itab)

  setting:
    data["fig"][ifig]["_commononxaxis"] = commononxaxis;

    data["fig"][ifig]["_datetimeonxaxis"] = datetimeonxaxis;

    data["fig"][ifig]["_datetimecommon"] = datetimecommon;
    
    data["_iserallcur"]
    data["_grp"][igrp]["isergrpcur"]
    data["fig"][ifig]["_iserfigcur"]

        data["fig"][ifig]["_isergrp"].push( isergrp );
  
        data["_grp"][igrp]["figures"] = pushunique(data["_grp"][igrp]["figures"],ifig);
        
        if (dataconversion["psychro"] == true) {
          ....
          dataconversion_psychro(x,icolx,y,icoly,dataconversion["xy"],Pb,Pbdatacolumn,ifig,iserfigs[icol]);
          ....
        }
        
        data["_grp"][igrp]["series"].push({
                              igrp: igrp,
                              ifig: ifig,
                              itab: itab,
                              icolx: xdatacolumn[0],
                              icoly: ydatacolumn[icol],
                              icolc: commondatacolumn[0],
                              iserfig: iserfigs[icol],
                              isergrp: isergrp,
                              iserall: iserall,
                              xdatakey: xdatakey,
                              ydatakey: ydatakey,
                              commondatakey: commondatakey,
                              commononxaxis: commononxaxis,
                              commongiven: commongiven,
                              datetimeonxaxis: datetimeonxaxis,
                              datetimecommon: datetimecommon,
                              xdataconversion: xdataconversion,
                              ydataconversion: ydataconversion,
                              xaxisprojection: xaxisprojection,
                              yaxisprojection: yaxisprojection,
                              xaddress: xaddress.slice(),
                              yaddress: yaddress.slice(),
                              caddress: caddress.slice(),
                              Pbaddress: Pbaddress,
                              Pbdatacolumn: Pbdatacolumn,
                              legend: legends[icol],
                              colour: styles[icol]["colour"],
                              line: styles[icol]["line"],
                              linewidth: styles[icol]["linewidth"],
                              isstep: styles[icol]["isstep"],
                              marker: styles[icol]["marker"],
                              markerskip: styles[icol]["markerskip"],
                              markerscale: styles[icol]["markerscale"],
                              markerdefid: "", // filled in in drawSeries(igrp) only if needed
                              displayed: true
                             });

--------------------------------------------------------------------------------
function drawFigure(ifig)

  setting:
     data["fig"][ifig]["_rotated"]
     data["fig"][ifig]["_axisbox"] = { x : axisboxleftmargin,
                                       y : axisboxtopmargin,
                                       width : axisboxwidth,
                                       height : axisboxheight,
                                     };
     data["fig"][ifig]["_spaces"]
     data["fig"][ifig]["_width"]
     data["fig"][ifig]["_height"]
     data["fig"][ifig]["_graphictransform"]
     data["fig"][ifig]["_axistransform"]
     data["fig"][ifig]["_xthreshold"]
     data["fig"][ifig]["_veil"]
     data["fig"][ifig]["_seriespointer"]
     data["fig"][ifig]["_xaxis"]
     data["fig"][ifig]["_yaxis"]
     data["fig"][ifig]["_legend"]
     data["fig"][ifig]["_Faxis"]
     data["fig"][ifig]["_Haxis"]
     
   creating
     -- definition group
     -- clip-path
     -- figure background rectangle
     -- axis background rectangle
     -- axis-clippath group
     -- axis-transform group
     -- x/y-axis-grid groups
     -- x/y-axis-tick-text groups
     -- dummy tick text group (with dummy texts)
     -- data["fig"][ifig]["_axisticktextboxsizes"]
     -- x/y axis labels
     -- veil
     -- mouse pointer
     -- mouse event object
     -- first two rows in the legend
     -- buttons
   print the title and caption texts
   setSpacing(ifig)

--------------------------------------------------------------------------------
function plot(seriesgroup,series,clim1,clim2,graphictransform)

--------------------------------------------------------------------------------
function analyseSeries(igrp)

  for isergrp
     setting:
       -- if data["fig"][ifig]["_commononxaxis"] == true: 
          data["_grp"][igrp]["csorted"] = c;
          data["_grp"][igrp]["ysorted"] = y;
          data["_grp"][igrp]["xminmax"] = xminmax;
       -- if data["fig"][ifig]["_commononxaxis"] == false: 
          data["fig"][ifig]["_xminmax"] = xminmax;
       -- data["fig"][ifig]["_yminmax"] = yminmax;
       
  for ifig
     setting: data["fig"][ifig]["_graphictransformation"]
     
--------------------------------------------------------------------------------
function drawSeries(igrp)

  for isergrp
     create marker definition
     draw lines and markers: plot(serieslinegroup,seriesmarkergroup,series,NaN,NaN,graphictransform);
     draw (invisible) series pointers
     print legend
     
  for ifig
     add buttons for view periods if date-time on x axis

--------------------------------------------------------------------------------
function scaleFigures(igrp,ifig1,xlim1,xlim2)
  /*
     -- when x axis value range is given at ("calling") figure ifig1:
        -- the range must be implemented to the x axes of every 
           figure (of type "c,y") within the group 
           -- to which ifig1 belongs and 
           -- for which the x axis is common (commononxaxis == true).
        -- the range must be implemented to the data points of every 
           figure (of type "x,y,c") within the group 
           -- to which ifig1 belongs and 
           -- for which the x axis is not common (commononxaxis == false 
                                                  && commongiven == true).

     -- when x axis value range is given with ifig1=-1, so for the whole figure group:
        -- for all figures within the figure group
           for which the x axis is common (commononxaxis == true):
           -- the range is found by all x axis data together 
           -- the range is implemented for all concerning figures
        -- for each figure within the figure group
           for which the x axis is not common (commononxaxis == false):
           -- the range is found by the x axis data of the concerning figure 
           -- the range is implemented for of the concerning figure
  
   */

  // it is called within: 
  // -- window.onload()
  //      --> for igrp
  //            scaleFigures(igrp,-1,NaN,NaN)
  // -- zoomExtentsFigures(ifig0)
  //      --> for igrp
  //            scaleFigures(igrp,-1,NaN,NaN)
  // -- onMouseUp(evt,ifig)
  //      --> scaleFigures(data["fig"][ifig]["_igrp"],ifig,x1,x2);

  for ifig
    select y by given x1 and x2
    scaleSeries(igrp,ifig,xminmaxwin,yminmaxwin)

--------------------------------------------------------------------------------
function scaleFigurey(igrp,ifig,ylim1,ylim2) {

    scaleSeries(igrp,ifig,xminmaxwin,yminmaxwin)

--------------------------------------------------------------------------------
function scaleSeries(igrp,ifig,xminmaxwin,yminmaxwin)

    calculate axis transformation
    draw grid lines
    print tick texts
    rescale markers
    drawPsychro(ifig)
    setSpacing(ifig)   

--------------------------------------------------------------------------------
function drawPsychro(ifig)

  plot F and H grid lines and tick texts
  
  add checkboxes for visibility of F and H axes
    
--------------------------------------------------------------------------------
function printvaluesFigures(igrp,ifig1,xc,yc)

  // it is called within: 
  // -- zoomExtentsFigures(ifig0)
  //      --> for igrp
  //            printvaluesFigures(igrp,-1,NaN,NaN)
  // -- onMouseUp(evt,ifig)
  //      --> if mouseDownStart.line
  //            printvaluesFigures(data["fig"][ifig]["_igrp"],ifig,(x1+x2)/2,(y1+y2)/2)
  //          else
  //            for igrp
  //              printvaluesFigures(igrp,-1,NaN,NaN)

  for ifig
    find the x and y values closest to xc
    write x axis value to element with id=name + ":legend:x:left/right:ser" + String(igrp) + "," + String(isergrp[iiser])
    write y axis value to element with id=name + ":legend:y:left/right:ser" + String(igrp) + "," + String(isergrp[iiser])
    set series pointers

--------------------------------------------------------------------------------
function zoomExtentsFigures(ifig0)

  unset_mouseDownStart()
  for iigrp
    igrp = groups[iigrp];
    set the veil of all figures in group to total transparency
    make visible all series in the figure group
    scaleFigures(igrp,-1,NaN,NaN)
    printvaluesFigures(igrp,-1,NaN,NaN)

--------------------------------------------------------------------------------
function changeAxisVisibility(visible,axis,ifig)

--------------------------------------------------------------------------------
function toggleAxisVisibility(checkbox,axis,ifig)

  --> changeAxisVisibility(checked,axis,ifig);

--------------------------------------------------------------------------------
function changeVisibility(visible,igrp,isergrp)

  --> changeVisibility(visible,igrp,isergrp[iiser]);
      
  --> checkbox = document.getElementById(name + ":legend:visibility:ser" + String(igrp) + "," + String(isergrp[iiser]));
      checkbox.checked = visible;

--------------------------------------------------------------------------------
function toggleVisibility(checkbox,igrp,isergrp)

  --> changeVisibility(visible,igrp,isergrp)  

--------------------------------------------------------------------------------
function setVisibilityFigure(ifig,visible)

--------------------------------------------------------------------------------
function retrieveMouseCoord(evt,svg)

--------------------------------------------------------------------------------
function mouseCoordToFigureCoord(xm,ym,ifig)

--------------------------------------------------------------------------------
function figureCoordToDataCoord(xf,yf,ifig)

--------------------------------------------------------------------------------
function unset_mouseDownStart()

--------------------------------------------------------------------------------
function set_mouseDownStart(mousecoord,ifig)

--------------------------------------------------------------------------------
function drawVeil(ifig,name,xf1,xf2)

--------------------------------------------------------------------------------
function onMouseEnter(evt,ifig)
  unset_mouseDownStart()

--------------------------------------------------------------------------------
function onMouseMove(evt,ifig)
  if ! isNaN(mouseDownStart.xm)
    drawVeil(ifig,name,mouseDownStart.xf,actualMouseCoordf.x)

--------------------------------------------------------------------------------
function onMouseDown(evt,ifig)
  if isNaN(mouseDownStart.xm)
    set_mouseDownStart(actualMouseCoordm,ifig)
    drawVeil(ifig,name,mouseDownStart.xf,mouseDownStart.xf)

--------------------------------------------------------------------------------
function onMouseUp(evt,ifig)
  if (actualMouseCoordf.inaxisrectangle)
    if (mouseDownStart.line)
      printvaluesFigures(data["fig"][ifig]["_igrp"],ifig,(x1+x2)/2,(y1+y2)/2)
    else
      set the veil to total transparency
      scaleFigures(data["fig"][ifig]["_igrp"],ifig,x1,x2)
      printvaluesFigures(data["fig"][ifig]["_igrp"],-1,NaN,NaN)
  unset_mouseDownStart()

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
notes & do-not-forget:

-- it is impossible to refer to a css class within an other css class definition, or extend one css class by another one !
   but class definitions may be disperged, e.g.:
                 .klasse { background-color: yellow; }
                 .klasse { color: red; border: 2px solid black; }
                 .klasse { font-family: sans-serif;}
-- https://www.w3.org/TR/SVGTiny12/ --> no markers
   https://www.w3.org/TR/SVG11/
-- complete use of option line markers:
      -- note: https://www.w3.org/TR/svg-markers/
               marker-segment (= marker inbetween two points on path)
               marker-pattern (= marker along the path at fixed distances)
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
   new Date(ms_since_19700101);
   new Date(dateString);
   new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
   Date.prototype.toISOString()
    Converts a date to a string following the ISO 8601 Extended Format.
   Date.prototype.toTimeString()
    Returns the "time" portion of the Date as a human-readable string. 
   Date.prototype.valueOf()
    Returns the primitive value of a Date object. Overrides the Object.prototype.valueOf() method. 
   Date.prototype.setTime()
    Sets the Date object to the time represented by a number of milliseconds since January 1, 1970, 00:00:00 UTC, allowing for negative numbers for times prior.    
    
    dt = new Date(2019,06,07,15,32,00,0)
    >> Date 2019-07-07T13:32:00.000Z   // time shift CET -> UTC
    
    dt = Date.UTC(2019,06,07,15,32,00,0)
    >> 1562513520000
    new Date(dt)
    >> Date 2019-07-07T15:32:00.000Z // no time shift
    
    a = new Date(dt)
    >> Date 2019-07-07T15:32:00.000Z

    a.toISOString()
    >> "2019-07-07T15:32:00.000Z"
-- <use xlink:href="#..."...> is not accepted, but the href attribute is accepted.
   --> perhaps xlink:href attribute is accepted for
       <svg xmlns="http://www.w3.org/2000/svg"
            xmlns:xlink="http://www.w3.org/1999/xlink" ...>
   --> which is correct notation?
       -- https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href
          Deprecated since SVG 2
          SVG 2 removed the need for the xlink namespace, so instead of xlink:href you should use href.
-- Contrary to Firefox, Chrome does not accept (i.e. in Chrome, the following has no tranformation effect at all):
   <symbol ... transform="....">
     ...
   </symbol>
   But the following has the expected transformation effect in Chrome (and Firefox):
   <symbol ... >
    <g transform="....">
     ...
    </g>
   </symbol>
--------------------------------------------------------------------------------
