mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
414 lines
16 KiB
JavaScript
414 lines
16 KiB
JavaScript
(function ($, GLOBAL) {
|
|
var CONTENT_TEMPLATE = '<div class="toolbar"><span class="label">Field<select name="field">FIELDS</select></span><span class="label">Probe<select name="probe"><option value="0">X</option><option value="1">Y</option><option value="2">Z</option></select></span> Slice <span class="slice-value txt-feedback">0</span> Time <span class="time-value txt-feedback">0</span></div><div class="control"><div class="header"><span class="vtk-icon-tools toggle"/><span class="vtk-icon-play play"/><span class="vtk-icon-stop stop"/></div><div class="parameters"><div class="label" data-name="slice"><span class="flag vtk-icon-flag"/>Slice<span class="slice-value">0</span></div><input type="range" min="0" max="NB_SLICES" value="0" name="slice"/><div class="label" data-name="time"><span class="flag vtk-icon-flag"/>Time<span class="time-value">0</span></div><input type="range" min="0" max="NB_TIMES" value="0" name="time"/></div></div><div class="image-sample" style="padding: 10px;"><canvas style="border: solid 1px black;"><img/></canvas></div><div class="chart-sample"></div>',
|
|
OPTION_TEMPLATE = '<option>VALUE</option>';
|
|
|
|
// ========================================================================
|
|
// Helper
|
|
// ========================================================================
|
|
|
|
function getFileName(filePattern, args) {
|
|
var fileName = filePattern;
|
|
for(key in args) {
|
|
fileName = fileName.replace('{'+key+'}', args[key]);
|
|
}
|
|
return fileName;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
function getOptions(values) {
|
|
var buffer = [];
|
|
for(var idx in values) {
|
|
buffer.push(OPTION_TEMPLATE.replace('VALUE', values[idx]));
|
|
}
|
|
return buffer.join('\n');
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
function update(container) {
|
|
var field = $('select[name="field"]', container).val(),
|
|
slice = $('input[name="slice"]', container).val(),
|
|
time = $('input[name="time"]', container).val(),
|
|
probeAxis = $('select[name="probe"]', container).val();
|
|
|
|
downloadJSON(container, slice, probeAxis, field, time);
|
|
downloadImage(container, slice, field, time);
|
|
}
|
|
|
|
// ========================================================================
|
|
// Download manager
|
|
// ========================================================================
|
|
|
|
function downloadJSON(container, slice, probeAxis, field, time) {
|
|
var sliceList = [],
|
|
cache = container.data('json-cache'),
|
|
info = container.data('info'),
|
|
basepath = container.data('base-path'),
|
|
urls = [];
|
|
|
|
if(probeAxis === "2") {
|
|
sliceList = info['arguments']['slice']['values'];
|
|
} else {
|
|
sliceList.push(slice);
|
|
}
|
|
|
|
function updateChart(){
|
|
if(0 === urls.length) {
|
|
container.trigger('invalidate-chart');
|
|
}
|
|
}
|
|
|
|
function download(fileName) {
|
|
$.getJSON( basepath + '/' + fileName, function(data){
|
|
cache[fileName] = data;
|
|
if(urls.length > 0) {
|
|
download(urls.pop());
|
|
} else {
|
|
updateChart();
|
|
}
|
|
}).fail(function(e){
|
|
console.log('Fail to download ' + fileName);
|
|
console.log(e);
|
|
});
|
|
}
|
|
|
|
// Fill download queue
|
|
for(var idx in sliceList) {
|
|
var fileName = getFileName(info['name_pattern'], {'field': field, 'slice': sliceList[idx], 'time': time, 'format': 'json'});
|
|
if(!cache.hasOwnProperty(fileName)) {
|
|
urls.push(fileName);
|
|
}
|
|
}
|
|
|
|
// Trigger download or update chart
|
|
if(urls.length > 0) {
|
|
download(urls.pop());
|
|
} else {
|
|
updateChart();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
function downloadImage(container, slice, field, time) {
|
|
var info = container.data('info'),
|
|
basepath = container.data('base-path'),
|
|
fileName = getFileName(info['name_pattern'], {'field': field, 'slice': slice.toString(), 'time': time, 'format': 'jpg'}),
|
|
img = $('img', container);
|
|
img.attr('src', basepath + '/' + fileName);
|
|
}
|
|
|
|
// ========================================================================
|
|
// Chart management
|
|
// ========================================================================
|
|
|
|
function updateChart(container) {
|
|
var cache = container.data('json-cache'),
|
|
info = container.data('info'),
|
|
probe = container.data('probe-coord'),
|
|
field = $('select[name="field"]', container).val(),
|
|
slice = Number($('input[name="slice"]', container).val()),
|
|
time = $('input[name="time"]', container).val(),
|
|
probeAxis = $('select[name="probe"]', container).val(),
|
|
fileName = getFileName(info['name_pattern'], {'field': field, 'slice': slice, 'time': time, 'format': 'json'}),
|
|
size = [0,0,0],
|
|
offset = 0, step = 0, nbSteps = 0, data = [],
|
|
chartContainer = $(".chart-sample", container);
|
|
|
|
if(cache[fileName] === undefined) {
|
|
return;
|
|
}
|
|
size = cache[fileName]["dimensions"];
|
|
|
|
function clamp(value) {
|
|
return (value == null || value < -1e10) ? null : value;
|
|
}
|
|
|
|
if(probe === undefined) {
|
|
return;
|
|
}
|
|
|
|
// Figure out way to traverse
|
|
if(probeAxis === '0') {
|
|
// Along X
|
|
nbSteps = size[0];
|
|
step = 1;
|
|
offset = (size[1] - probe[1]) * size[0];
|
|
} else if(probeAxis === '1') {
|
|
// Along Y
|
|
nbSteps = size[1];
|
|
step = size[0];
|
|
offset = probe[0];
|
|
} else if(probeAxis === '2') {
|
|
// Along Z
|
|
nbSteps = size[2];
|
|
step = -1;
|
|
offset = probe[0] + (size[1] - probe[1]) * size[0];
|
|
}
|
|
|
|
// Extract data
|
|
if(probeAxis === '2') {
|
|
sliceList = info['arguments']['slice']['values'];
|
|
// Need multi-files
|
|
for(var idx in sliceList) {
|
|
f = getFileName(info['name_pattern'], {'field': field, 'slice': sliceList[idx], 'time': time, 'format': 'json'});
|
|
sliceDataField = cache[f][field];
|
|
data.push({x: Number(idx), y: clamp(sliceDataField[offset])})
|
|
}
|
|
} else if(probeAxis === '1') {
|
|
// Same slice
|
|
sliceDataField = cache[fileName][field];
|
|
for(var i = 0; i < nbSteps; ++i) {
|
|
data.push({x: i, y: clamp(sliceDataField[offset + (i*step)])})
|
|
}
|
|
} else if(probeAxis === '0') {
|
|
// Same slice
|
|
sliceDataField = cache[fileName][field];
|
|
for(var i = 0; i < nbSteps; ++i) {
|
|
data.push({x: i, y: clamp(sliceDataField[offset + (i*step)])})
|
|
}
|
|
}
|
|
|
|
// Update UI with chart
|
|
if(chartContainer.hasClass('vtk-chart')) {
|
|
// Update
|
|
chartContainer.vtkChartUpdateData([ { data: data, color: 'steelblue', name: field } ], true);
|
|
chartContainer.vtkChartConfigure({'chart-padding': [0, 0, 0, 0]});
|
|
} else {
|
|
// Create chart
|
|
chartContainer.vtkChart({
|
|
'legend': {basic: false, toggle: false, highlight: false},
|
|
'renderer': 'line',
|
|
'series': [ { data: data, color: 'steelblue', name: field } ],
|
|
'axes': [ "bottom", "left", "top"],
|
|
'chart-padding': [0, 0, 0, 0]
|
|
});
|
|
}
|
|
}
|
|
|
|
// ========================================================================
|
|
// Listeners
|
|
// ========================================================================
|
|
|
|
function initializeListeners(container) {
|
|
// Attach redraw callback
|
|
var canvas = $('canvas', container),
|
|
chartContainer = $('.chart-sample', container),
|
|
image = $('img', container),
|
|
enableProbing = false,
|
|
startSliding = false,
|
|
sliders = $('input', container),
|
|
timeSlider = $('input[name="time"]', container),
|
|
sliceSlider = $('input[name="slice"]', container),
|
|
timeTxt = $('span.time-value', container),
|
|
sliceTxt = $('span.slice-value', container),
|
|
activeSlider = null;
|
|
dropDowns = $('select', container),
|
|
currentSlideValue = 0,
|
|
maxSlideValue = 1,
|
|
keepAnimation = false,
|
|
play = $('.play', container),
|
|
stop = $('.stop', container);
|
|
|
|
function animate() {
|
|
if(activeSlider) {
|
|
currentSlideValue = (currentSlideValue + 1) % maxSlideValue;
|
|
activeSlider.val(currentSlideValue);
|
|
if(keepAnimation) {
|
|
setTimeout(animate, 150);
|
|
}
|
|
updateAll();
|
|
}
|
|
}
|
|
|
|
// Generic data update
|
|
function updateAll() {
|
|
timeTxt.html(timeSlider.val());
|
|
sliceTxt.html(sliceSlider.val());
|
|
update(container);
|
|
paint();
|
|
}
|
|
|
|
// Callback methods to probe data
|
|
function probe(event) {
|
|
if(enableProbing) {
|
|
var offset = canvas.offset(),
|
|
z = $('input[name="slice"]', container).val(),
|
|
scale = image[0].naturalWidth / canvas.width();
|
|
container.data('probe-coord',
|
|
[Math.floor(scale*(event.pageX - offset.left)), Math.floor(scale*(event.pageY - offset.top)), Number(z)]);
|
|
updateAll();
|
|
}
|
|
}
|
|
|
|
// Callback methods to paint image
|
|
function paint() {
|
|
if(image[0].naturalWidth == 0) {
|
|
setTimeout(paint, 100);
|
|
return;
|
|
}
|
|
|
|
var ctx = canvas[0].getContext("2d"),
|
|
w = canvas.parent().width(),
|
|
img = image[0],
|
|
ih = img.naturalHeight,
|
|
iw = img.naturalWidth,
|
|
ratio = ih / iw,
|
|
scale = iw / w,
|
|
headHeight = canvas.offset().top - container.offset().top + 22,
|
|
probePoint = container.data('probe-coord');
|
|
|
|
canvas.css('left', '20px').attr('width', w + 'px').attr('height', Math.ceil(w*ratio) + 'px');
|
|
chartContainer.css('width', '100%').css('height', (container.height() - Math.ceil(w*ratio) - headHeight) + 'px');
|
|
ctx.drawImage(image[0],
|
|
0, // source image upper left x
|
|
0, // source image upper left y
|
|
iw, // source image width
|
|
ih, // source image height
|
|
0, // destination canvas upper left x
|
|
0, // destination canvas upper left y
|
|
canvas.width(), // destination canvas width
|
|
canvas.height()); // destination canvas height
|
|
|
|
// Draw line
|
|
if(probePoint) {
|
|
var probeAxis = $('select[name="probe"]', container).val();
|
|
ctx.strokeStyle = "#000000";
|
|
ctx.fillStyle="#FFFFFF";
|
|
if(probeAxis === '0') {
|
|
// Along X
|
|
var y = probePoint[1] / scale;
|
|
ctx.rect(0,y,canvas.width(), Math.ceil(scale));
|
|
ctx.stroke();
|
|
ctx.fill();
|
|
} else if(probeAxis === '1') {
|
|
// Along Y
|
|
var x = probePoint[0] / scale;
|
|
ctx.rect(x,scale,Math.ceil(scale),canvas.height());
|
|
ctx.stroke();
|
|
ctx.fill();
|
|
} else if(probeAxis === '2') {
|
|
// Along Z
|
|
var x = probePoint[0] / scale, y = probePoint[1] / scale;
|
|
ctx.beginPath();
|
|
ctx.arc(x,y,5,0,2*Math.PI);
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Attach probing listeners
|
|
canvas.bind('mousemove', probe);
|
|
canvas.bind('mouseup', function(){ enableProbing = false; });
|
|
canvas.bind('mousedown', function(e){
|
|
enableProbing = true;
|
|
probe(e);
|
|
});
|
|
|
|
// Attach auto-paint listener
|
|
image.bind('load onload', paint);
|
|
|
|
// Attach graph update
|
|
container.bind('invalidate-chart', function(){
|
|
updateChart(container);
|
|
});
|
|
|
|
// Attach dropDowns listeners
|
|
dropDowns.bind('change', updateAll);
|
|
|
|
// Attach slider listener
|
|
sliders.bind('change keyup', updateAll);
|
|
sliders.bind('mousedown', function(){
|
|
startSliding = true;
|
|
});
|
|
sliders.bind('mouseup', function(){
|
|
startSliding = false;
|
|
});
|
|
sliders.bind('mousemove', function(){
|
|
if(startSliding) {
|
|
updateAll();
|
|
}
|
|
});
|
|
|
|
$('div.label', container).click(function(){
|
|
var me = $(this),
|
|
all = $('.label', container);
|
|
|
|
activeSlider = $('input[name="' + me.attr('data-name') + '"]', container);
|
|
|
|
if(activeSlider) {
|
|
currentSlideValue = Number(activeSlider.val());
|
|
maxSlideValue = Number(activeSlider.attr('max'));
|
|
|
|
// Handle flag visibility
|
|
all.removeClass('active');
|
|
me.addClass('active');
|
|
}
|
|
});
|
|
|
|
$('.toggle', container).click(function(){
|
|
container.toggleClass('small');
|
|
});
|
|
|
|
play.click(function(){
|
|
play.hide();
|
|
stop.show();
|
|
keepAnimation = true;
|
|
animate();
|
|
});
|
|
stop.click(function(){
|
|
stop.hide();
|
|
play.show();
|
|
keepAnimation = false;
|
|
});
|
|
}
|
|
|
|
// ========================================================================
|
|
// JQuery
|
|
// ========================================================================
|
|
|
|
/**
|
|
* jQuery catalyst view constructor.
|
|
*
|
|
* @member jQuery.vtkCatalystViewer
|
|
* @param basePath
|
|
* Root directory for data to visualize
|
|
*/
|
|
|
|
$.fn.vtkCatalystResamplerViewer = function(dataBasePath) {
|
|
return this.each(function() {
|
|
var me = $(this).empty().addClass('vtk-catalyst-resample-viewer small').unbind();
|
|
|
|
// Get meta-data
|
|
$.ajax({
|
|
url: dataBasePath + '/info.json',
|
|
dataType: 'json',
|
|
success: function( data ) {
|
|
// Store metadata
|
|
me.data('info', data);
|
|
me.data('active-args', {});
|
|
me.data('json-cache', {});
|
|
me.data('base-path', dataBasePath);
|
|
|
|
// Create UI
|
|
me.html(CONTENT_TEMPLATE
|
|
.replace('FIELDS', getOptions(data['arguments']['field']['values']))
|
|
.replace('NB_SLICES', data['arguments']['slice']['values'].length-1)
|
|
.replace('NB_TIMES', data['arguments']['time']['values'].length-1)
|
|
);
|
|
initializeListeners(me);
|
|
|
|
// Load data
|
|
update(me);
|
|
},
|
|
error: function(error) {
|
|
console.log("error when trying to download " + dataBasePath + '/info.json');
|
|
console.log(error);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
}(jQuery, window)); |