/*
* 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
*
* 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, 18]*/
(function (niviz, moment) {
'use strict';
// --- Module Dependencies ---
var Graph = niviz.Graph;
var Common = niviz.Common;
var Config = niviz.Config;
var Cartesian = niviz.Cartesian;
var Axis = niviz.Axis;
var Grid = niviz.Grid;
var t = niviz.Translate.gettext;
var round = niviz.util.round;
var hsgrid = niviz.Grid.hsgrid;
var extend = niviz.util.extend;
var nivizNode = niviz.util.nivizNode;
var format = niviz.Visuals.format;
var formatSimple = niviz.Visuals.formatSimple;
/** @module niviz */
var lbl = ['F', '4F', '1F', 'P', 'K', 'I'],
boxcolor = '#cccbea',
criticalcolor = '#F00',
parameters = {
'lwc': {
color: '#3f9397',
label: 'LWC'
},
'density': {
color: '#6dc06a',
label: 'Density\n[kg/m\u00b3]'
},
'grainsize': {
color: '#cc7b30',
label: 'Grain\nsize [mm]'
},
'grainshape': {
color: '#000',
label: 'Grain\nform'
},
'stability': {
color: '#000',
label: 'Stability\nTests'
}
};
/**
* Visualization of a singular snow profile optimized for mobile viewing.
*
* @class MobileProfile
* @constructor
* @extends Graph
*
* @param {Station} station A niViz station object
* @param {Object} canvas A svg element that will be used as SnapSVG paper
* @param {Object} properties
*/
function MobileProfile (station, canvas, properties) {
MobileProfile.uber.call(this);
if (canvas.jquery) {
this.canvasnode = canvas[0];
this.canvas = canvas;
} else {
this.canvasnode = canvas;
this.canvas = nivizNode(canvas);
}
this.canvas.empty();
this.station = station;
console.dir(this.station);
this.elements = {};
this.properties = extend({}, MobileProfile.defaults.values);
extend(this.properties, properties);
var self = this;
station.emitter.on('profile', function (object) {
self.draw(object);
});
if (this.station && this.station.profiles.length) this.draw(station.profiles[0]);
}
Graph.implement(MobileProfile, 'MobileProfile', 'profile');
MobileProfile.defaults = new Config('Mobile Profile', [
{ name: 'fontsize', type: 'number', default: 14, required: true },
{ name: 'margin_top', type: 'number', default: 0 }
]);
MobileProfile.defaults.load();
/**
* Remove a parameter from the barparams Config MobileProfile.defaults. This method is
* invoked by the settings modal when a user removes a parameter from the additional
* parameters section.
*
* @method remove
* @static
* @param {String} name Paramter name (e. g. ramm, density)
*/
MobileProfile.remove = function (name) {
var i, ii = MobileProfile.defaults.barparams.length - 1, current;
for (i = ii; i >= 0; --i) {
current = MobileProfile.defaults.barparams[i].name;
if (current === name || current === '') MobileProfile.defaults.barparams.splice(i, 1);
}
};
/**
* Deregister events
* @method destroy
*/
MobileProfile.prototype.destroy = function () {
this.station.emitter.off('profile');
};
/**
* Overwrite current properties with the ones passed as parameter.
*
* @method setProperties
* @param {Object} properties
*/
MobileProfile.prototype.setProperties = function (properties) {
extend(this.properties, MobileProfile.defaults.values);
this.draw(this.profile);
};
/**
* Configure basic properties of the MobileProfile such as font,
* height and width.
*
* @method config
* @private
*/
MobileProfile.prototype.config = function () {
var p = this.properties, station = this.station, canvas = this.canvas,
oldheight = p.height, oldwidth = p.width, profile = this.profile;
canvas.width(400);
canvas.height(600 + p.margin_top);
p.height = Math.round(canvas.height()); //container height
p.width = Math.round(canvas.width()); //container width
p.gheight = p.height - 7 * p.fontsize;
if (profile && profile.hardness) {
var nr = profile.hardness.layers.length;
canvas.height(Math.max(nr * p.fontsize * 2 + 7 * p.fontsize + p.margin_top, 600));
p.height = Math.round(canvas.height());
p.gheight = p.height - 7 * p.fontsize;
}
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.hsgrid = hsgrid(station, null, null, Common.defaults.autoscale);
p.top = 3 * p.fontsize + p.margin_top;
p.bottom = p.height - 4 * p.fontsize;
p.left = p.fontsize;
p.right = p.width - 4 * p.fontsize;
p.tempgrid = [];
if (!this.profile.info.hs) {
var tmpaxis = new Axis(this.hsgrid.min, this.hsgrid.max, p.bottom, p.top);
if (p.bottom - tmpaxis.pixel(this.profile.bottom) < 30) {
this.hsgrid = hsgrid({ top: station.top, bottom: station.bottom - 20 },
null, null, Common.defaults.autoscale);
}
}
this.cartesian = new Cartesian();
this.cartesian.addy('depth',
Math.min(Math.abs(this.hsgrid.min), Math.abs(this.hsgrid.max)),
Math.max(Math.abs(this.hsgrid.min), Math.abs(this.hsgrid.max)), p.top, p.bottom);
this.cartesian.addy('hs', this.profile.bottom, this.profile.top,
this.cartesian.py('depth',
Math.max(Math.abs(this.profile.top), Math.abs(this.profile.bottom))), p.top);
this.cartesian.addx('hardness', 0, 6, p.right, p.left);
this.cartesian.addx('density', 0, 1050, this.cartesian.px('hardness', 3), p.left);
if (profile.temperature && (profile.temperature.min || profile.temperature.min === 0)) {
var min = Math.min(Math.floor(profile.temperature.min / 10) * 10, -10);
p.tempgrid = Grid.smartLegend(min, 0);
this.cartesian.addx('temperature', p.tempgrid[0], 0, p.left, p.right);
}
p.font = {
fontSize: p.fontsize + 'px',
fill: '#000',
textAnchor: 'middle',
fontFamily: 'Helvetica, Arial'
};
if (this.elements.text) this.elements.text.remove();
this.elements.text = this.paper.g();
// console.dir(this.cartesian);
// console.dir(this.hsgrid);
// console.dir(this.paper);
};
/**
* Draw the top and bottom grid of the abscissa (user configured)
* including annotating texts.
*
* @method grid
* @private
*/
MobileProfile.prototype.grid = function () {
var p = this.properties, cartesian = this.cartesian, paper = this.paper,
i, set = paper.g(), path = paper.g(), x, y, bottom;
this.remove('grid');
// Hand hardness labels
for (i = 0; i < 7; ++i) {
x = round(cartesian.px('hardness', i), 1);
y = (!i || i === 6) ? p.top - 5 : p.bottom;
bottom = p.bottom + 5;
if (!this.profile.info.hs && i === 0) bottom = cartesian.py('hs', this.profile.bottom);
path.add(paper.line(x, y, x, bottom));
i && set.add(paper.text(x, p.bottom + 8 + p.fontsize, lbl[i - 1]).attr(p.font));
if (i === 5) { // Stability tests label
set.add(paper.multitext(x, p.bottom + 10 + 2 * p.fontsize, parameters.stability.label)
.attr(p.font).attr({ fontSize: p.fontsize - 3 + 'px' }));
} else if (i === 3) { // Stability tests label
set.add(paper.multitext(x, p.bottom + 10 + 2 * p.fontsize, parameters.lwc.label)
.attr(p.font).attr({ fontSize: p.fontsize - 3 + 'px', fill: parameters.lwc.color }));
} else if (i === 4) { // Density label
set.add(paper.multitext(x, p.bottom + 10 + 2 * p.fontsize, parameters.density.label)
.attr(p.font)
.attr({ fontSize: p.fontsize - 3 + 'px', fill: parameters.density.color }));
} else if (i === 2) { // Grainsize label
set.add(paper.multitext(x, p.bottom + 10 + 2 * p.fontsize, parameters.grainsize.label)
.attr(p.font)
.attr({ fontSize: p.fontsize - 3 + 'px', fill: parameters.grainsize.color }));
} else if (i === 1) { // Grainform label
set.add(paper.multitext(x, p.bottom + 10 + 2 * p.fontsize, parameters.grainshape.label)
.attr(p.font)
.attr({ fontSize: p.fontsize - 3 + 'px', fill: parameters.grainshape.color }));
}
}
// HS labels and legend
for (i = 0; i < this.hsgrid.divisions; ++i) {
x = (!i || i === this.hsgrid.divisions - 1) ? p.left : p.right;
y = round(cartesian.py('depth', Math.abs(this.hsgrid.heights[i])), 1);
path.add(paper.line(x, y, p.right + 5, y));
if (i === 0 && !this.profile.info.hs) continue;
set.add(paper.text(p.right + 8, y + (p.fontsize / 3),
round(Math.abs(this.hsgrid.heights[i]), 2) + '')
.attr(p.font).attr({textAnchor: 'start'}));
}
set.add(paper.text(p.width - 5, p.top + (p.bottom - p.top) / 2, t('Depth') + ' [cm]')
.attr(p.font).transform('r270,' + (p.width - 5) + ',' + (p.top + (p.bottom - p.top) / 2))
.attr({ opacity: 0.9 }));
// Temperature (snow) labels and legend
for (i = 0; i < p.tempgrid.length; ++i) {
x = round(cartesian.px('temperature', p.tempgrid[i]), 1);
path.add(paper.line(x, p.top, x, p.top - 5));
set.add(paper.text(x, p.top - p.fontsize / 2 - 5, round(p.tempgrid[i], 4) + '')
.attr(p.font));
}
set.add(paper.text(p.left + (p.right - p.left) / 2, p.top - 5 - 1.8 * p.fontsize,
t('Temperature') + ' [°C]')
.attr(p.font).attr({ opacity: 0.9 }));
this.path(false, path, set);
this.elements['grid'] = set;
};
/**
* Check if the object with identifier name exists in this.elements and
* try to remove it from the paper and then delete the object itself.
*
* @method remove
* @private
* @param {String} name Object identifier
*/
MobileProfile.prototype.remove = function (name, ctx) {
ctx = ctx || this.elements;
if (ctx[name] && ctx[name].remove) ctx[name].remove();
delete ctx[name];
};
/**
* Draw grid paths, either on the grid (light and dotted) or as solid lines.
*
* @method path
* @private
* @param {Boolean} grid true if dotted, false if solid
* @param {Array<String>} path The path to draw
* @param {Object} svg group container to append to
*/
MobileProfile.prototype.path = function (grid, path, set) {
var p = this.properties;
if (grid) {
set.add(path.attr({
'stroke-dasharray': '1,1',
'stroke': '#bdbdbd',
'opacity': 0.9,
fill: 'none'
}).transform('t0.5,0.5'));
} else {
set.add(path.attr({
'stroke': p.grid_color || '#000',
'strokeWidth': 1,
//'opacity': 0.9,
fill: 'none'
}));
}
};
/**
* Draw the snow temperature curve
*
* @method temperature
* @private
*/
MobileProfile.prototype.temperature = function () {
var profile = this.profile, data = profile.temperature, old, path = [],
paper = this.paper, i, cartesian = this.cartesian, set = paper.g(), circles = paper.g();
if (this.elements['temperature']) this.elements['temperature'].remove();
if (!data || !data.layers) return;
this.temperatures = [];
for (i = 0; i < data.layers.length; ++i) {
var current = data.layers[i];
var c = cartesian.pixel('temperature', 'hs', current.value, current.top);
circles.add(paper.circle(c.x, c.y, 2).attr({
stroke: 'black', fill: 'none', strokeWidth: 1
}));
this.temperatures.push({'c': c, 't': current.value});
if (i > 0) path.push(old.x, old.y, c.x, c.y);
old = c;
}
set.add(paper.polyline(path.join(','))
.attr({ stroke: '#f00600', fill: 'none', strokeWidth: 3 }));
set.add(circles);
this.elements['temperature'] = set;
this.elements['temperature'].after(this.elements['text']);
};
/**
* Draw the snow density curve
*
* @method density
* @private
*/
MobileProfile.prototype.density = function () {
var profile = this.profile, data = profile.density, old, path = [],
paper = this.paper, i, cartesian = this.cartesian, set = paper.g(),
p = this.properties, text = paper.g();
if (this.elements['density']) this.elements['density'].remove();
if (!data || !data.layers) return;
this.densities = [];
for (i = 0; i < data.layers.length; ++i) {
var current = data.layers[i];
var c = cartesian.pixel('density', 'hs', current.value, current.top);
var bottom = cartesian.py('hs', current.bottom);
if (i > 0) path.push(c.x, old.y, c.x, c.y);
else path.push(c.x, bottom, c.x, c.y);
text.add(paper.text(c.x - 5, bottom - (bottom - c.y) / 2 + p.fontsize / 3,
Math.round(current.value))
.attr(p.font)
.attr({fill: parameters.density.color, textAnchor: 'end', fontSize: p.fontsize - 3}));
old = c;
}
set.add(paper.polyline(path.join(','))
.attr({ stroke: parameters.density.color, fill: 'none', strokeWidth: 3 }));
this.elements['text'].add(text);
this.elements['density'] = set;
this.elements['density'].after(this.elements['text']);
};
/**
* Note snow stability tests in the graph
*
* @method stability
* @private
*/
MobileProfile.prototype.stability = function () {
var profile = this.profile, paper = this.paper, cartesian = this.cartesian,
set = paper.g(), p = this.properties, text = paper.g(), stabilites = ['ct', 'ect'];
if (this.elements['stability']) this.elements['stability'].remove();
stabilites.forEach(function (test) {
profile[test] && profile[test].layers.forEach(function (layer) {
//console.dir(layer);
var y = cartesian.py('hs', layer.top);
var ltext = layer.text;
if (test === 'ct' && layer.character) {
ltext += ' ' + layer.character || '';
}
text.add(paper.text(p.left + 10, y - 2, ltext));
set.add(paper.line(p.left + 10, y, p.right, y).attr({
'stroke-dasharray': '3,3',
'stroke': '#000',
'opacity': 0.3,
fill: 'none'
}).transform('t0.5,0.5'));
});
});
text.attr(p.font)
.attr({ fontSize: p.fontsize - 3, fontWeight: 'bold', textAnchor: 'start' });
this.elements['text'].add(text);
this.elements['stability'] = set;
this.elements['stability'].after(this.elements['text']);
};
/**
* Display the layer comments as footnotes
*
* @method comments
* @private
*/
MobileProfile.prototype.comments = function () {
var paper = this.paper, p = this.properties, text = paper.g(), references = paper.g(),
layers = this.partitions.filter(function (l) { return l.comment; }), y, self = this,
fontsize = p.fontsize - 3, formatting = { fontSize: fontsize, textAnchor: 'start' };
if (!layers.length) return;
var box = paper.text(0, 0, '').attr(p.font).attr(formatting), sum = 0;
var ignoreLibs = !!window.ignoreLibs;
layers.slice().reverse().forEach(function (layer, i) {
var currenttxt = format(box, '', layer.comment, 300);
if (ignoreLibs) currenttxt = formatSimple(layer.comment);
var mbox = paper.multitext(0, 0, currenttxt).attr(p.font).attr(formatting);
// Increase the height of the SVG canvas depending on the height of mbox
var lines = (currenttxt.match(/\n/g) || []).length + 1, h = lines * fontsize * 1.2;
if (!ignoreLibs) h = mbox.getBBox().height;
p.height = p.height + h + 0.3 * p.fontsize;
self.canvas.height(p.height);
var cy = p.bottom + 5 * p.fontsize + sum + i * 0.2 * p.fontsize;
// Numbering of comments
y = layer.ctop + p.fontsize - 4;
references.add(paper.text(p.right - 5, y, '(' + (i + 1) + ')'));
text.add(paper.text(p.left, cy, '(' + (i + 1) + ') ')
.attr(p.font).attr(formatting).attr({ textAnchor: 'middle' }));
mbox.transform('t' + (p.left + 12) + ',' + cy);
text.add(mbox);
sum += h;
});
box.remove();
references.attr(p.font).attr({ fontSize: p.fontsize - 3, textAnchor: 'end' });
this.elements['text'].add(text);
this.elements['text'].add(references);
};
/**
* Arrange the layers for best display
*
* @method arrange
* @private
*/
MobileProfile.prototype.arrange = function () {
var p = this.properties, profile = this.profile, hardness = profile.hardness,
cartesian = this.cartesian, xbottom, object,
layers = hardness.layers, nlayers = layers.length, minheight = p.fontsize * 2, i;
this.partitions = [];
var space = 0, oldy = cartesian.py('hs', profile.top);
for (i = nlayers - 1; i >= 0; --i) { // starting from the surface
var ctop = Math.round(cartesian.py('hs', layers[i].top));
var cbtm = Math.round(cartesian.py('hs', layers[i].bottom));
xbottom = null;
if (profile.hardnessBottom && profile.hardnessBottom.layers[i].value) {
xbottom = Math.round(cartesian.px('hardness', profile.hardnessBottom.layers[i].value));
}
var x = Math.round(cartesian.px('hardness', layers[i].value || 0));
var gs = '';
if (profile.grainsize.layers[i].value) {
gs += profile.grainsize.layers[i].value.avg || '';
if (profile.grainsize.layers[i].value.max
&& profile.grainsize.layers[i].value.max !== profile.grainsize.layers[i].value.avg)
gs += ' - ' + profile.grainsize.layers[i].value.max;
}
object = {
x: x, xbottom: xbottom || x, gs: gs,
code: profile.grainshape.layers[i].code || '',
fill: profile.grainshape.layers[i].color || '#FFF',
lwc: profile.wetness.layers[i].code || '',
critical: profile.critical && profile.critical.layers[i].value || null,
comment: profile.comments.layers[i].value || null
};
var diff_to_last = cbtm - oldy;
if (diff_to_last < minheight) { // just append
object.top = oldy;
object.bottom = oldy + minheight;
object.ctop = ctop;
object.cbtm = cbtm;
oldy = oldy + minheight;
} else {
space += (diff_to_last - minheight);
object.top = Math.max(oldy, ctop);
object.bottom = cbtm;
object.ctop = ctop;
object.cbtm = cbtm;
oldy = cbtm;
}
this.partitions.unshift(object);
}
this.shiftup(nlayers, minheight, space);
//console.dir(this.partitions);
};
/**
* Shift the stratigraphic layers upwards as much as possible
*
* @method shiftup
* @private
*/
MobileProfile.prototype.shiftup = function (nlayers, minheight, space) {
var tmp = null, moveup, i;
for (i = 0; i < nlayers; ++i) {
tmp = this.partitions[i];
var h = Math.round(tmp.bottom - tmp.top - minheight);
if (i < nlayers - 1) {
h = Math.round(tmp.bottom - this.partitions[i + 1].bottom - minheight);
}
if (tmp.bottom > tmp.cbtm || (i && tmp.bottom > this.partitions[i - 1].top)) {
moveup = tmp.bottom - tmp.cbtm;
if (i) moveup = Math.max(moveup, tmp.bottom - this.partitions[i - 1].top);
tmp.bottom -= Math.min(space, moveup);
}
if (h > 0) space -= h;
if (space <= 0) break;
}
// Second pass: check if all layers are high enough
for (i = 0; i < nlayers - 1; ++i) {
tmp = this.partitions[i];
if (tmp.top > tmp.ctop) {
moveup = Math.min(tmp.top - tmp.ctop, tmp.top - this.partitions[i + 1].bottom);
tmp.top -= moveup;
}
if (tmp.bottom - tmp.top < minheight) {
tmp.top = tmp.bottom - minheight;
if (this.partitions[i + 1].bottom > tmp.top) this.partitions[i + 1].bottom = tmp.top;
}
}
};
/**
* Display the hardness profile (including wetness, grain size and grain shape)
*
* @method stratigraphy
* @private
*/
MobileProfile.prototype.stratigraphy = function () {
var p = this.properties, cartesian = this.cartesian, partitions = this.partitions,
paper = this.paper, set = paper.g(), path = [], text = paper.g(), i, poly;
var xF = Math.round(cartesian.px('hardness', 1)),
middle = Math.round(xF + (p.right - xF) / 2),
x4F = Math.round(cartesian.px('hardness', 2)),
x1F = Math.round(cartesian.px('hardness', 3));
//xP = Math.round(cartesian.px('hardness', 4));
//xK = Math.round(cartesian.px('hardness', 5));
if (this.elements['stratigraphy']) this.elements['stratigraphy'].remove();
for (i = 0; i < partitions.length; ++i) {
var c = partitions[i];
path.length = 0;
path.push(c.x, c.top, xF, c.top, middle, c.ctop, p.right, c.ctop, p.right, c.cbtm,
middle, c.cbtm, xF, c.bottom, c.xbottom, c.bottom, c.x, c.top);
poly = paper.polyline(path).attr({ fill: boxcolor });
set.add(poly);
if (c.critical) this.markCriticalLayer(c, xF, middle, paper, p, set, poly);
// Add grainshape column
text.add(paper.text(xF - 5, c.top + (c.bottom - c.top) / 2 + p.fontsize / 3, c.code)
.attr({
fontSize: (p.fontsize + 3) + 'px', fill: '#000', fontWeight: 'bold',
textAnchor: 'end', fontFamily: 'snowsymbolsiacs'
}));
// Add grain size column
text.add(paper.text(x4F - 2, c.top + (c.bottom - c.top) / 2 + p.fontsize / 3, c.gs)
.attr(p.font).attr({
fill: parameters.grainsize.color, textAnchor: 'end',
fontSize: p.fontsize - 3, fontWeight: 'bold'}));
// Add wetness column
text.add(paper.text(x1F - 3, c.top + (c.bottom - c.top) / 2 + p.fontsize / 3, c.lwc)
.attr(p.font).attr({fill: parameters.lwc.color, textAnchor: 'end',
fontSize: p.fontsize - 3, fontWeight: 'bold'}));
}
set.attr({ strokeWidth: 1, stroke: '#000', opacity: 1 });
this.elements['text'].add(text);
this.elements['stratigraphy'] = set;
this.elements['stratigraphy'].after(this.elements['text']);
};
/**
* Mark critical layer
*
* @method markCriticalLayer
*/
MobileProfile.prototype.markCriticalLayer = function (c, xF, middle, paper, p, set, poly) {
var gradient, gradpath;
if (c.critical === 'top') {
var gradbtm = Math.round((c.x - c.xbottom) * (2 / 3) + c.xbottom),
ctop = Math.round(c.ctop + (c.cbtm - c.ctop) / 3),
top = Math.round(c.top + (c.bottom - c.top) / 3);
gradpath = [c.x, c.top, xF, c.top, middle, c.ctop, p.right, c.ctop,
p.right, ctop, middle, ctop, xF, top, gradbtm, top, c.x, c.top];
gradient = paper.polyline(gradpath).attr({ fill: criticalcolor, strokeWidth: 0 });
set.add(gradient);
} else if (c.critical === 'bottom'){
var gradtop = Math.round((c.x - c.xbottom) * (1 / 3) + c.xbottom),
cbtm = Math.round(c.cbtm - (c.cbtm - c.ctop) / 3),
btm = Math.round(c.bottom - (c.bottom - c.top) / 3);
gradpath = [ gradtop, btm, xF, btm, middle, cbtm, p.right, cbtm, p.right, c.cbtm,
middle, c.cbtm, xF, c.bottom, c.xbottom, c.bottom, gradtop, btm ];
gradient = paper.polyline(gradpath).attr({ fill: criticalcolor, strokeWidth: 0 });
set.add(gradient);
} else {
poly.attr({ fill: criticalcolor });
}
};
/**
* Mark soil surface
*
* @method markSoil
*/
MobileProfile.prototype.markSoil = function () {
var profile = this.profile, paper = this.paper, cartesian = this.cartesian,
set = paper.g(), p = this.properties;
this.remove('soil');
// Mark soil if possible
if (profile.info.hs) {
var y = round(cartesian.py('depth', Math.abs(this.profile.info.hs), 1));
var left = round(((p.right + cartesian.px('hardness', 1)) / 2), 1);
var lineattr = { fill: '#FFF', stroke: 'sienna', strokeWidth: 2 };
var space = Math.round((p.right - left - 2) / 4);
set.add(paper.polyline(left + space, y + 8, left, y, p.right + 5, y).attr(lineattr));
for (var i = 1; i < 4; ++i) {
set.add(paper.line(left + space * i, y, left + space * (i + 1), y + 8).attr(lineattr));
}
set.add(paper.rect(p.right + 5, y - p.fontsize * 0.7, p.fontsize * 2.7, p.fontsize * 1.4)
.attr(lineattr));
set.add(paper.text(p.right + 8, y + p.fontsize / 3, 'GND').attr(p.font)
.attr({fill: 'sienna', textAnchor: 'start'}));
}
this.elements['soil'] = set;
};
/**
* Mark that profile is not dug to ground
*
* @method zigzag
*/
MobileProfile.prototype.zigzag = function () {
var profile = this.profile, paper = this.paper, cartesian = this.cartesian,
set = paper.g(), p = this.properties;
this.remove('zigzag');
// Mark zigzag
if (!profile.info.hs) {
var y = round(cartesian.py('depth', Math.abs(this.profile.bottom), 1));
var lineattr = { fill: '#FFF', stroke: 'black', strokeWidth: 1 };
set.add(paper.polyline(p.right, p.bottom + 5, p.right, p.bottom - 10,
p.right + 15, p.bottom - 15, p.right - 15, p.bottom - 20,
p.right, p.bottom - 25, p.right, y).attr(lineattr));
}
this.elements['zigzag'] = set;
};
/**
* Draw the MobileProfile.
*
* @method draw
* @param {Profile} profile The niViz profile to render
*/
MobileProfile.prototype.draw = function (profile) {
if (profile) this.profile = profile;
this.config();
this.arrange();
try { // fail more graciously when plotting the grid
this.grid();
} catch (e) {
console.error(e);
}
this.stratigraphy();
this.density();
this.stability();
this.temperature();
this.comments();
this.markSoil();
this.zigzag();
};
// --- Helpers ---
// --- Module Exports ---
niviz.MobileProfile = MobileProfile;
}(niviz, moment));