Page zoom (scale) at cursor location - javascript

I'm working on a Chrome App that injects Javascript into a webview (similar to an iframe). The JS listens for a right-click inside the webview, and zooms in (scales) the contents of the webview, centering the scale at the cursor location. In other words, if I were to frame StackOverflow.com inside the webview and right-click on the S.O. logo near the top left of the page, the webview should then center on the S.O. logo, with it zoomed in.
I'm getting relatively close, but my math (or logic) is apparently a little bit off. Here is the JS I'm injecting into the webview ("window", "document", etc. below refers to the webpage inside the webview, not the parent window)...
window.oncontextmenu = function (){ // when the webview content is right-clicked...
var page = document.getElementsByTagName('body')[0]; // get the webview body element
// get cursor location inside webview...
var cursorX = event.clientX;
var cursorY = event.clientY;
// get scrollbar offset inside webview...
var scrollX = page.scrollLeft;
var scrollY = page.scrollTop;
// scrollbar offset + cursor location (I'm *not* sure if this is the correct logic, but it gets me fairly close)...
var x = scrollX + cursorX;
var y = scrollY + cursorY;
page.style.transformOrigin = x + 'px ' + y + 'px'; // set CSS transform origin (the pixel location where the scales centers)
page.style.transform = 'scale(10)'; // Zoom in 10X
return false;
}
FYI, the size of the webview in my app will vary, depending on the end user's screen size, so I need code that takes that into consideration. If the webview was a fixed size, then I think the math would be a little easier.
Thank you.

Related

Creating a Cursor Follow Script Without Breaking Usability

I'm learning how to make a script that creates a circle following the mouse cursor similar to the script below:
https://www.kirupa.com/canvas/follow_mouse_cursor.htm
This script will darken the whole website except for the part inside the circle, which will be visible at normal brightness.
However, using the author's canvas approach the user can not interact with the website underneath, as there is an overlay over the website.
Any input is appreciated.
Since HTML works in layers, there's really no way to have an element under the mouse and properly interact with the elements underneath.
Instead, what you may want to think about, instead of showing only whats under the mouse, hiding everything that isn't under the mouse.
The could be achieved by creating elements that stay a number of pixels away from the cursor, leaving a window into the site.
I made an example of this on JSFiddle, here is the important part using JQuery (although it could easily be done in plan JS as well).
var offset = 50; //the area around the cursor that is visible
$("body").mousemove(function(e){
var newPos = (e.pageX - offset);
$("#left").width(newPos);
$("#top,#bottom").css("left", newPos);
newPos = (window.innerWidth - (e.pageX + (offset + 17)));
$("#right").width(newPos);
newPos = (e.pageY - offset);
$("#top").height(newPos);
newPos = (window.innerHeight - (e.pageY + offset));
$("#bottom").height(newPos);
})
JSFiddle with full code. Note that the text can still be selected as usual.

authenticate user based on tap location in image in alloy app

I am building an alloy app where I have the requirement to authenticate a user based on his tap location on an image, loaded with ImageView. The image has few marked points of authentication, any of which when tapped on, shows whether the tap location was right or wrong. How can I build this?
So far, I am only able to get the tapped location in a touch event listener and the image's properties using ImageView's rect property. How can I pinpoint the marked locations in the image to identify a tap over those specific positions?
Here is the code I am using (derived from this: How to convert coordinates of the image view to the coordinates of the bitmap?):
// eventX, eventY are x and y coordinates of tapped location
function getScaledCoordinates(imageView, eventX, eventY) {
//original height and width of the image
var originalImageBounds = imageView.toBlob();
var intrinsicHeight = originalImageBounds.height;
var intrinsicWidth = originalImageBounds.width;
//height and width of the visible (scaled) image
var imageBounds = imageView.getRect();
var scaledHeight = imageBounds.height;
var scaledWidth = imageBounds.width;
//Find the ratio of the original image to the scaled image
var heightRatio = intrinsicHeight / scaledHeight;
var widthRatio = intrinsicWidth / scaledWidth;
//get the distance from the left and top of the image bounds
var scaledImageOffsetX = (eventX - imageBounds.x);
var scaledImageOffsetY = (eventY - imageBounds.y);
// get the units in device pixel
// getUnitsInDevicePixel(scaledImageOffsetX, scaledImageOffsetY)
//scale these distances according to the ratio of your scaling
var originalImageOffsetX = scaledImageOffsetX * widthRatio;
var originalImageOffsetY = scaledImageOffsetY * heightRatio;
// Return the coordinates in original image adjusted for scale factor
return [originalImageOffsetX, originalImageOffsetY];
}
I have coordinates of the original marked points stored in a data structure.
I am even able to get this to work, but the solution lacks accuracy. Sometimes, the tapped location is mapped correctly to the original image, other times it's not. Any suggestions to improve on this?
I was looking for something along the lines of clickable area of image, but can't find enough documentation to implement these in Titanium. Also, I read about the idea of placing invisible buttons at the marked locations, but not sure how to get this working in Titanium.
Any help will be appreciated. Thanks in advance!

svg.js / svg-pan-zoom - doubleclick interactions

I am using Ariutta's svg-pan-zoom with svg.js. I have disabled the native Arriuta doubleclick functionality and have tried adding my own, which ultimately consists of a pan adjustment and an animation.
Usually this works fine, but sometimes when I load my page the doubleclick function acts strangely. According to my debugging, it looks like sometimes when my app loads, the doubleclick function I wrote is called twice for each doubleclick. This causes the animation to behave strangely, and there seems to be no consistent basis for when this issue arises. Restarting my server sometimes works, and sometimes doesn't. I pretty much just have to continue reloading my page until the issue goes away.
My initial thoughts are that maybe there is something off in the load order of my files, and sometimes things load out of order. Currently investigating this. My other thought was that maybe this has something to do with the svg.js animation library or my trying to replace the native double-click function in arriuta's plugin. Thoughts?
myApp.service('AnimatorService', function(){
this.dblClickBehavior = function(svgCanvas, zoom){
$('.node').dblclick(function(){
// get pan
pan = zoom.getPan();
// get screen width and height
var sizes = zoom.getSizes();
var centerX = (sizes.width)/2;
var centerY = (sizes.height)/2;
// get center position of svg object double clicked
var x0 = this.instance.first().attr('cx');
var y0 = this.instance.first().attr('cy');
//determine the correct pan value necessary to center the svg
panAdjustX = centerX - x0*sizes.realZoom;
panAdjustY = centerY - y0*sizes.realZoom;
//center the svg object by adjust pan
zoom.pan({'x' :centerX - x0*sizes.realZoom, 'y' : centerY - y0*sizes.realZoom});
//simple animation on the object
this.instance.first().animate().radius(centerX);
});
}
});
When it behaves correctly, the svg image centers and then grows. When it behaves incorrectly, it centers and then shrinks into nothingness.
You tagged svg.js so I will give an svg.js answer. There is a plugin svg.panZoom.js now which can be used to easily implement the functionality you want:
var canvas = SVG('container').viewbox(0,0,1000,1000)
canvas.image('https://www.zooroyal.de/magazin/wp-content/uploads/2017/05/cat-2783601_1920.jpg', 1000, 1000)
.attr('preserveAspectRatio', 'none')
canvas.on('dblclick', function(e) {
var p = this.point(e.pageX, e.pageY)
var zoomLvl = 3
// zoom into point p to zoomLvl
canvas.animate().zoom(zoomLvl, p)
})
Here is a fiddle: https://jsfiddle.net/Fuzzy/95t6oL8y/5/
When you want to be able to panZoom your svg, too. Just add a call to canvas.panZoom()

Add HTML/CSS overlays by text location on pdf document when rendering in pdf.js viewer

How can I programmatically:
overlay HTML/CSS elements over a PDF document rendered in pdf.js, and
control the part of the document that is shown in the viewport
Using the locations in the native PDF coordinate system?
The goal here is to be able to, for example, highlight all occurrences of a phrase or add interactive design elements that are positioned according to the location of text that I have already parsed out of the document on the back end.
As a specific example, if know the phrase 'This is my Text.' is located on page 4 of my pdf document, and the box defining the position of this text on the page in the native pdf coordinate system is
bottom left corner = (0,0)
top right corner = (14, 5)
Is it possible to 1) scroll down to that line of the document so it is visible, and 2) overlay a div over this location?
I see that this is essentially what the built in 'text search', 'find next', and 'find prev' functionality it doing, but having some trouble interpreting the code.
PDF.js defines so called PageViewport which allows to convert between PDF coordinates and presentation on the screen. To create a viewport see PDF page's getViewport. Convert coordinates to on-screen presentation: var screenRect = viewport.convertToViewportRectangle([0, 0, 14, 5]); Normalize coordinates and overlay div on the canvas.
API for the generic viewer is not defined yet. However you can get a page view using viewer component: var pageView = PDFViewerApplication.pdfViewer.getPageView(3); // get page 4 view. The pageView will have viewport and div-container. (Since API is not defined yet, names and arguments might change) If you are using viewers containers, please notice that they are periodically cleaned up during zooming/scroll -- draw your stuff after pagerendered event.
Scrolling is just showing pageView.div at the region screenRect in the current view.
var pageNumber = 4;
var pdfRect = [0,0,140,150];
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1);
var screenRect = pageView.viewport.convertToViewportRectangle(pdfRect);
var x = Math.min(screenRect[0], screenRect[2]), width = Math.abs(screenRect[0] - screenRect[2]);
var y = Math.min(screenRect[1], screenRect[3]), height = Math.abs(screenRect[1] - screenRect[3]);
// note: needs to be done in the 'pagerendered' event
var overlayDiv = document.createElement('div');
overlayDiv.setAttribute('style', 'background-color: rgba(255,255,0,0.5);position:absolute;' +
'left:' + x + 'px;top:' + y + 'px;width:' + width + 'px;height:' + height + 'px;');
pageView.div.appendChild(overlayDiv);
// scroll
scrollIntoView(pageView.div, {top: y});

TypeError: myCanvas.getContext is not a function

I am developing a Firefox extension that uses the canvas element. It is added programatically (The canvas element is not there from the beginning, it is created and then I try to append).
The code used in the XUL (the mozilla XML) in very simple, adds NO elements, and only loads the script using the common tag.
The problems i've faced are, first, when the line
var myCtx = myCanvas.getContext("2d");
runs, the firefox console error returns TypeError: myCanvas.getContext is not a function.
Then, the other error is, even if I dont try to paint the canvas or anything, when I run the code, the line that appends the canvas to the body of the document also does not work, returning that document.body is undefined.
The script is as follows:
endSelectBox : function(aEvent){
mouseX2 = aEvent.clientX;
mouseY2 = aEvent.clientY;
//Start creating new canvas to be added in this position.
var canvasWidth, canvasHeight;
canvasWidth = Math.abs(mouseX2 - mouseX); //Calculates canvas width to be used.
canvasHeight = Math.abs(mouseY2 - mouseY); //Calculates canvas height to be used.
alert("pre id height width");
//Set canvas values for size.
var myCanvas;
myCanvas = document.createElement("canvas");
myCanvas.setAttribute("id", "canvas1");
myCanvas.setAttribute("height", canvasHeight.toString());
myCanvas.setAttribute("width", canvasHeight.toString());
//Set canvas fixed position on the page.
alert("pre CSS");
var top = Math.max(mouseY, mouseY2);
top = top.toString();
top = top + "px";
var left = Math.min(mouseX, mouseX2);
left = left.toString();
left = left + "px";
myCanvas.style.top = top;
myCanvas.style.left = left;
//myCanvas.style.position = "fixed";
//Paint canvas interior. //Not working because getContext returns null. No idea why, try to figure this out.
alert("pre painting");
var myCtx = myCanvas.getContext("2d");
alert("pre fillstyle");
myCtx.fillStyle = "#150000";
alert("pre fillrect");
myCtx.fillRect(0,0, canvasWidth - 1, canvasHeight - 1);
document.body.appendChild(myCanvas);// This never runs. WHY??
alert("worked");
}
The solution was to create the element using the document.createElementNS() function, and also when accessing the document, as user powerc9000 said, we need to use content.document in order to access it properly.
Cheers!
When making an extenion in Firefox from this link
To get the document of the current webpage from a browser.xul overlay, you should use content.document, instead of just document which is the document of the browser's window itself.
So try changing all your document with content.document that should solve your problem.

Categories

Resources