Files
ThirdParty-6/ParaView-5.0.1/VTK/Web/JavaScript/Widgets/CatalystBrowser/vtkweb-widget-catalyst-resampler-viewer.js

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));