![JAR search and dependency download from the Maven repository](/logo.png)
jadex.micro.mandelbrot.webui.mandelbrot.js Maven / Gradle / Ivy
The newest version!
//export class MandelbrotElement extends LitElement
class MandelbrotElement extends HTMLElement
{
static getHost(node)
{
let tmp = node;
while(tmp!=null && tmp.parentNode!=null)
tmp = tmp.parentNode;
tmp=tmp.host;
//console.log(tmp);
return tmp;
}
constructor()
{
super();
this.attachShadow({ mode: 'open'});
this.visible = true;
window['getHost'] = MandelbrotElement.getHost;
console.log("init of mandelbrot elem");
//let self = this;
/*this.app = App.getInstance();
this.listener = (type, value) =>
{
self.appChanged(type, value);
};*/
// this.listener = this.appChanged; // 'this' is wrong in that case
/*this.loadStyle("style.css").then(()=>
{
self.update();
})
.catch(err =>
{
self.setError(err);
});*/
this.style = this.addStyle(this.getCss());
//this.update();
}
update()
{
this.shadowRoot.innerHTML = this.getHtml();
this.initListener();
this.paint();
}
// todo: why does caching (above) not work :-(
loadStyle(url)
{
//console.log("###########LOADING STY " + url);
var self = this;
var ret = null;
ret = new Promise(function(resolve, reject)
{
axios.get(url).then(function(resp)
{
//console.log("loaded version: "+url+" "+self.shadowRoot.adoptedStyleSheets.length);
//console.log(resp.data);
var css = resp.data;
resolve(self.addStyle(css));
BaseElement.loaded[url] = css;
})
.catch(function(err)
{
reject(err);
});
});
return ret;
}
addStyle(css)
{
var sheet = new CSSStyleSheet();
sheet.replaceSync(css);
this.shadowRoot.adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets.concat(sheet);
return sheet;
}
connectedCallback()
{
console.log('connected');
let self = this;
this.displayid = "webgui"+jadex.generateUUID();
this.colors = null; // the color scheme
this.data = null; // the area data to draw
this.progressdata = null; // the progress infos
this.calculating = false;
this.startdrag = null;
this.enddrag = null;
this.point = null; // The current selection start point (if any).
this.range = null;
this.setColorScheme([this.createColor(50, 100, 0), this.createColor(255, 0, 0)], true);
// shadow dom not available here :-(
// must not use args_0 as parameter name as this will be made to args list
this.terminate = jadex.getIntermediate('mandelbrotdisplay/subscribeToDisplayUpdates?a='+this.displayid+'&returntype=jadex.commons.future.ISubscriptionIntermediateFuture',
function(response)
{
//console.log("subscribe received: "+response.data);
self.handleDisplayUpdate(response);
},
function(err)
{
console.log("display subscribe err: "+err);
},
null,
function() // init handler
{
console.log("display subscribed");
self.getAlgorithms().then(algos =>
{
self.algorithms = algos.map(a =>
{
let parts = a.value.split(".");
let name = parts[parts.length-1];
let suffix = "Algorithm";
if(name.endsWith(suffix))
name = name.slice(0, -suffix.length);
return {classname: a.value, name: name};
});
//console.log("received algos: "+self.algorithms);
self.calcArea();
self.update();
})
.catch(ex =>
{
console.log(ex);
});
});
}
disconnectedCallback()
{
console.log('disconnected');
if(this.terminate)
jadex.terminateCall(this.terminate);
}
initListener()
{
let self = this;
this.addMouseListener(this.shadowRoot.getElementById("canvas"));
this.makeElementDragable(this.shadowRoot.getElementById("settings"));
this.makeElementDragable(this.shadowRoot.getElementById("image"), true);
// turn off right click popup menu
this.shadowRoot.getElementById("canvas").oncontextmenu = e =>
{
e.preventDefault();
};
// get informed on resize events of the canvas
let ro = new ResizeObserver(entries =>
{
for(let entry of entries)
{
//self.checkAdaptSizeToCanvas();
if(this.isTrackSize())
self.adaptSizeToCanvas(entry, self);
let adaptresize = this.shadowRoot.getElementById("adaptresize").checked;
if(adaptresize)
{
let canvas = this.shadowRoot.getElementById("canvas");
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
//console.log("resize update");
self.paint();
//self.update();
}
}
});
ro.observe(this.shadowRoot.getElementById("canvas"));
//this.resetSettings(e);
}
handleDisplayUpdate(response)
{
//console.log("recceived display update: "+response.data);
let self = this;
let data = response.data;
//System.out.println("rec: "+result.getClass());
if(data.algorithmClass!=null) // result instanceof AreaData
{
//self.calculating = true;
self.initResults(data);
self.setSettings(data);
let adaptsize = this.shadowRoot.getElementById("adaptsize").checked;
if(adaptsize)
{
let results = this.data.data;
let swidth = results.length;
let sheight = results[0].length;
let container = this.shadowRoot.getElementById("image");
container.style.width = swidth+"px";
container.style.height = sheight+"px";
console.log("adapted container size: "+container.style.width+" "+container.style.height);
}
}
else if(data.data!=null) // result instanceof PartDataChunk
{
//console.log("received data");
//self.calculating = true;
self.addDataChunk(data);
}
if(data.progress!=null) // result instanceof ProgressData
{
//console.log("received progress: "+data.progress);
let prog = {};
prog.name = data.worker;//.name;
prog.area = data.area;
prog.progress = data.progress;
prog.imageWidth = data.imageWidth;
prog.imageHeight = data.imageHeight;
prog.finished = data.progress==100;
self.addProgress(prog);
}
}
paint()
{
if(this.data==null || this.data.data==null || this.data.image==null)
return;
let results = this.data.data;
let oimage = this.data.image;
let image = new Uint8ClampedArray(oimage); // clone the image data
//let adaptsize = this.shadowRoot.getElementById("adaptsize").checked;
//let adaptresize = this.shadowRoot.getElementById("adaptresize").checked;
let fill = this.shadowRoot.getElementById("fill").checked;
let container = this.shadowRoot.getElementById("image");
let canvas = this.shadowRoot.getElementById("canvas");
let ctx = canvas.getContext("2d");
let sx = 0;
let sy = 0;
let swidth = results.length;
let sheight = results[0].length;
let width = canvas.width;
let height = canvas.height;
// screen range, coordinates on canvas
let srange = this.range!=null? this.convertRangeToScreenValues(this.range): null;
/*if(canvas.width
{
ctx.drawImage(imgbitmap, sx, sy, swidth, sheight, tx, ty, twidth, theight);
})
.catch(err =>
{
console.log(err);
});*/
let canvas2 = null;
let ctx2 = null;
// Draw progress boxes.
if(this.progressdata!=null && Object.keys(this.progressdata).length>0)
{
//canvas2 = this.createCanvas(swidth, sheight);
let w = canvas.offsetWidth;
let h = canvas.offsetHeight;
canvas2 = this.createCanvas(w, h);
ctx2 = canvas2.getContext('2d');
for(let key of Object.keys(this.progressdata))
{
let progress = this.progressdata[key];
//console.log("progress is: "+progress);
let xf = fill? w/progress.imageWidth: 1;
let yf = fill? h/progress.imageHeight: 1;
let corx = Math.trunc(progress.area.x*xf);
let cory = Math.trunc(progress.area.y*yf);
let corw = Math.trunc(progress.area.w*xf);
let corh = Math.trunc(progress.area.h*yf);
let mystartx = fill? corx: corx+startx;
let mystarty = fill? cory: cory+starty;
if(!progress.finished)
{
//ctx2.fillStyle = this.createColor(20, 20, 150, 160); //160
ctx2.fillStyle = "rgba(20, 20, 150, 0.3)";
ctx2.fillRect(mystartx+1, mystarty+1, corw-1, corh-1);
}
ctx2.strokeStyle = "white";
ctx2.strokeRect(mystartx, mystarty, corw, corh);
// Print worker name
let name = progress.name? progress.name: "n/a";
let provider = "";
if(name)
{
let index = name.indexOf('@');
if(index!=-1)
{
provider = name.substring(index+1);
name = name.substring(0, index);
}
}
let textwidth;
let textheight;
let fsize = 20;
while(true)
{
ctx2.font = fsize+'px sans-serif';
let m1 = ctx2.measureText(name);
let m2 = ctx2.measureText(provider);
textwidth = Math.max(m1.width, m2.width);
//textheight = (m1.fontBoundingBoxAscent + m1.fontBoundingBoxDescent)*3; // + barsize.height + 2;
textheight = Math.max(m1.actualBoundingBoxAscent + m1.actualBoundingBoxDescent, m2.actualBoundingBoxAscent + m2.actualBoundingBoxDescent);
//textheight = Math.max(m1.fontBoundingBoxAscent + m1.fontBoundingBoxDescent, m2.fontBoundingBoxAscent + m2.fontBoundingBoxDescent);
if(textwidth8 && corh>8)
{
//console.log("b: "+textwidth+" "+textheight+" "+corw+" "+corh+" "+fsize);
let x = mystartx + 2;
let y = mystarty + Math.max((corh-textheight)/2, 2);
this.drawProgressBar(x, y, textwidth, textheight, 'red', progress.progress/100, true, ctx2);
}
}
}
// Draw range area.
if(!this.calculating && this.range!=null)
{
if(canvas2==null)
{
canvas2 = this.createCanvas(canvas.offsetWidth, canvas.offsetHeight);
ctx2 = canvas2.getContext('2d');
}
let rratio = this.range.width/this.range.height;
let bratio = width/height;
// Draw left and right boxes to show unused space
if(rratiobratio)
{
let drawheight = this.range.width*sheight/swidth;
let offset = (this.range.height-drawheight)/2;
ctx2.fillStyle = "rgba(128,128,128,0.25)";
ctx2.fillRect(srange.x, srange.y+offset, srange.width+1, -offset);
ctx2.fillRect(srange.x, srange.y+srange.height, srange.width+1, -offset);
}
ctx2.strokeStyle = "white";
ctx2.strokeRect(srange.x, srange.y, srange.width, srange.height);
}
if(canvas2!=null)
ctx.drawImage(canvas2, 0, 0, canvas2.width, canvas2.height, 0, 0, width, height);
}
/**
* ctx: The draw context
* image: The image data to draw
* swidth: with in pixel of source picture
* sheight: height in pixel of source picture
* startx: where to start at target
* starty: where to start at target
* width: width of target
* height: height of target
* fill: fill target (resize) or paint pixel as is
*/
drawImage(ctx, image, swidth, sheight, width, height, fill, xoff, yoff)
{
let startx = Math.trunc((width-swidth)/2);
let starty = Math.trunc((height-sheight)/2);
xoff = xoff===undefined? 0: xoff;
yoff = yoff===undefined? 0: yoff;
let imgdata = new ImageData(image, swidth, sheight);
if(!fill)
{
//ctx.putImageData(imgdata, startx, starty, xoff, yoff, swidth, sheight);
let canvas2 = this.createCanvas(swidth, sheight);
let ctx2 = canvas2.getContext('2d');
ctx2.putImageData(imgdata, 0, 0);
ctx.drawImage(canvas2, -xoff, -yoff, swidth, sheight, startx, starty, swidth, sheight);
}
else
{
let canvas2 = this.createCanvas(swidth, sheight);
let ctx2 = canvas2.getContext('2d');
ctx2.putImageData(imgdata, 0, 0);
ctx.drawImage(canvas2, 0, 0, swidth, sheight, xoff, yoff, width, height);
}
}
makeElementDragable(element, leftborder)
{
var x1 = 0;
var y1 = 0;
var x2 = 0;
var y2 = 0;
var moved = e =>
{
e = e || window.event;
e.preventDefault();
x1 = x2 - e.clientX;
y1 = y2 - e.clientY;
x2 = e.clientX;
y2 = e.clientY;
//console.log("to: "+x2+" "+y2);
// set the element's new position:
//var y = parseInt(element.style.top) || 0;
//var x = parseInt(element.style.left) || 0;
element.style.top = element.offsetTop-y1+"px";
element.style.left = element.offsetLeft-x1+"px";
}
var md = e =>
{
//console.log("offsetx: "+e.offsetX+" "+e.clientX+" "+element.offsetWidth);
// only dragable when at left border (in case leftborder true)
if(leftborder && e.offsetX>0)
{
//console.log("not at border");
return;
}
if(element.offsetWidth-e.offsetX < 20 && element.offsetHeight-e.offsetY < 20)
{
//console.log("at resize border");
return;
}
e = e || window.event;
//e.preventDefault(); // if used will hinder input fields from working
x2 = e.clientX;
y2 = e.clientY;
//console.log("from: "+x2+" "+y2);
// clean up document mouse listeners after mouse released
var mu = e =>
{
document.removeEventListener("mouseup", mu);
document.removeEventListener("mousemove", moved);
};
document.addEventListener("mouseup", mu);
// watch now for movements
document.addEventListener("mousemove", moved);
}
// listen on mouse clicks on that element
element.addEventListener("mousedown", md);
}
getMethodPrefix()
{
//return '/webjcc/invokeServiceMethod?cid=null'+'&servicetype='+'jadex.micro.examples.mandelbrot.IDisplayService'; cid=null leads to CID(null) :-()
return '/webjcc/invokeServiceMethod?servicetype='+'jadex.micro.mandelbrot.IDisplayService';
}
initResults(data)
{
if(data.data==null)
data.data = this.makeArray(data.sizeX, data.sizeY);
this.data = data;
this.data.image = new Uint8ClampedArray(data.sizeX*data.sizeY*4);
}
addProgress(part)
{
if(this.progressdata==null)
this.progressdata = {};//new HashSet();
let key = this.getProgressKey(part);
delete this.progressdata[key];
if(!part.finished)
this.progressdata[key] = part;
let len = Object.keys(this.progressdata).length;
if(len>0)
this.range = null;
if(len==0)
this.calculating = false;
//console.log("progressdata len (before, after): "+len+" "+Object.keys(this.progressdata).length+" "+part.finished+" "+part.progress);
//console.log("progress update");
this.paint();
//this.update();
}
getProgressKey(part)
{
let area = part.area;
let key = 'x='+area.x+"y="+area.y+"w="+area.w+"h="+area.h;
return key;
}
addDataChunk(data) //PartDataChunk
{
// first chunk is empty and only delivers name of worker
if(data.data===null || this.data===null)
{
console.log("Cannot add data chunk, no initial AreaData received");
return;
}
var chunk = data.data;
var results = this.data.data;
var image = this.data.image;
var xi = data.area.x+data.xStart;
var yi = data.area.y+data.yStart;
var xmax = data.area.x+data.area.w;
//console.log("chunk: "+xi+" "+yi+" "+xmax+" "+chunk.length);
var cnt = 0;
while(cnt=xmax)
{
xi=data.area.x;
yi++;
}
}
//console.log("addDataChunk update");
//this.update();
this.paint();
}
makeArray(d1, d2)
{
var arr = [];
for(let i = 0; i < d1; i++)
{
arr.push(new Array(d2));
}
return arr;
}
getColor(value)
{
let ret;
if(value==-1)
{
ret = this.createColor(0, 0, 0);
}
else
{
ret = this.colors[value%this.colors.length];
}
return ret
}
drawPixel(data, width, x, y, color)
{
this.drawPixel2(data, width, x, y, this.getRed(color), this.getGreen(color), this.getBlue(color), this.getAlpha(color));
}
drawPixel2(data, width, x, y, r, g, b, a)
{
var index = x*4 + y*width*4;
data[index + 0] = r;
data[index + 1] = g;
data[index + 2] = b;
if(a)
data[index + 3] = a;
else
data[index + 3] = 255; // make NOT transparent
}
drawProgressBar(x, y, w, h, color, percentage, complete, ctx)
{
if(complete)
{
ctx.beginPath();
ctx.arc(h / 2 + x, h / 2 + y, h / 2, Math.PI / 2, 3 / 2 * Math.PI);
ctx.lineTo(w - h + x, 0 + y);
ctx.arc(w - h / 2 + x, h / 2 + y, h / 2, 3 / 2 *Math.PI, Math.PI / 2);
ctx.lineTo(h / 2 + x, h + y);
ctx.strokeStyle = '#000000';
ctx.stroke();
ctx.closePath();
}
let p = percentage * w;
if(p <= h)
{
ctx.beginPath();
ctx.arc(h / 2 + x, h / 2 + y, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h));
ctx.save();
ctx.scale(-1, 1);
ctx.arc((h / 2) - p - x, h / 2 + y, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h));
ctx.restore();
ctx.closePath();
}
else
{
ctx.beginPath();
ctx.arc(h / 2 + x, h / 2 + y, h / 2, Math.PI / 2, 3 / 2 *Math.PI);
ctx.lineTo(p - h + x, 0 + y);
ctx.arc(p - (h / 2) + x, h / 2 + y, h / 2, 3 / 2 * Math.PI, Math.PI / 2);
ctx.lineTo(h / 2 + x, h + y);
ctx.closePath();
}
ctx.fillStyle = color;
ctx.fill();
}
createCanvas(width, height)
{
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
//canvas2.style.background = "transparent";
ctx.canvas.width = width;
ctx.canvas.height = height;
return canvas;
}
// Determine how the image can be printed on screen
// swidth/height: screen width/height (screen)
// iwidth/height: image width/height (calculated)
/*scaleToFit(swidth, sheight, iwidth, iheight)
{
var sratio = swidth/sheight;
var iratio = iwidth/iheight;
var drawstartx = 0;
var drawstarty = 0;
var drawendx = swidth;
var drawendy = sheight;
// Scale to fit height
if(iratio<=sratio)
{
var hratio = sheight/iheight;
drawendy = iwidth*hratio;
drawstartx = (swidth-drawendx)/2;
}
// Scale to fit width
else if(iratio>sratio)
{
var wratio = swidth/iwidth;
drawendy = iheight*wratio;
drawstarty = (sheight-drawendy)/2;
}
return {x: Math.trunc(drawstartx), y: Math.trunc(drawstarty), width: Math.trunc(drawendx), height: Math.trunc(drawendy)};
}*/
createColor(r, g, b, a)
{
const color = a << 24 | r << 16 | g << 8 | b;
return color;
}
getAlpha(color)
{
return color >>> 24;
}
getRed(color)
{
return color >>> 16 & 0xff;
}
getGreen(color)
{
return color >>> 8 & 0xff;
}
getBlue(color)
{
return color & 0xff;
}
createColorBetween(start, end, diff)
{
let ret = this.createColor(
this.getRed(start)+diff*(this.getRed(end)-this.getRed(start)),
this.getGreen(start)+diff*(this.getGreen(end)-this.getGreen(start)),
this.getBlue(start)+diff*(this.getBlue(end)-this.getBlue(start))
);
//console.log("start: "+start+" end: "+end+" diff: "+diff+" created: "+ret);
return ret;
}
setColorScheme(scheme, cycle)
{
if(scheme==null || scheme.length==0)
{
this.colors = [this.createColor[0xFF, 0xFF, 0xFF]];
}
else if(scheme.length==1)
{
this.colors = scheme;
}
else if(cycle)
{
this.colors = new Array(scheme.length*16);
for(var i=0; i
{
drag = false;
if(!self.calculating)
{
if(e.button===2)
{
self.startdrag = self.getMousePosition(element, e);
self.range = null;
self.point = null;
console.dir("startdrag: "+self.startdrag);
}
else if(e.button===0)
{
self.point = self.getMousePosition(element, e);
}
}
else
{
self.startdrag = null;
}
}
element.addEventListener('mousedown', downlis);
let movelis = e =>
{
//console.log("mouse move: "+e.button);
drag = true;
if(self.startdrag!=null && e.buttons===2)
{
self.enddrag = self.getMousePosition(element, e);
console.dir('update, new enddrag: '+self.enddrag);
self.paint();
//self.update();
}
if(!self.calculating && self.point!=null && e.buttons===1)
{
let pos = self.getMousePosition(element, e);
let startx = this.getStartX();
let starty = this.getStartY();
//console.table("x1: "+self.point.x+" x2: "+pos.x);
//console.table("y1: "+self.point.y+" x2: "+pos.y);
let x1 = self.point.x;
let x2 = pos.x;
let y1 = self.point.y;
let y2 = pos.y;
if(!self.isFill())
{
if(x1startx+self.getImageWidth())
x1 = startx+self.getImageWidth();
if(x2>startx+self.getImageWidth())
x2 = startx+self.getImageWidth();
if(y1starty+self.getImageHeight())
y1 = starty+self.getImageHeight();
if(y2>starty+self.getImageHeight())
y2 = starty+self.getImageHeight();
}
let range = {
x: x1
{
if(self.startdrag!=null && self.enddrag!=null)
{
self.dragImage();
}
self.startdrag = null;
self.enddrag = null;
//self.update();
self.paint();
//console.log("update drag");
}
element.addEventListener('mouseup', uplis);
let wheellis = e =>
{
let pos = self.getMousePosition(element, e);
let delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)))*-1;
//console.log("wheel: "+delta);
let percent = Math.abs(10*delta)*2;
let factor;
if(delta>0)
{
factor = (100+percent)/100;
}
else
{
factor = 100/(100+percent);
}
let x = pos.x;
let y = pos.y;
if(!self.isFill())
{
x = x-self.getStartX();
y = y-self.getStartY();
}
else
{
x = x*self.getImageWidth()/self.getCanvasScreenWidth();
y = y*self.getImageHeight()/self.getCanvasScreenHeight();
}
//self.checkAdaptSizeToCanvas();
self.zoomImage(x, y, factor);
}
element.addEventListener("wheel", wheellis);
let clicklis = e =>
{
//console.log("drag: "+drag);
if(drag)
return;
let pos = self.getMousePosition(element, e);
if(e.button===2)
{
//self.calcDefaultImage();
}
else if(e.button===0 && !self.calculating && self.range!=null)
{
// Zoom when user clicked into range
let srange = this.convertRangeToScreenValues(self.range);
if(pos.x>=srange.x && pos.x<=srange.x+srange.width
&& pos.y>=srange.y && pos.y<=srange.y+srange.height)
{
//self.checkAdaptSizeToCanvas();
self.zoomIntoRange();
}
else
{
self.range = null;
console.log("update click");
self.paint();
//self.update();
}
}
}
element.addEventListener("click", clicklis);
}
getMousePosition(element, event)
{
let rect = element.getBoundingClientRect();
let x = event.clientX - rect.left;
let y = event.clientY - rect.top;
return {x,y};
}
getImageWidth()
{
let results = this.data.data;
let width = results.length;
return width;
}
getImageHeight()
{
let results = this.data.data;
let height = results[0].length;
return height;
}
getCanvasWidth()
{
let canvas = this.shadowRoot.getElementById("canvas");
let ctx = canvas.getContext("2d");
return ctx.canvas.width;
}
getCanvasHeight()
{
let canvas = this.shadowRoot.getElementById("canvas");
let ctx = canvas.getContext("2d");
return ctx.canvas.height;
}
getCanvasScreenWidth()
{
let canvas = this.shadowRoot.getElementById("canvas");
return canvas.offsetWidth;
}
getCanvasScreenHeight()
{
let canvas = this.shadowRoot.getElementById("canvas");
return canvas.offsetHeight;
}
convertRangeToScreenValues(r)
{
let range = {...r}; // clone
if(!this.isFill())
{
range.x = range.x+this.getStartX();
range.y = range.y+this.getStartY();
}
else
{
range.x = range.x*this.getCanvasScreenWidth()/this.getImageWidth();
range.y = range.y*this.getCanvasScreenHeight()/this.getImageHeight();
range.width = range.width*this.getCanvasScreenWidth()/this.getImageWidth();
range.height = range.height*this.getCanvasScreenHeight()/this.getImageHeight();
}
return range;
}
convertRangeToImageValues(r)
{
let range = {...r}; // clone
if(!this.isFill())
{
range.x = range.x-this.getStartX();
range.y = range.y-this.getStartY();
}
else
{
range.x = range.x*this.getImageWidth()/this.getCanvasScreenWidth();
range.y = range.y*this.getImageHeight()/this.getCanvasScreenHeight();
range.width = range.width*this.getImageWidth()/this.getCanvasScreenWidth();
range.height = range.height*this.getImageHeight()/this.getCanvasScreenHeight();
}
return range;
}
getScreenRange()
{
return this.range==null? null: convertRangeToScreenValues(this.range);
}
getStartX()
{
return Math.trunc((this.getCanvasWidth()-this.getImageWidth())/2);
}
getStartY()
{
return Math.trunc((this.getCanvasHeight()-this.getImageHeight())/2);
}
dragImage()
{
console.log("dragImage: "+this.startdrag+" "+this.enddrag);
let sw = this.getImageWidth();
let sh = this.getImageHeight();
//let drawarea = this.scaleToFit(sw, sh, iw, ih);
let xdiff = this.startdrag.x-this.enddrag.x;
let ydiff = this.startdrag.y-this.enddrag.y;
let xp = xdiff/sw;
let yp = ydiff/sh;
let xm = (this.data.xEnd-this.data.xStart)*xp;
let ym = (this.data.yEnd-this.data.yStart)*yp;
let xs = this.data.xStart+xm;
let xe = this.data.xEnd+xm;
let ys = this.data.yStart+ym;
let ye = this.data.yEnd+ym;
this.startdrag = null;
this.enddrag = null;
//this.range = {x: xdiff, y: ydiff, width: sw, height: sh};
let size = [this.data.sizeX, this.data.sizeY];
if(this.isTrackSize())
size = this.adaptSize(this.data.sizeX, this.data.sizeY, this.getCanvasScreenWidth(), this.getCanvasScreenHeight());
this.calcArea(xs, xe, ys, ye, size[0], size[1]);
}
// Zoom into the given location by the given factor.
// x, y must be coordinates in image scale (not screen)
zoomImage(x, y, factor)
{
//console.log("zoomImage "+factor);
let sw = this.getImageWidth();
let sh = this.getImageHeight();
let iw = this.getImageWidth();
let ih = this.getImageHeight();
let mx = Math.min(sw, Math.max(0, x));
let my = Math.min(sh, Math.max(0, y));
let xrel = mx/sw;
let yrel = my/sh;
let wold = this.data.xEnd-this.data.xStart;
let hold = this.data.yEnd-this.data.yStart;
let wnew = wold*factor;
let hnew = hold*factor;
let wd = wold-wnew;
let hd = hold-hnew;
let xs = this.data.xStart+wd*xrel;
let xe = xs+wnew;
let ys = this.data.yStart+hd*yrel;
let ye = ys+hnew;
// Set range for drawing preview of zoom area.
let xdiff = sw - sw*factor;
let ydiff = sh - sh*factor;
// range is set in image scale
this.range = {x: Math.trunc(xdiff*xrel), y: Math.trunc(ydiff*yrel),
width: Math.trunc(sw*factor), height: Math.trunc(sh*factor)};
// zoomIntoRange();
let size = [this.data.sizeX, this.data.sizeY];
if(this.isTrackSize())
size = this.adaptSize(this.data.sizeX, this.data.sizeY, this.getCanvasScreenWidth(), this.getCanvasScreenHeight());
this.calcArea(xs, xe, ys, ye, size[0], size[1]);
}
zoomIntoRange()
{
//console.log("zoomIntoRange: "+this.range);
//let sw = this.range.width;
//let sh = this.range.height;
let iw = this.getImageWidth();
let ih = this.getImageHeight();
let x = this.range.x/iw;
let y = this.range.y/ih;
let x2 = x + this.range.width/iw;
let y2 = y + this.range.height/ih;
// Original bounds
let ox = this.data.xStart;
let oy = this.data.yStart;
let owidth = this.data.xEnd-this.data.xStart;
let oheight = this.data.yEnd-this.data.yStart;
// adapt cutout to image data size
let neww;
let newh;
let rw = this.range.width/this.range.height;
let rh = this.range.height/this.range.width;
if(rh<1)
{
neww = iw;
newh = Math.trunc(rh*ih);
}
else
{
neww = Math.trunc(rw*iw);
newh = ih;
}
// adapt image data size to screen size
let size = [neww, newh];
if(this.isTrackSize())
size = this.adaptSize(neww, newh, this.getCanvasScreenWidth(), this.getCanvasScreenHeight());
this.calcArea(ox+owidth*x, ox+owidth*x2, oy+oheight*y, oy+oheight*y2, size[0], size[1]);
}
adaptSize(w1, h1, w2, h2)
{
let rw = w2/w1;
let rh = h2/h1;
let r = Math.min(rw, rh);
return [r*w1, r*h1];
}
getAlgorithmDefaultSettings(name)
{
return new Promise((resolve, reject) =>
{
fetch('mandelbrotdisplay/getAlgorithmDefaultSettings?a=' + name)
.then(response =>
{
if(!response.ok)
throw new Error('Network response was not ok');
return response.json();
})
.then(data =>
{
console.log("fetching default settings finished: " + data);
resolve(data);
})
.catch(error =>
{
console.error('There was a problem with the fetch operation:', error);
reject(error);
});
/*axios.get('/mandelbrotdisplay/getAlgorithmDefaultSettings?a='+name, this.transform)
.then(function(response)
{
console.log("fetching default settings finished: "+response.data);
resolve(response.data);
})
.catch(ex =>
{
console.log(ex);
reject(err);
});*/
});
}
getAlgorithms()
{
return new Promise((resolve, reject) =>
{
fetch('mandelbrotdisplay/getAlgorithms')
.then(response =>
{
if(!response.ok)
throw new Error('Network response was not ok');
return response.json();
})
.then(data =>
{
console.log("fetching algos finished: " + data);
resolve(data);
})
.catch(error =>
{
console.error('There was a problem with the fetch operation:', error);
reject(error);
});
});
}
calcArea(x1, x2, y1, y2, sizex, sizey, algo, max, chunks, tasksize)
{
let data = {};
data.xStart = x1;
data.xEnd = x2;
data.yStart = y1;
data.yEnd = y2;
data.sizeX = sizex;
data.sizeY = sizey;
if(algo)
data.algorithmClass = algo;
else if(this.data!=null)
data.algorithmClass = this.data.algorithmClass;
if(max)
data.max = max;
else if(this.data!=null)
data.max = this.data.max;
if(chunks)
data.chunkCount = chunks;
else if(this.data!=null)
data.chunkCount = this.data.chunkCount;
if(tasksize)
data.taskSize = tasksize;
else if(this.data!=null)
data.taskSize = this.data.taskSize;
data.displayId = this.displayid;
//DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
this.calculating = true;
//console.log("update calcArea");
this.paint();
//this.update();
console.log("request data: "+JSON.stringify(data));
fetch('mandelbrotgenerate/generateArea?a=' + encodeURIComponent(JSON.stringify(data)))
.then(response =>
{
if(!response.ok)
throw new Error('Network response was not ok');
//console.log("generateArea finished: " + response.ok);
self.calculating = false;
//self.handleDisplayUpdate(response);
//DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
})
.catch(error =>
{
console.error('There was a problem with the fetch operation:', error);
self.calculating = false;
});
/*axios.get('/mandelbrotgenerate/generateArea?a='+JSON.stringify(data), this.transform)
.then(function(response)
{
console.log("generateArea finished: "+response.data);
self.calculating = false;
//self.handleDisplayUpdate(response);
//DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
})
.catch(ex =>
{
console.log(ex);
self.calculating = false;
});*/
}
generateArea(e)
{
var algo = this.shadowRoot.getElementById("algorithm").value;
if(algo)
algo = {value: algo};
var xmin = this.shadowRoot.getElementById("xmin").value;
var xmax = this.shadowRoot.getElementById("xmax").value;
var ymin = this.shadowRoot.getElementById("ymin").value;
var ymax = this.shadowRoot.getElementById("ymax").value;
var sizex = this.shadowRoot.getElementById("sizex").value;
var sizey = this.shadowRoot.getElementById("sizey").value;
var max = this.shadowRoot.getElementById("max").value;
var chunks = this.shadowRoot.getElementById("chunks").value;
var tasksize = this.shadowRoot.getElementById("tasksize").value;
this.calcArea(xmin, xmax, ymin, ymax, sizex, sizey, algo, max, chunks, tasksize);
}
isTrackSize()
{
return this.shadowRoot.getElementById("tracksize").checked;
}
resetSettings(e)
{
this.setDefaultSettings().then(x =>
{
this.generateArea();
})
.catch(err =>
{
console.log(err);
});
this.range = null;
}
setSettings(data)
{
if(data.algorithmClass!=null)
this.shadowRoot.getElementById("algorithm").value = data.algorithmClass.value;
this.shadowRoot.getElementById("xmin").value = data.xStart;
this.shadowRoot.getElementById("xmax").value = data.xEnd;
this.shadowRoot.getElementById("ymin").value = data.yStart;
this.shadowRoot.getElementById("ymax").value = data.yEnd;
this.shadowRoot.getElementById("sizex").value = data.sizeX;
this.shadowRoot.getElementById("sizey").value = data.sizeY;
this.shadowRoot.getElementById("max").value = data.max;
this.shadowRoot.getElementById("chunks").value = data.chunkCount;
this.shadowRoot.getElementById("tasksize").value = data.taskSize;
}
setDefaultSettings(e)
{
let self = this;
return new Promise(function(resolve, reject)
{
let elem = self.shadowRoot.getElementById('algorithm');
let value = elem.options[elem.selectedIndex].value;
self.getAlgorithmDefaultSettings(value).then(data =>
{
self.setSettings(data);
resolve();
})
.catch(err =>
{
console.log(err);
reject(err);
});
})
}
adaptSizeToCanvas(e, self)
{
if(self==null)
self = this;
let canvas = this.shadowRoot.getElementById("canvas");
self.shadowRoot.getElementById("sizex").value = canvas.offsetWidth;
self.shadowRoot.getElementById("sizey").value = canvas.offsetHeight;
}
isFill()
{
let fill = this.shadowRoot.getElementById("fill").checked;
return fill;
}
getCss()
{
return `
.dragable {
padding: 10px;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 30%;
background-color: #00000066;
border: 1px solid #d3d3d3;
z-index: 1;
resize: both;
overflow: hidden;
color: white;
}
.dragable2 {
position: fixed;
width: fit-content;
height: fit-content;
resize: both;
overflow: hidden;
background-color: yellow;
}
.grid {
display: grid;
grid-template-columns: max-content auto;
grid-gap: 0.5em;
}
.grid2 {
display: grid;
grid-template-columns: auto auto;
}
.fitcontent {
width: fit-content;
}
.fitcontentheight {
height: fit-content;
}
.floatright {
float: right;
}
.margintop {
margin-top: 0.5em;
}
.jadexbtn {
background-color:#2a6699;
border-radius:6px 6px 6px 6px;
font-weight:bold;
font-weight:600;
padding-top:10px;
padding-bottom:10px;
border: 0px;
color: #fff;
}
.jadexbtn:disabled,
.jadexbtn.disabled {
border: 1px solid #999999;
background-color: #cccccc;
color: #666666;
}
.leftborder {
border-left: 10px solid red;
}
.w100 {
width: 100%;
}
.h100 {
height: 100%;
}
.checkboxleft {
width: fit-content;
margin-left: 0px;
}
.block {
display: block;
}
`;
// display block for canvas to
// avoid strange 5px bottom :-( https://stackoverflow.com/questions/15807833/div-containing-canvas-have-got-a-strange-bottom-margin-of-5px
}
getHtml()
{
return `
Factals
`;
}
}
if(customElements.get('jadex-mandelbrot') === undefined)
customElements.define('jadex-mandelbrot', MandelbrotElement);
© 2015 - 2025 Weber Informatics LLC | Privacy Policy