2023-02-22 02:59:40 +03:00
|
|
|
const sources = {
|
|
|
|
"rainbow":"../data/testpattern.dzi",
|
|
|
|
"leaves":"../data/iiif_2_0_sizes/info.json",
|
|
|
|
"bblue":{
|
|
|
|
type:'image',
|
|
|
|
url: "../data/BBlue.png",
|
|
|
|
},
|
2023-03-11 19:38:21 +03:00
|
|
|
"duomo":"https://openseadragon.github.io/example-images/duomo/duomo.dzi",
|
|
|
|
}
|
|
|
|
const labels = {
|
|
|
|
rainbow: 'Rainbow Grid',
|
|
|
|
leaves: 'Leaves',
|
|
|
|
bblue: 'Blue B',
|
|
|
|
duomo: 'Duomo',
|
2023-02-22 02:59:40 +03:00
|
|
|
}
|
2023-09-26 16:31:43 +03:00
|
|
|
const drawers = {
|
|
|
|
canvas: "Context2d drawer (default in OSD <= 4.1.0)",
|
2023-11-21 22:53:06 +03:00
|
|
|
webgl: "New WebGL drawer"
|
2023-09-26 16:31:43 +03:00
|
|
|
}
|
|
|
|
|
2024-10-17 22:06:04 +03:00
|
|
|
const viewportMargins = {
|
2024-10-25 20:15:52 +03:00
|
|
|
left: 100,
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 50,
|
2024-10-17 22:06:04 +03:00
|
|
|
};
|
|
|
|
|
2023-09-26 16:31:43 +03:00
|
|
|
//Support drawer type from the url
|
|
|
|
const url = new URL(window.location.href);
|
|
|
|
const drawer1 = url.searchParams.get("left") || 'canvas';
|
|
|
|
const drawer2 = url.searchParams.get("right") || 'webgl';
|
|
|
|
|
|
|
|
$("#title-w1").html(drawers[drawer1]);
|
|
|
|
$("#title-w2").html(drawers[drawer2]);
|
2023-03-13 22:56:04 +03:00
|
|
|
|
2023-06-30 23:06:17 +03:00
|
|
|
//Double viewer setup for comparison - CanvasDrawer and WebGLDrawer
|
2023-06-30 04:55:59 +03:00
|
|
|
// viewer1: canvas drawer
|
2023-06-27 04:29:08 +03:00
|
|
|
let viewer1 = window.viewer1 = OpenSeadragon({
|
2023-06-30 04:55:59 +03:00
|
|
|
id: "canvasdrawer",
|
2023-02-22 02:59:40 +03:00
|
|
|
prefixUrl: "../../build/openseadragon/images/",
|
2023-03-06 00:08:32 +03:00
|
|
|
minZoomImageRatio:0.01,
|
2023-03-11 19:38:21 +03:00
|
|
|
maxZoomPixelRatio:100,
|
|
|
|
smoothTileEdgesMinZoom:1.1,
|
|
|
|
crossOriginPolicy: 'Anonymous',
|
2023-03-12 18:42:03 +03:00
|
|
|
ajaxWithCredentials: false,
|
2023-06-27 04:29:08 +03:00
|
|
|
// maxImageCacheCount: 30,
|
2023-09-26 16:31:43 +03:00
|
|
|
drawer:drawer1,
|
2023-11-30 00:46:14 +03:00
|
|
|
blendTime:0,
|
|
|
|
showNavigator:true,
|
2024-10-17 22:06:04 +03:00
|
|
|
viewportMargins,
|
2023-02-22 02:59:40 +03:00
|
|
|
});
|
|
|
|
|
2023-06-29 23:41:45 +03:00
|
|
|
// viewer2: webgl drawer
|
2023-06-27 04:29:08 +03:00
|
|
|
let viewer2 = window.viewer2 = OpenSeadragon({
|
|
|
|
id: "webgl",
|
2023-06-07 17:16:21 +03:00
|
|
|
prefixUrl: "../../build/openseadragon/images/",
|
|
|
|
minZoomImageRatio:0.01,
|
2023-06-27 04:29:08 +03:00
|
|
|
maxZoomPixelRatio:100,
|
|
|
|
smoothTileEdgesMinZoom:1.1,
|
2023-06-07 17:16:21 +03:00
|
|
|
crossOriginPolicy: 'Anonymous',
|
2023-06-27 04:29:08 +03:00
|
|
|
ajaxWithCredentials: false,
|
|
|
|
// maxImageCacheCount: 30,
|
2023-09-26 16:31:43 +03:00
|
|
|
drawer:drawer2,
|
2023-06-29 23:41:45 +03:00
|
|
|
blendTime:0,
|
2023-11-30 00:46:14 +03:00
|
|
|
showNavigator:true,
|
2024-10-17 22:06:04 +03:00
|
|
|
viewportMargins,
|
2023-06-29 23:41:45 +03:00
|
|
|
});
|
|
|
|
|
2023-09-26 16:31:43 +03:00
|
|
|
// // viewer3: html drawer, unused
|
2023-11-30 01:35:49 +03:00
|
|
|
var viewer3 = window.viewer3 = OpenSeadragon({
|
|
|
|
id: "htmldrawer",
|
|
|
|
drawer:'html',
|
|
|
|
blendTime:2,
|
|
|
|
prefixUrl: "../../build/openseadragon/images/",
|
|
|
|
minZoomImageRatio:0.01,
|
|
|
|
customDrawer: OpenSeadragon.HTMLDrawer,
|
|
|
|
tileSources: [sources['leaves'], sources['rainbow'], sources['duomo']],
|
|
|
|
sequenceMode: true,
|
|
|
|
crossOriginPolicy: 'Anonymous',
|
|
|
|
ajaxWithCredentials: false
|
|
|
|
});
|
2023-06-29 23:41:45 +03:00
|
|
|
|
|
|
|
|
2023-06-27 04:29:08 +03:00
|
|
|
// Sync navigation of viewer1 and viewer 2
|
|
|
|
var viewer1Leading = false;
|
|
|
|
var viewer2Leading = false;
|
|
|
|
|
|
|
|
var viewer1Handler = function() {
|
|
|
|
if (viewer2Leading) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewer1Leading = true;
|
|
|
|
viewer2.viewport.zoomTo(viewer1.viewport.getZoom());
|
|
|
|
viewer2.viewport.panTo(viewer1.viewport.getCenter());
|
|
|
|
viewer2.viewport.rotateTo(viewer1.viewport.getRotation());
|
|
|
|
viewer2.viewport.setFlip(viewer1.viewport.flipped);
|
|
|
|
viewer1Leading = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
var viewer2Handler = function() {
|
|
|
|
if (viewer1Leading) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewer2Leading = true;
|
|
|
|
viewer1.viewport.zoomTo(viewer2.viewport.getZoom());
|
|
|
|
viewer1.viewport.panTo(viewer2.viewport.getCenter());
|
|
|
|
viewer1.viewport.rotateTo(viewer2.viewport.getRotation());
|
|
|
|
viewer1.viewport.setFlip(viewer1.viewport.flipped);
|
|
|
|
viewer2Leading = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
viewer1.addHandler('zoom', viewer1Handler);
|
|
|
|
viewer2.addHandler('zoom', viewer2Handler);
|
|
|
|
viewer1.addHandler('pan', viewer1Handler);
|
|
|
|
viewer2.addHandler('pan', viewer2Handler);
|
|
|
|
viewer1.addHandler('rotate', viewer1Handler);
|
|
|
|
viewer2.addHandler('rotate', viewer2Handler);
|
|
|
|
viewer1.addHandler('flip', viewer1Handler);
|
|
|
|
viewer2.addHandler('flip', viewer2Handler);
|
|
|
|
|
|
|
|
|
2023-02-22 02:59:40 +03:00
|
|
|
$('#image-picker').sortable({
|
|
|
|
update: function(event, ui){
|
2023-06-27 04:29:08 +03:00
|
|
|
let thisItem = ui.item.find('.toggle').data('item1');
|
|
|
|
let items = $('#image-picker input.toggle:checked').toArray().map(item=>$(item).data('item1'));
|
2023-02-22 02:59:40 +03:00
|
|
|
let newIndex = items.indexOf(thisItem);
|
|
|
|
if(thisItem){
|
2023-06-27 04:29:08 +03:00
|
|
|
viewer1.world.setItemIndex(thisItem, newIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
thisItem = ui.item.find('.toggle').data('item2');
|
|
|
|
items = $('#image-picker input.toggle:checked').toArray().map(item=>$(item).data('item2'));
|
|
|
|
newIndex = items.indexOf(thisItem);
|
|
|
|
if(thisItem){
|
|
|
|
viewer2.world.setItemIndex(thisItem, newIndex);
|
2023-02-22 02:59:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-03-11 19:38:21 +03:00
|
|
|
Object.keys(sources).forEach((key, index)=>{
|
|
|
|
let element = makeImagePickerElement(key, labels[key])
|
|
|
|
$('#image-picker').append(element);
|
|
|
|
if(index === 0){
|
|
|
|
element.find('.toggle').prop('checked',true);
|
|
|
|
}
|
|
|
|
})
|
2023-02-22 02:59:40 +03:00
|
|
|
|
2023-09-26 16:31:43 +03:00
|
|
|
$('#image-picker').append(makeComparisonSwitcher());
|
|
|
|
|
2023-02-22 02:59:40 +03:00
|
|
|
$('#image-picker input.toggle').on('change',function(){
|
|
|
|
let data = $(this).data();
|
|
|
|
if(this.checked){
|
2023-06-27 04:29:08 +03:00
|
|
|
addTileSource(viewer1, data.image, this);
|
2023-06-27 04:44:03 +03:00
|
|
|
addTileSource(viewer2, data.image, this);
|
2023-02-22 02:59:40 +03:00
|
|
|
} else {
|
2023-06-27 04:29:08 +03:00
|
|
|
if(data.item1){
|
|
|
|
viewer1.world.removeItem(data.item1);
|
2023-06-27 04:44:03 +03:00
|
|
|
viewer2.world.removeItem(data.item2);
|
2023-06-27 04:29:08 +03:00
|
|
|
$(this).data({item1: null, item2: null});
|
2023-02-22 02:59:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}).trigger('change');
|
|
|
|
|
|
|
|
$('#image-picker input:not(.toggle)').on('change',function(){
|
|
|
|
let data = $(this).data();
|
|
|
|
let value = $(this).val();
|
2023-06-27 04:29:08 +03:00
|
|
|
let tiledImage1 = $(`#image-picker input.toggle[data-image=${data.image}]`).data('item1');
|
|
|
|
let tiledImage2 = $(`#image-picker input.toggle[data-image=${data.image}]`).data('item2');
|
|
|
|
updateTiledImage(tiledImage1, data, value, this);
|
|
|
|
updateTiledImage(tiledImage2, data, value, this);
|
|
|
|
});
|
|
|
|
|
|
|
|
function updateTiledImage(tiledImage, data, value, item){
|
2023-10-23 17:03:47 +03:00
|
|
|
let field = data.field;
|
|
|
|
|
2023-02-22 02:59:40 +03:00
|
|
|
if(tiledImage){
|
|
|
|
//item = tiledImage
|
|
|
|
if(field == 'x'){
|
|
|
|
let bounds = tiledImage.getBoundsNoRotate();
|
|
|
|
let position = new OpenSeadragon.Point(Number(value), bounds.y);
|
|
|
|
tiledImage.setPosition(position);
|
|
|
|
} else if ( field == 'y'){
|
|
|
|
let bounds = tiledImage.getBoundsNoRotate();
|
|
|
|
let position = new OpenSeadragon.Point(bounds.x, Number(value));
|
|
|
|
tiledImage.setPosition(position);
|
|
|
|
} else if (field == 'width'){
|
|
|
|
tiledImage.setWidth(Number(value));
|
|
|
|
} else if (field == 'degrees'){
|
|
|
|
tiledImage.setRotation(Number(value));
|
|
|
|
} else if (field == 'opacity'){
|
|
|
|
tiledImage.setOpacity(Number(value));
|
|
|
|
} else if (field == 'flipped'){
|
2023-06-27 04:29:08 +03:00
|
|
|
tiledImage.setFlip($(item).prop('checked'));
|
2023-03-06 00:08:32 +03:00
|
|
|
} else if (field == 'cropped'){
|
2023-06-27 04:29:08 +03:00
|
|
|
if( $(item).prop('checked') ){
|
2023-07-09 19:05:17 +03:00
|
|
|
let scale = tiledImage.source.width;
|
|
|
|
let croppingPolygons = [ [{x:0.2*scale, y:0.2*scale}, {x:0.8*scale, y:0.2*scale}, {x:0.5*scale, y:0.8*scale}] ];
|
2023-03-06 00:08:32 +03:00
|
|
|
tiledImage.setCroppingPolygons(croppingPolygons);
|
|
|
|
} else {
|
|
|
|
tiledImage.resetCroppingPolygons();
|
|
|
|
}
|
|
|
|
} else if (field == 'clipped'){
|
2023-06-27 04:29:08 +03:00
|
|
|
if( $(item).prop('checked') ){
|
2023-07-09 19:05:17 +03:00
|
|
|
let scale = tiledImage.source.width;
|
|
|
|
let clipRect = new OpenSeadragon.Rect(0.1*scale, 0.2*scale, 0.6*scale, 0.4*scale);
|
2023-03-06 00:08:32 +03:00
|
|
|
tiledImage.setClip(clipRect);
|
|
|
|
} else {
|
|
|
|
tiledImage.setClip(null);
|
|
|
|
}
|
2023-10-23 17:03:47 +03:00
|
|
|
} else if (field == 'debug'){
|
2023-06-27 04:29:08 +03:00
|
|
|
if( $(item).prop('checked') ){
|
2023-03-06 00:08:32 +03:00
|
|
|
tiledImage.debugMode = true;
|
|
|
|
} else {
|
|
|
|
tiledImage.debugMode = false;
|
|
|
|
}
|
2023-02-22 02:59:40 +03:00
|
|
|
}
|
2023-10-23 17:03:47 +03:00
|
|
|
} else {
|
|
|
|
//viewer-level option
|
2023-02-22 02:59:40 +03:00
|
|
|
}
|
2023-06-27 04:29:08 +03:00
|
|
|
}
|
2023-03-06 00:08:32 +03:00
|
|
|
|
|
|
|
$('.image-options select[data-field=composite]').append(getCompositeOperationOptions()).on('change',function(){
|
|
|
|
let data = $(this).data();
|
2023-06-27 04:29:08 +03:00
|
|
|
let tiledImage1 = $(`#image-picker input.toggle[data-image=${data.image}]`).data('item1');
|
|
|
|
if(tiledImage1){
|
|
|
|
tiledImage1.setCompositeOperation(this.value == 'null' ? null : this.value);
|
|
|
|
}
|
|
|
|
let tiledImage2 = $(`#image-picker input.toggle[data-image=${data.image}]`).data('item2');
|
|
|
|
if(tiledImage2){
|
|
|
|
tiledImage2.setCompositeOperation(this.value == 'null' ? null : this.value);
|
2023-03-06 00:08:32 +03:00
|
|
|
}
|
|
|
|
}).trigger('change');
|
|
|
|
|
|
|
|
$('.image-options select[data-field=wrapping]').append(getWrappingOptions()).on('change',function(){
|
|
|
|
let data = $(this).data();
|
2023-06-27 04:29:08 +03:00
|
|
|
let tiledImage = $(`#image-picker input.toggle[data-image=${data.image}]`).data('item1');
|
|
|
|
if(tiledImage){
|
|
|
|
switch(this.value){
|
|
|
|
case "None": tiledImage.wrapHorizontal = tiledImage.wrapVertical = false; break;
|
|
|
|
case "Horizontal": tiledImage.wrapHorizontal = true; tiledImage.wrapVertical = false; break;
|
|
|
|
case "Vertical": tiledImage.wrapHorizontal = false; tiledImage.wrapVertical = true; break;
|
|
|
|
case "Both": tiledImage.wrapHorizontal = tiledImage.wrapVertical = true; break;
|
|
|
|
}
|
2023-11-30 00:46:14 +03:00
|
|
|
tiledImage.redraw();//trigger a redraw for the webgl renderer.
|
2023-06-27 04:29:08 +03:00
|
|
|
}
|
|
|
|
tiledImage = $(`#image-picker input.toggle[data-image=${data.image}]`).data('item2');
|
2023-03-06 00:08:32 +03:00
|
|
|
if(tiledImage){
|
|
|
|
switch(this.value){
|
|
|
|
case "None": tiledImage.wrapHorizontal = tiledImage.wrapVertical = false; break;
|
|
|
|
case "Horizontal": tiledImage.wrapHorizontal = true; tiledImage.wrapVertical = false; break;
|
|
|
|
case "Vertical": tiledImage.wrapHorizontal = false; tiledImage.wrapVertical = true; break;
|
|
|
|
case "Both": tiledImage.wrapHorizontal = tiledImage.wrapVertical = true; break;
|
|
|
|
}
|
2023-11-30 00:46:14 +03:00
|
|
|
tiledImage.redraw();//trigger a redraw for the webgl renderer.
|
2023-03-06 00:08:32 +03:00
|
|
|
}
|
|
|
|
}).trigger('change');
|
|
|
|
|
|
|
|
function getWrappingOptions(){
|
|
|
|
let opts = ['None', 'Horizontal', 'Vertical', 'Both'];
|
|
|
|
let elements = opts.map((opt, i)=>{
|
|
|
|
let el = $('<option>',{value:opt}).text(opt);
|
|
|
|
if(i===0){
|
|
|
|
el.attr('selected',true);
|
|
|
|
}
|
|
|
|
return el[0];
|
|
|
|
// $('.image-options select').append(el);
|
|
|
|
});
|
|
|
|
return $(elements);
|
|
|
|
}
|
|
|
|
function getCompositeOperationOptions(){
|
|
|
|
let opts = [null,'source-over','source-in','source-out','source-atop',
|
|
|
|
'destination-over','destination-in','destination-out','destination-atop',
|
|
|
|
'lighten','darken','copy','xor','multiply','screen','overlay','color-dodge',
|
|
|
|
'color-burn','hard-light','soft-light','difference','exclusion',
|
|
|
|
'hue','saturation','color','luminosity'];
|
|
|
|
let elements = opts.map((opt, i)=>{
|
|
|
|
let el = $('<option>',{value:opt}).text(opt);
|
|
|
|
if(i===0){
|
|
|
|
el.attr('selected',true);
|
|
|
|
}
|
|
|
|
return el[0];
|
|
|
|
// $('.image-options select').append(el);
|
|
|
|
});
|
|
|
|
return $(elements);
|
|
|
|
|
|
|
|
}
|
2023-02-22 02:59:40 +03:00
|
|
|
|
2023-06-27 04:29:08 +03:00
|
|
|
function addTileSource(viewer, image, checkbox){
|
2023-02-22 02:59:40 +03:00
|
|
|
let options = $(`#image-picker input[data-image=${image}][type=number]`).toArray().reduce((acc, input)=>{
|
|
|
|
let field = $(input).data('field');
|
|
|
|
if(field){
|
|
|
|
acc[field] = Number(input.value);
|
|
|
|
}
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
options.flipped = $(`#image-picker input[data-image=${image}][data-type=flipped]`).prop('checked');
|
|
|
|
|
|
|
|
let items = $('#image-picker input.toggle:checked').toArray();
|
|
|
|
let insertionIndex = items.indexOf(checkbox);
|
|
|
|
|
|
|
|
let tileSource = sources[image];
|
|
|
|
if(tileSource){
|
2023-06-27 04:29:08 +03:00
|
|
|
viewer&&viewer.addTiledImage({tileSource: tileSource, ...options, index: insertionIndex});
|
|
|
|
viewer&&viewer.world.addOnceHandler('add-item',function(ev){
|
2023-02-22 02:59:40 +03:00
|
|
|
let item = ev.item;
|
2023-06-27 04:29:08 +03:00
|
|
|
let field = viewer === viewer1 ? 'item1' : 'item2';
|
|
|
|
$(checkbox).data(field,item);
|
2023-06-30 23:06:17 +03:00
|
|
|
// item.source.hasTransparency = ()=>true; //simulate image with transparency, to show seams in default renderer
|
2023-02-22 02:59:40 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-26 16:31:43 +03:00
|
|
|
function getAvailableDrawerSelect(name, selectedDrawer) {
|
|
|
|
return `
|
|
|
|
<select name="${name}">
|
|
|
|
${Object.entries(drawers).map(([k, v]) => {
|
|
|
|
const selected = selectedDrawer === k ? "selected" : "";
|
|
|
|
return `<option value="${k}" ${selected}>${v}</option>`;
|
|
|
|
}).join("\n")}
|
|
|
|
</select>`;
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeComparisonSwitcher() {
|
|
|
|
const left = getAvailableDrawerSelect("left", drawer1),
|
|
|
|
right = getAvailableDrawerSelect("right", drawer2);
|
|
|
|
return `
|
|
|
|
<div>
|
|
|
|
Note: you can run the comparison with desired drawers like this: drawercomparison.html?left=[type]&right=[type]
|
|
|
|
<form method="get">
|
|
|
|
${left}
|
|
|
|
${right}
|
|
|
|
<button>Submit</button>
|
|
|
|
</form>
|
|
|
|
</div>`;
|
|
|
|
}
|
|
|
|
|
2023-03-11 19:38:21 +03:00
|
|
|
function makeImagePickerElement(key, label){
|
|
|
|
return $(`<div class="image-options">
|
|
|
|
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
|
|
|
|
<label><input type="checkbox" data-image="" class="toggle"> __title__</label>
|
|
|
|
<div class="option-grid">
|
|
|
|
<label>X: <input type="number" value="0" data-image="" data-field="x"> </label>
|
|
|
|
<label>Y: <input type="number" value="0" data-image="" data-field="y"> </label>
|
|
|
|
<label>Width: <input type="number" value="1" data-image="" data-field="width" min="0"> </label>
|
|
|
|
<label>Degrees: <input type="number" value="0" data-image="" data-field="degrees"> </label>
|
|
|
|
<label>Opacity: <input type="number" value="1" data-image="" data-field="opacity" min="0" max="1" step="0.2"> </label>
|
2023-07-09 19:05:17 +03:00
|
|
|
<span></span>
|
2023-03-11 19:38:21 +03:00
|
|
|
<label>Flipped: <input type="checkbox" data-image="" data-field="flipped"></label>
|
|
|
|
<label>Cropped: <input type="checkbox" data-image="" data-field="cropped"></label>
|
2023-07-09 19:05:17 +03:00
|
|
|
<label>Clipped: <input type="checkbox" data-image="" data-field="clipped"></label>
|
2023-10-23 17:03:47 +03:00
|
|
|
<label>Chess Tile Opacity: <input type="checkbox" data-image="" data-field="tile-level-opecity"></label>
|
2023-03-11 19:38:21 +03:00
|
|
|
<label>Debug: <input type="checkbox" data-image="" data-field="debug"></label>
|
|
|
|
<label>Composite: <select data-image="" data-field="composite"></select></label>
|
2023-07-09 19:05:17 +03:00
|
|
|
<label>Wrap: <select data-image="" data-field="wrapping"></select></label>
|
2023-03-11 19:38:21 +03:00
|
|
|
</div>
|
|
|
|
</div>`.replaceAll('data-image=""', `data-image="${key}"`).replace('__title__', label));
|
2023-02-22 02:59:40 +03:00
|
|
|
|
2023-03-11 19:38:21 +03:00
|
|
|
}
|
2023-02-22 02:59:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|