/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*eslint complexity: [2, 14]*/
(function (niviz, moment) {
'use strict';
// --- Module Dependencies ---
var Graph = niviz.Graph;
var Common = niviz.Common;
var Config = niviz.Config;
var Value = niviz.Value;
var Cartesian = niviz.Cartesian;
var arrows = niviz.Visuals.Arrows;
var round = niviz.util.round;
var t = niviz.Translate.gettext;
var header = niviz.Header;
var extend = niviz.util.extend;
/** @module niviz */
/**
* Visualization of a singular snow profile SLF style.
*
* @class SLFProfile
* @constructor
*
* @extends TabularProfile
*/
function SLFProfile (station, canvas, properties) {
SLFProfile.uber.call(this, station, canvas, properties);
this.properties = extend(this.properties, SLFProfile.defaults.values);
extend(this.properties, properties);
// make sure that the children retain the right to call draw themselves
if (!(this instanceof niviz.StructureProfile)) {
this.draw(station.current || station.profiles[0]);
}
}
Graph.implement(SLFProfile, 'SLFProfile', 'profile', 'TabularProfile');
SLFProfile.defaults = new Config('SLF Profile', [
{ name: 'fontsize', type: 'number', default: 12, required: true },
{ name: 'font_color', type: 'color', default: '#000000', required: true },
{ name: 'grid_color', type: 'color', default: '#000000', required: true },
{ name: 'ramm_color', type: 'color', default: '#0000FF', required: true },
{ name: 'hardness_color', type: 'color', default: '#707070', required: true },
Common.head,
{
name: 'max_snowheight', type: 'number', default: '',
hint: 'max_snowheight_hint'
},
{
name: 'min_temperature', type: 'number', default: '',
hint: 'max_snowheight_hint'
},
Common.stability_parameters,
Common.other_parameters,
Common.show_arrows,
{ name: 'show_comment', type: 'boolean', default: true },
{ name: 'show_layer_lines', type: 'boolean', default: false },
{ name: 'print_optimized', type: 'boolean', default: false }
]);
SLFProfile.defaults.load();
SLFProfile.newton = 1000;
/**
* Deregister events
* @method destroy
*/
SLFProfile.prototype.destroy = function () {};
/**
* Overwrite current properties with the ones passed as parameter.
*
* @method setProperties
* @param {Object} properties
*/
SLFProfile.prototype.setProperties = function (properties) {
extend(this.properties, SLFProfile.defaults.values);
this.draw(this.profile);
};
/**
* Configure basic properties of the SLFProfile and the parent class TabularProfile
* such as font, table margins, height and width.
*
* @method config
* @private
*/
SLFProfile.prototype.config = function () {
var p = this.properties, station = this.station,
oldheight = p.height, oldwidth = p.width;
p.height = this.canvas.height();
p.width = this.canvas.width();
if (!this.paper || p.height !== oldheight || p.width !== oldwidth) {
if (this.paper) {
this.paper.attr({ width: p.width + 'px', height: p.height + 'px' });
} else {
this.paper = Snap(this.canvasnode);
}
}
this.paper.clear();
var max = Math.max(Number(SLFProfile.defaults.max_snowheight), 0);
if (isNaN(max) || max === 0) {
if (station.top === 0) {
max = 20;
if (this.profile.info.ta === 0 || this.profile.info.ta) max += 30;
} else {
max = Math.max(Math.floor((station.top + 90) / 50) * 50, 200);
}
}
p.margin = p.fontsize * 2;
p.table = {};
p.table.max = max;
p.table.min = station.bottom ? Math.ceil((station.bottom - 20) / 20) * 20 : 0;
p.table.range = p.table.max - p.table.min;
p.table.dock = 550; // where the interconnector starts
p.table.origin = {
x: p.table.dock + p.fontsize * 4
};
p.table.font = {
fontSize: p.fontsize + 'px',
fontFamily: 'Helvetica, Arial',
fill: p.font_color,
textAnchor: 'middle'
};
p.font = p.table.font;
this.canvas.width(Math.round(p.table.origin.x + this.table().width + 1));
p.width = this.canvas.width();
p.table.top = 4 * p.fontsize +
header.height(p, this.paper, this.profile, p.margin, p.width - p.margin - 1);
p.table.origin.y = p.table.top;
p.table.labels = {
symbol: p.table.top - p.fontsize * 2.5,
unit: p.table.top - 7 - p.fontsize / 2
};
if (p.print_optimized)
this.canvas.height(this.canvas.width() * Math.sqrt(2));
//p.height = Math.round(this.canvas.width() * Math.sqrt(2));
p.height = this.canvas.height();
this.paper.attr({ width: p.width + 'px', height: p.height + 'px' });
p.table.bottom = 4 * p.fontsize;
p.table.height = p.height - p.table.top - p.table.bottom;
p.table.origin.y = p.table.top + p.table.height;
p.origin = {
x: p.table.dock - 100,
y: p.table.top + p.table.height
};
p.left = { 'text-anchor': 'start' };
p.right = { 'text-anchor': 'end' };
};
/**
* Configure the axes for hs, hardness, temperature and the gradient parameters.
*
* @method setup
* @private
*/
SLFProfile.prototype.setup = function () {
var p = this.properties, profile = this.profile,
xright = p.origin.x, xleft = p.margin + 10;
this.cartesian = new Cartesian();
var cartesian = this.cartesian;
cartesian.addy('hs', p.table.min, p.table.max, p.origin.y, p.table.top);
cartesian.addx('hardness', 0, SLFProfile.newton, xright, xleft);
if (profile.ramm) cartesian.addx('ramm', 0, SLFProfile.newton, xright, xleft);
if (profile.temperature) {
var min = Number(SLFProfile.defaults.min_temperature);
if (isNaN(min) || min >= 0) {
min = Math.ceil(this.profile.temperature.min / 10 - 1) * 10;
min = Math.min(min, -20);
}
cartesian.addx('temperature', min, 0, xleft, xright);
if (profile.gradient) {
var max = Math.max(Math.abs(profile.gradient.min), Math.abs(profile.gradient.max));
max = Math.floor( max / 50 + 1) * 50;
cartesian.addx('gradient', -max, max, xleft, xright); //symmetrical
}
} else {
cartesian.addx('temperature', -20, 0, xleft, xright);
}
p.cliprect = [p.margin, p.table.top, p.origin.x - p.margin, p.origin.y - p.table.top];
};
/**
* Draw the comment box on the graph.
* @method comment
* @private
*/
SLFProfile.prototype.comment = function () {
var p = this.properties, paper = this.paper, profile = this.profile;
if (!profile.info.slf || !profile.info.slf.txt) return;
var tmp = '', set = paper.g(), box = paper.text(0, 0, '').attr(p.font).attr(p.left);
tmp = this.print('default', '', box, tmp);
tmp = this.print('loc', t('Location', 'comment') + ': ', box, tmp);
tmp = this.print('profile', t('Profile', 'comment') + ': ', box, tmp);
tmp = this.print('rb', t('Rutschblock', 'comment') + ': ', box, tmp);
tmp = this.print('ss', t('Snow surface', 'comment') + ': ', box, tmp);
tmp = this.print('drift', t('Snowdrift', 'comment') + ': ', box, tmp);
tmp = this.print('signals', t('Alarm signals', 'comment') + ': ', box, tmp);
tmp = this.print('avalanches', t('Avalanches', 'comment') + ': ', box, tmp);
tmp = this.print('danger', t('Danger level', 'comment') + ': ', box, tmp);
tmp = this.print('remarks', t('Remarks', 'comment') + ':', box, tmp);
tmp = this.print('confidential', t('Confidential remarks', 'comment') + ': ', box, tmp);
tmp = this.testprint(box, tmp);
box.remove(); // remove the dummy textbox
if (tmp.length !== 0) {
box = paper.multitext(p.margin + 10, p.table.top, tmp).attr(p.font).attr(p.left);
box.transform('t0,' + (p.table.top - box.getBBox().y + 3 * p.fontsize));
var width = box.getBBox().width + 10, height = box.getBBox().height + 10;
set.add(paper.rect(box.getBBox().x - 5, box.getBBox().y - 5, width, height).attr({
'fill': '#FFF',
'stroke': '#000'
}).transform('t0.5,0.5'));
box.node.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
set.add(box);
this.elements['comment'] = set;
}
};
/**
* Check if the passed stability test is ordered and if so return
* the ordered sequence.
*
* @method testorder
* @private
* @param {Feature} test CT or ECT
* @return {Array<Number>} The sequence of tests
*/
SLFProfile.prototype.testorder = function (test) {
var i, ii, order = [], ordered = true, sequence = [];
for (i = test.layers.length - 1; i >= 0; --i) {
if (test.layers[i].order === undefined) {
ordered = false;
} else {
if (sequence.indexOf(test.layers[i].order) === -1) {
for (ii = 0; ii < sequence.length; ++ii) {
if (test.layers[i].order < sequence[ii]) break;
}
sequence.splice(ii, 0, test.layers[i].order);
}
}
}
if (ordered) {
for (ii = 0; ii < sequence.length; ++ii) {
for (i = test.layers.length - 1; i >= 0; --i)
if (test.layers[i].order === sequence[ii]) order.push(i);
}
} else {
for (i = test.layers.length - 1; i >= 0; --i) order.push(i);
}
return order;
};
/**
* Print the stability test ECT and CT (comment section).
*
* @method testprint
* @private
* @param {Object} box svg text element
* @param {String} current The current comment string
* @return {String} The altered comment string
*/
SLFProfile.prototype.testprint = function (box, current) {
var tests = ['ct', 'ect'], i, flag = false, first = true;
for (i = 0; i < tests.length; ++i) {
var test = this.profile[tests[i]], ii;
if (test && test.layers && test.layers.length) {
var order = -1, sequence = this.testorder(test);
for (ii = 0; ii < sequence.length; ++ii) {
var layer = test.layers[sequence[ii]], h = layer.top ? round(layer.top, 2) : '';
if (ii === 0 && !flag) {
current = this.format(box, current, '\n');
current = this.format(box, current, '\n');
current = this.format(box, current,
t('Stability tests') + ':\n"""""""""""""""""""""\n');
flag = true;
}
if (layer.order !== undefined && layer.order !== '' && order !== layer.order) {
order = layer.order;
if (!first) current = this.format(box, current, '\n');
current += tests[i].toUpperCase() + ' #' + (layer.order + 1) + ':\n';
first = false;
}
if (test.type === 'ct') {
current = this.format(box, current,
layer.value + '@' + h + 'cm ' + (layer.comment || '') + '\n');
} else if (test.type === 'ect') {
var height = layer.top ? '@' + h + 'cm\n' : ' \n', text = layer.text;
if (Common.defaults.ECT_format === 'Swiss') text = layer.swiss || layer.text;
current = this.format(box, current, text + height);
}
}
}
}
return current;
};
/**
* Print the stability test ECT and CT (comment section).
*
* @method print
* @private
* @param {String} param Name of string within the txt object
* @param {String} lbl The label for the current text block
* @param {Object} box svg text element
* @param {String} current The current comment string
* @return {String} The altered comment string
*/
SLFProfile.prototype.print = function (param, lbl, box, current) {
var text = this.profile.info.slf.txt[param];
if (!text) return current;
if (current.length) current += '\n \n';
if (lbl) current = current + lbl + '\n';
current = this.format(box, current, text);
box.attr('text', current);
return current;
};
/**
* Actually add the addendum string by making sure it doesn't transgress the
* boundaries of the textbox.
*
* @method format
* @private
* @param {Object} textbox svg text element
* @param {String} current The current comment string
* @param {String} addendum Text string to be added
* @return {String} The altered comment string
*/
SLFProfile.prototype.format = function (textbox, current, addendum) {
addendum += '';
var words = addendum.split(/[ ]/) || [], ii, last = current.lastIndexOf('\n'), index;
if (last) last = current.substring(last);
else last = '';
for (ii = 0; ii < words.length; ++ii) {
last = last + (ii === 0 ? '' : ' ') + words[ii];
textbox.attr('text', last);
if (textbox.getBBox().width > 250) {
current += '\n' + words[ii];
last = '';
} else {
if (words[ii] === '\n') {
current += '\u200C\n';
last = '';
} else if (words[ii] === '') {
current = current;
} else {
current += (ii === 0 ? '' : ' ') + words[ii];
index = words[ii].lastIndexOf('\n');
if (index > -1) last = words[ii].substring(index);
}
}
}
return current;
};
/**
* Draw the coordinate system
* @method coordsys
* @private
*/
SLFProfile.prototype.coordsys = function () {
var cartesian = this.cartesian, p = this.properties, paper = this.paper,
ii, set = paper.g(), profile = this.profile;
if (this.elements['coordsys']) this.elements['coordsys'].remove();
var path = paper.g(), c1 = cartesian.pixel('hardness', 'hs', 0, p.table.min),
c2 = cartesian.pixel('hardness', 'hs', SLFProfile.newton, p.table.max),
legend = paper.g(), hardness = paper.g(), increment = 10, x, y;
for (ii = p.table.min; ii <= p.table.max; ii += increment) {
y = Math.round(cartesian.py('hs', ii));
if (ii > p.table.min && ii < p.table.max)
path.add(paper.line(p.table.dock - 5, y, p.margin + .5, y));
set.add(paper.text(p.table.dock + 5, y, ii).attr(p.font).attr(p.left));
legend.add(paper.line(p.table.dock + .5, Math.round(y), p.table.dock - 5, Math.round(y)));
}
increment = 100;
for (ii = 0; ii <= SLFProfile.newton; ii += increment) {
x = Math.round(cartesian.px('hardness', ii));
if (ii && ii <= SLFProfile.newton)
path.add(paper.line(x, c2.y + .5, x, c1.y - .5));
legend.add(paper.line(x, p.origin.y + .5, x, p.origin.y + 5));
legend.add(paper.line(x, p.table.top - .5, x, p.table.top - 5));
set.add(paper.text(x, p.table.top - 10, ii + '').attr(p.font));
}
set.add(path.attr({ stroke: '#bdbdbd' }).transform('t0.5,0.5'));
set.add(legend.attr({ stroke: '#000' }).transform('t0.5,0.5'));
path = ['M' + c1.x, c1.y, 'V' + c2.y, 'H' + p.margin, 'V' + c1.y, 'H' + p.table.dock];
path.push(['V' + c2.y, 'H' + c1.x]);
set.add(paper.path(path.join(',')).attr({
fill: 'none',
stroke: '#000'
}).transform('t0.5,0.5'));
for (ii = 0; ii < 5; ++ii) {
x = Math.round(cartesian.px('hardness', hhardness[ii].value));
hardness.add(paper.line(x, p.table.top + .5, x, p.table.top + 5));
set.add(paper.text(x, p.table.top + 5 + p.fontsize, hhardness[ii].text).attr(p.font));
}
set.add(hardness.attr({ stroke: '#000' }).transform('t0.5,0.5'));
set.add(paper.text(p.margin / 2, p.table.top + p.table.height / 2,
t('Snow height') + ' [cm]').attr(p.font).transform('r270'));
set.add(paper.text(p.margin + (p.origin.x - p.margin) / 2,
p.table.labels.symbol, t('Ram resistance') + ' [N]')
.attr(p.font).attr({fill: 'blue'}));
if (profile.hs === 0 || profile.height < profile.hs) { // green bar
y = cartesian.py('hs', profile.bottom);
set.add(paper.rect(p.margin - 10, y, p.origin.x - p.margin + 20, 20).
attr({stroke: 'none', fill: '#060', opacity: 0.4}));
}
this.draw_lower_legend('temperature');
this.elements['coordsys'] = set;
};
/**
* Draw legend for the curve (temperature/gradient) at the bottom of the graph.
*
* @method draw_lower_legend
* @private
* @param {String} parameter The profile parameter (e. g. temperature, gradient)
*/
SLFProfile.prototype.draw_lower_legend = function (parameter) {
var cartesian = this.cartesian, p = this.properties, paper = this.paper,
ii, set = paper.g(), profile = this.profile, increment, self = this;
if (!profile[parameter]) return;
if (this.elements['bottom']) this.elements['bottom'].remove();
increment = 100;
for (ii = 0; ii <= SLFProfile.newton; ii += increment) {
var x = cartesian.px('hardness', ii);
set.add(paper.text(x, p.origin.y + 5 + p.fontsize,
round(cartesian.coordx(parameter, x), 2) + '').attr(p.font));
}
set.add(paper.text(p.margin + (p.origin.x - p.margin) / 2,
p.origin.y + 5 + 2.5 * p.fontsize,
t(profile[parameter].name) + ' [' + profile[parameter].unit + ']')
.attr(p.font).attr({fill: 'red', cursor: 'pointer'}));
set.click(function (){
self.toggle();
});
this.elements['bottom'] = set;
};
/**
* Toggle between gradient and temperature curve.
* @method toggle
* @private
*/
SLFProfile.prototype.toggle = function () {
if (this.showgrad === undefined) this.showgrad = false;
this.showgrad = !this.showgrad;
var parameter = this.showgrad ? 'gradient' : 'temperature';
this.draw_lower_legend(parameter);
this.draw_curve(parameter);
};
/**
* Draw a parameter of the profile as a curve.
*
* @method draw_curve
* @private
* @param {String} parameter The profile parameter (e. g. temperature, gradient)
*/
SLFProfile.prototype.draw_curve = function (parameter) {
var profile = this.profile, data = profile[parameter], old, path = [],
paper = this.paper, ii, cartesian = this.cartesian, set = paper.g(),
p = this.properties;
if (this.elements['curve']) this.elements['curve'].remove();
if (!data || !data.layers) return;
this.temperatures = [];
for (ii = 0; ii < data.layers.length; ++ii) {
var current = data.layers[ii];
var c = cartesian.pixel(parameter, 'hs', current.value, current.top);
set.add(paper.circle(c.x, c.y, 2).attr({
stroke: 'red', fill: 'red', strokeWidth: 1
}));
this.temperatures.push({'c': c, 't': current.value});
if (ii > 0) path.push(old.x, old.y, c.x, c.y);
old = c;
}
if (profile.info.ta !== undefined && profile.info.ta !== '' && parameter === 'temperature') {
var d = 4;
c = cartesian.pixel('temperature', 'hs', profile.info.ta, profile.top + 40);
var ta = paper.line(old.x, old.y, c.x, c.y);
set.add(ta.attr({ stroke: 'red', strokeDasharray: '4,4' }));
var cross = paper.g();
cross.add(paper.line(c.x, c.y - d, c.x, c.y + d));
cross.add(paper.line(c.x - d, c.y, c.x + d, c.y));
set.add(cross.attr({ stroke: 'red' }));
this.temperatures.push({'c': c, 't': profile.ta});
if (profile.info.ta > 0) this.temperatures.hover = { tr: c, bl: old, ta: profile.ta };
}
set.add(paper.polyline(path.join(',')).attr({ stroke: 'red', fill: 'none' }));
set.attr({
clip: paper.rect(p.cliprect[0], p.cliprect[1], p.cliprect[2], p.cliprect[3])
});
this.elements['curve'] = set;
};
/**
* Draw a parameter of the profile as a staircase graph.
*
* @method draw_block
* @private
* @param {String} parameter The profile parameter (e. g. ramm)
* @param {String} color
* @param {String} name The name of the value of the parameter to be drawn (e. g. value)
*/
SLFProfile.prototype.draw_block = function (parameter, color, name) {
var cartesian = this.cartesian, paper = this.paper, p = this.properties,
profile = this.profile, data = profile[parameter], ii;
if (this.elements[parameter]) this.elements[parameter].remove();
if (!data || !data.layers) return;
var initial = data.layers &&
data.layers[0].bottom !== undefined ? data.layers[0].bottom : profile.bottom;
var old = cartesian.pixel(parameter, 'hs', 0, initial), path = [old.x, old.y], c;
for (ii = 0; ii < data.layers.length; ++ii) {
var current = data.layers[ii];
c = cartesian.pixel(parameter, 'hs', current[name], current.top);
if (data.layers[ii].bottom !== undefined &&
data.layers[ii].bottom === data.layers[ii].top) continue;
path.push(c.x, old.y, c.x, c.y);
old = c;
}
old = cartesian.pixel(parameter, 'hs', 0, initial);
path.push(old.x, c.y, old.x, old.y);
this.elements[parameter] = paper.polygon(path).attr({
'stroke': color,
'stroke-width': 2,
'fill': paper.hatching(color, (parameter === 'ramm' ? 0 : 90)),
'fill-opacity': 0.7,
clip: paper.rect(p.cliprect[0], p.cliprect[1], p.cliprect[2], p.cliprect[3])
});
};
/**
* Display the snow height label.
*
* @method hs
* @protected
* @param {Number} snowheight
*/
SLFProfile.prototype.hs = function (snowheight) {
var element = this.elements['hs'], text = snowheight ? round(snowheight, 3) + ' cm' : '';
if (element) {
if (!snowheight) text = '';
element.attr('text', text);
} else {
var p = this.properties, center = (p.table.dock - p.origin.x) / 2 + p.origin.x,
label = this.paper.text(center, p.table.labels.symbol, text).attr(p.font);
this.elements['hs'] = label;
}
};
/**
* Method to be called when mousemove event is detected. It calls the method
* SLFProfile:show in turn and deals with the comment box.
*
* @method mousemove
* @private
* @return {Boolean} on Turn mouse events on
*/
SLFProfile.prototype.mousemove = function (on) {
var self = this, paper = this.paper, cartesian = this.cartesian,
p = this.properties;
var c1 = cartesian.pixel('hardness', 'hs', 0, p.table.min);
var c2 = cartesian.pixel('hardness', 'hs', SLFProfile.newton, p.table.max);
if (this.overlay) this.overlay.remove();
if (on) {
this.overlay = paper.rect(c2.x - 5, c2.y - 5, c1.x - c2.x + 15, c1.y - c2.y + 20)
.attr({ 'opacity': 0.00, 'fill': '#000' })
.click(function () {
if (!self.hiddencomment && self.elements['comment']) {
self.elements['comment']
.animate({ opacity : 0 }, 500, function () { this.attr('display', 'none'); });
self.hiddencomment = true;
} else if (self.hiddencomment && self.elements['comment']) {
self.elements['comment'].attr('display', '').animate({ opacity : 1 }, 500);
self.hiddencomment = false;
}
});
this.overlay.mousemove(function (e) {
clearTimeout(this.overlaytimer);
this.overlaytimer = setTimeout( function () {
var parentOffset = self.canvas.offset();
var y = e.pageY - parentOffset.top;
var x = e.pageX - parentOffset.left;
self.show(x, y);
}, 10);
});
}
};
/**
* Build the popup for the temperature / gradient curve.
*
* @method buildpopup
* @private
* @param {Object} paper SnapSVG paper object
* @param {Object} p Properties object
* @param {String} text Popup text
* @param {Number} x Popup position x-coordinate
* @param {Number} y Popup position y-coordinate
*/
SLFProfile.prototype.buildpopup = function (paper, p, text, x, y) {
if (this.popup) this.popup.remove();
this.popup = paper.g();
var label = this.paper.text(0, 0, text).attr(p.font).attr(p.left);
var side = (x > p.margin + 50) ? 'left' : 'right';
this.popup.add(this.paper.popup(x, y, label, side, 10).attr({
fill: '#fff', stroke: '#666', 'stroke-width': 1, 'fill-opacity': .7
}));
this.popup.add(label);
};
/**
* Draw the popup for the temperature or gradient curve (whichever is present)
* if mouse cursor is close to or on data point of the curve.
*
* @method show
* @private
* @param {Number} x Mouse x-coordinate
* @param {Number} y Mouse y-coordinate
*/
SLFProfile.prototype.show = function (x, y) {
var p = this.properties, paper = this.paper, ii, success = false, text,
i = this.temperatures ? this.temperatures.length : 0,
unit = this.showgrad ? '°C/m' : '°C';
for (ii = 0; ii < i; ++ii) {
var c = this.temperatures[ii].c;
if (y < c.y + 8 && y >= c.y - 8 &&
x > c.x - 8 && x < c.x + 8) {
text = round(this.temperatures[ii].t, 2) + ' ' + unit;
this.buildpopup(paper, p, text, c.x, c.y);
success = true;
break;
}
}
if (this.temperatures && this.temperatures.hover) {
var bl = this.temperatures.hover.bl, tr = this.temperatures.hover.tr,
ta = this.temperatures.hover.ta;
if (y < bl.y && y > tr.y && x > bl.x && x < p.origin.x) {
text = t('Air temp.') + ': ' + round(ta, 2) + ' ' + unit;
this.buildpopup(paper, p, text, p.origin.x, tr.y);
success = true;
}
}
if (!success && this.popup) this.popup.remove();
};
/**
* Draw the arrows for the parameters passed.
*
* @method arrows
* @private
* @param {Array<Object>} params The parameters to be drawn
* @param {String} name Name for the svg group container, that will hold the arrows
*/
SLFProfile.prototype.arrows = function (params, name) {
if (this.elements[name]) this.elements[name].remove();
var p = this.properties, left = p.origin.x, right = p.table.dock,
set = this.paper.g(), i, ii = params.length, el,
c = this.cartesian.py.bind(this.cartesian, 'hs');
for (i = 0; i < ii; ++i) {
el = this.profile[params[i].name];
if (el && el.layers && el.layers.length) {
set.add(arrows(this, el, left, right, p.table.min, p.table.max, c));
break;
}
}
this.elements[name] = set;
};
/**
* Delete the hs, datesmall and layerlines elements.
* @method clear
* @private
*/
SLFProfile.prototype.clear = function () {
var garbage = ['hs', 'datesmall', 'layerlines'], ii;
for (ii = 0; ii < garbage.length; ++ii) {
var tmp = garbage[ii];
if (this.elements[tmp]) {
this.elements[tmp].remove();
delete this.elements[tmp];
}
}
};
/**
* Draw the SLFProfile and set up the mouse events.
* @method draw
*/
SLFProfile.prototype.draw = function (profile) {
var p = this.properties;
if (p.miniature) return;
if (profile) {
this.clear();
this.canvas.height(p.print_optimized ? 1400 : 950);
this.profile = profile;
}
this.config(); // configure table
SLFProfile.uber.prototype.draw.call(this, profile);
this.setup(); // configure graph
this.coordsys();
header.draw(this, p.margin, p.width - p.margin - 1);
this.draw_block('hardness', p.hardness_color, 'newton');
this.draw_block('ramm', p.ramm_color, 'value');
this.draw_curve('temperature');
if (p.show_comment) this.comment();
this.arrows(SLFProfile.defaults.show_arrows, 'arrows');
this.mousemove(true);
};
// --- Helpers ---
var hhardness = function () {
return [
{value: (new Value.Hardness(0, 1)).newton, text: 'F'},
{value: (new Value.Hardness(0, 2)).newton, text: '4F'},
{value: (new Value.Hardness(0, 3)).newton, text: '1F'},
{value: (new Value.Hardness(0, 4)).newton, text: 'P'},
{value: (new Value.Hardness(0, 5)).newton, text: 'K'}
];
}();
// --- Module Exports ---
niviz.SLFProfile = SLFProfile;
}(niviz, moment));