Image doesn't render in print preview - javascript

I need to print a element, for this, i am using primefaces <p:printer>
In carDetail panelGrid, i have a zoomable image, when i click in print commandlink, the zoomed image does not render in print preview.
zoom JS:
function updateBgStyle() {
if (bgPosX > 0) {
bgPosX = 0;
} else if (bgPosX < width - bgWidth) {
bgPosX = width - bgWidth;
}
if (bgPosY > 0) {
bgPosY = 0;
} else if (bgPosY < height - bgHeight) {
bgPosY = height - bgHeight;
}
img.style.backgroundSize = bgWidth+'px '+bgHeight+'px';
img.style.backgroundPosition = bgPosX+'px '+bgPosY+'px';
x = document.getElementById('myimage');
img2 = document.createElement("IMG");
img2.src = '../../RESOURCES/images/remoteAgent/473_180420160608_HJF4013_2.jpg';
document.getElementById('myresult').style.backgroundSize = img.style.backgroundSize;
document.getElementById('myresult').style.backgroundPosition = img.style.backgroundPosition;
document.getElementById('myresult').style.backgroundImage = "url('" + img2.src + "')";
}
function onwheel(e) {
var deltaY = 0;
e.preventDefault();
if (e.deltaY) {
deltaY = e.deltaY;
} else if (e.wheelDelta) {
deltaY = -e.wheelDelta;
}
var rect = img.getBoundingClientRect();
var offsetX = e.pageX - rect.left - window.pageXOffset;
var offsetY = e.pageY - rect.top - window.pageYOffset;
var bgCursorX = offsetX - bgPosX;
var bgCursorY = offsetY - bgPosY;
var bgRatioX = bgCursorX/bgWidth;
var bgRatioY = bgCursorY/bgHeight;
if (deltaY < 0) {
bgWidth += bgWidth*settings.zoom;
bgHeight += bgHeight*settings.zoom;
} else {
bgWidth -= bgWidth*settings.zoom;
bgHeight -= bgHeight*settings.zoom;
}
if (settings.maxZoom) {
bgWidth = Math.min(width*settings.maxZoom, bgWidth);
bgHeight = Math.min(height*settings.maxZoom, bgHeight);
}
bgPosX = offsetX - (bgWidth * bgRatioX);
bgPosY = offsetY - (bgHeight * bgRatioY);
if (bgWidth <= width || bgHeight <= height) {
reset();
} else {
updateBgStyle();
}
}
xhtml:
<p:panelGrid id="images" columns="1" style="border: 2px solid white;float: right;
border: 2px solid white;">
<script>
wheelzoom(document.querySelector('img.zoom'));
</script>
<img class="zoom" id="myimage" src="../../RESOURCES/images/remoteAgent/473_180420160608_HJF4013_2.jpg"
style=" width: 340px; margin-top: 20px;"/>
<div id="myresult" style="width: 340px;height: 200px; align: center; border: 1px solid black;"></div>
</p:panelGrid>
<p:commandLink style="margin: 2%; width: 15px; height: 15px;">
<h:graphicImage url="/RESOURCES/images/remoteAgent/bolaVerde.png" style="margin: 2%; width: 15px; height: 15px;"/>
<p:printer target=":form:carDetail"/>
</p:commandLink>
The zoomed/non-zoomed image doesn't appear in print preview, but i update the result img
every time the wheel event occurs
Test page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
template="/RESOURCES/template/layoutPrincipal.xhtml">
<ui:define name="head">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<style>
.parrent_ggn{
overflow: hidden;
width: 200px ;
height: 200px;
}
.parrent_ggn img{
width: 100%;
}
</style>
</ui:define>
<ui:define name="cont_principal">
<div class="parrent_ggn" id="parrent_ggn1">
<div>
<img src="https://www.w3schools.com/jsref/img_pulpit.jpg"/>
</div>
</div>
<script>
function ScrollZoom(container,max_scale,factor){
var target = container.children().first()
var size = {w:target.width(),h:target.height()}
var pos = {x:0,y:0}
var zoom_target = {x:0,y:0}
var zoom_point = {x:0,y:0}
var scale = 1
target.css('transform-origin','0 0')
target.on("mousewheel DOMMouseScroll",scrolled)
function scrolled(e){
var offset = container.offset()
zoom_point.x = e.pageX - offset.left
zoom_point.y = e.pageY - offset.top
e.preventDefault();
var delta = e.delta || e.originalEvent.wheelDelta;
if (delta === undefined) {
//we are on firefox
delta = e.originalEvent.detail;
}
delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
// determine the point on where the slide is zoomed in
zoom_target.x = (zoom_point.x - pos.x)/scale
zoom_target.y = (zoom_point.y - pos.y)/scale
// apply zoom
scale += delta*factor * scale
scale = Math.max(1,Math.min(max_scale,scale))
// calculate x and y based on zoom
pos.x = -zoom_target.x * scale + zoom_point.x
pos.y = -zoom_target.y * scale + zoom_point.y
// Make sure the slide stays in its container area when zooming out
if(pos.x>0)
pos.x = 0
if(pos.x+size.w*scale<size.w)
pos.x = -size.w*(scale-1)
if(pos.y>0)
pos.y = 0
if(pos.y+size.h*scale<size.h)
pos.y = -size.h*(scale-1)
update()
}
function update(){
target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')')
}
}
var scroll_zoom = new ScrollZoom($('#parrent_ggn1'),4,0.5);
</script>
</ui:define>
</ui:composition>

By default, a browser will ignore background css rules when printing a page, and you can't overcome this using css.
The user will need to change their browser settings.mor
To keep yourself from relying on that, put the images directly in the HTML with an actual <img /> tag.
you can set parent ‍‌overflow: hidden; and set image transform then increase scale image element for zoomable.this should work in print.
function ScrollZoom(container,max_scale,factor){
var target = container.children().first()
var size = {w:target.width(),h:target.height()}
var pos = {x:0,y:0}
var zoom_target = {x:0,y:0}
var zoom_point = {x:0,y:0}
var scale = 1
target.css('transform-origin','0 0')
target.on("mousewheel DOMMouseScroll",scrolled)
function scrolled(e){
var offset = container.offset()
zoom_point.x = e.pageX - offset.left
zoom_point.y = e.pageY - offset.top
e.preventDefault();
var delta = e.delta || e.originalEvent.wheelDelta;
if (delta === undefined) {
//we are on firefox
delta = e.originalEvent.detail;
}
delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
// determine the point on where the slide is zoomed in
zoom_target.x = (zoom_point.x - pos.x)/scale
zoom_target.y = (zoom_point.y - pos.y)/scale
// apply zoom
scale += delta*factor * scale
scale = Math.max(1,Math.min(max_scale,scale))
// calculate x and y based on zoom
pos.x = -zoom_target.x * scale + zoom_point.x
pos.y = -zoom_target.y * scale + zoom_point.y
// Make sure the slide stays in its container area when zooming out
if(pos.x>0)
pos.x = 0
if(pos.x+size.w*scale<size.w)
pos.x = -size.w*(scale-1)
if(pos.y>0)
pos.y = 0
if(pos.y+size.h*scale<size.h)
pos.y = -size.h*(scale-1)
update()
}
function update(){
target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')')
}
}
var scroll_zoom = new ScrollZoom($('#parrent_ggn1'),4,0.5);
.parrent_ggn{
overflow: hidden;
width: 200px ;
height: 200px;
}
.parrent_ggn img{
width: 100%;
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<div class="parrent_ggn" id="parrent_ggn1">
<div>
<img src="https://www.w3schools.com/jsref/img_pulpit.jpg">
</div>
</div>

Related

How to zoom or out image follow mouse position?use image element(scale、top、left)

I don’t know how to calculate the movement of the picture when it is zoom out or zoom in
Let the picture produce the feeling of zooming in or out from the mouse position, and have a natural excessive effect
The effect is similar to this
https://www.jacklmoore.com/wheelzoom/
https://github.com/jackmoore/wheelzoom
But I have to use "div" and "img" element
demo
https://i.imgur.com/hBRII3X.mp4
code is like this
const imageDiv = document.getElementById("imageDiv");
const image = document.getElementById("image");
const max = 10, min = 1, step = 0.2;
let startX = 0, startY = 0, offsetX = 0, offsetY = 0, holding = false;
function setImageTopAndLeft(image, left, top) {
const scale = parseFloat(image.dataset.scale); // current scale ratio
let currentLeft = (image.dataset.prevleft) ? parseInt(image.dataset.prevleft) : 0; // prev left value
let currentTop = (image.dataset.prevtop) ? parseInt(image.dataset.prevtop) : 0; // prev top value
let { width: imageWidth, height: imageHeight } = image.getBoundingClientRect();
let { width: constraintWidth, height: constraintHeight } = imageDiv.getBoundingClientRect();
let maxOffsetLeft = 0; // left max value
let maxOffsetTop = 0; // top max value
if (scale > 1) {
maxOffsetLeft = (imageWidth - constraintWidth) / 2; // left max value
maxOffsetTop = (imageHeight - constraintHeight) / 2; // top max value
let offsetLeft = left + currentLeft; // offset left value
let offsetTop = top + currentTop; // offset top value
if (maxOffsetLeft > 0) {
if (offsetLeft >= maxOffsetLeft) {
offsetLeft = maxOffsetLeft;
} else if (offsetLeft <= -1 * maxOffsetLeft) {
offsetLeft = -1 * maxOffsetLeft;
} else {
offsetLeft = offsetLeft * 1;
}
image.style.left = offsetLeft + "px";
}
if (maxOffsetTop > 0) {
if (offsetTop >= maxOffsetTop) {
offsetTop = maxOffsetTop;
} else if (offsetTop <= -1 * maxOffsetTop) {
offsetTop = -1 * maxOffsetTop;
} else {
offsetTop = offsetTop * 1;
}
image.style.top = offsetTop + "px";
}
}
}
function wheel(event) {
let ratio = parseFloat(image.dataset.scale);
if (event.deltaY < 0) { // 放大
ratio = ratio + step;
}
if (event.deltaY > 0) { // 縮小
ratio = ratio - step;
}
if (ratio > max) {
ratio = max;
}
if (ratio < min) {
ratio = min
}
image.dataset.scale = ratio.toFixed(2);
image.style.transform = `scale(${ratio.toFixed(2)})`
}
image.onload = () => {
imageDiv.addEventListener("wheel", (event) => {
wheel(event);
})
imageDiv.addEventListener("mousedown", (event) => {
event.preventDefault();
holding = true;
startX = event.pageX;
startY = event.pageY;
})
imageDiv.addEventListener("mousemove", (event) => {
event.preventDefault();
if (holding) {
offsetX = event.pageX - startX;
offsetY = event.pageY - startY;
setImageTopAndLeft(image, offsetX, offsetY);
}
})
imageDiv.addEventListener("mouseup", (event) => {
event.preventDefault();
holding = false;
startX = 0;
startY = 0;
image.dataset.prevleft = parseInt(image.style.left);
image.dataset.prevtop = parseInt(image.style.top);
})
}
div {
margin: auto;
width: 800px;
height: 800px;
overflow: hidden;
display: flex;
align-items: center;
/* child image vertical center */
justify-items: center;
/* child image horizontal center */
justify-content: center;
background-color: blue;
}
img {
max-width: 100%;
/*Adapt to different proportions of pictures*/
max-height: 100%;
/*Adapt to different proportions of pictures*/
position: relative;
top: 0;
/*mouse move change this value or wheel zoom then follow mouse position change this value*/
left: 0;
transform: scale(1);
/*wheel zoom or out scale image*/
}
<div id="imageDiv">
<img data-prevleft="0" data-prevtop="0" data-scale="1" id="image"
src="https://images.unsplash.com/photo-1637249833220-d399eb65e802?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80">
</div>
jsfiddle demo link: https://jsfiddle.net/0b6qaLgz/2/
sorry my english is bad
HTML
<div id="container">
<div id="slide">
<img src="https://iso.500px.com/wp-content/uploads/2014/07/big-one.jpg">
</div>
</div>
CSS
#container{
width:500px;
height:500px;
overflow:hidden;
}
#slide{
width:100%;
height:100%;
transition: transform .3s;
}
img{
width:auto;
height:auto;
max-width:100%;
}
JS
$(document).ready(function (){
var scroll_zoom = new ScrollZoom($('#container'),4,0.5)
})
function ScrollZoom(container,max_scale,factor){
var target = container.children().first()
var size = {w:target.width(),h:target.height()}
var pos = {x:0,y:0}
var zoom_target = {x:0,y:0}
var zoom_point = {x:0,y:0}
var scale = 1
target.css('transform-origin','0 0')
target.on("mousewheel DOMMouseScroll",scrolled)
function scrolled(e){
var offset = container.offset()
zoom_point.x = e.pageX - offset.left
zoom_point.y = e.pageY - offset.top
e.preventDefault();
var delta = e.delta || e.originalEvent.wheelDelta;
if (delta === undefined) {
//we are on firefox
delta = e.originalEvent.detail;
}
delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
// determine the point on where the slide is zoomed in
zoom_target.x = (zoom_point.x - pos.x)/scale
zoom_target.y = (zoom_point.y - pos.y)/scale
// apply zoom
scale += delta*factor * scale
scale = Math.max(1,Math.min(max_scale,scale))
// calculate x and y based on zoom
pos.x = -zoom_target.x * scale + zoom_point.x
pos.y = -zoom_target.y * scale + zoom_point.y
// Make sure the slide stays in its container area when zooming out
if(pos.x>0)
pos.x = 0
if(pos.x+size.w*scale<size.w)
pos.x = -size.w*(scale-1)
if(pos.y>0)
pos.y = 0
if(pos.y+size.h*scale<size.h)
pos.y = -size.h*(scale-1)
update()
}
function update(){
target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')')
}
}
FIDDLE

Zoom/scale at mouse position

I am struggling to figure out and determine how to zoom on my mouse position based on this example. (https://stackblitz.com/edit/js-fxnmkm?file=index.js)
let node,
scale = 1,
posX = 0,
posY = 0,
node = document.querySelector('.frame');
const render = () => {
window.requestAnimationFrame(() => {
let val = `translate3D(${posX}px, ${posY}px, 0px) scale(${scale})`
node.style.transform = val
})
}
window.addEventListener('wheel', (e) => {
e.preventDefault();
// Zooming happens here
if (e.ctrlKey) {
scale -= e.deltaY * 0.01;
} else {
posX -= e.deltaX * 2;
posY -= e.deltaY * 2;
}
render();
});
My desired effect is based on this example (https://codepen.io/techslides/pen/zowLd?editors=0010) when zooming in. Currently my example above only scales to the center of the "viewport" but I want it to be where my cursor currently is.
I have searched high and low for a solution that is not implemented via canvas. Any help would be appreciated!
Caveat The reason why I am using the wheel event is to mimic the interaction of Figma (the design tool) panning and zooming.
Use the canvas for zoomable content
Zooming and panning elements is very problematic. It can be done but the list of issues is very long. I would never implement such an interface.
Consider using the canvas, via 2D or WebGL to display such content to save your self many many problems.
The first part of the answer is implemented using the canvas. The same interface view is used in the second example that pans and zooms an element.
A simple 2D view.
As you are only panning and zooming then a very simple method can be used.
The example below implements an object called view. This holds the current scale and position (pan)
It provides two function for user interaction.
Panning the function view.pan(amount) will pan the view by distance in pixels held by amount.x, amount.y
Zooming the function view.scaleAt(at, amount) will scale (zoom in out) the view by amount (a number representing change in scale), at the position held by at.x, at.y in pixels.
In the example the view is applied to the canvas rendering context using view.apply() and a set of random boxes are rendered whenever the view changes.
The panning and zooming is via mouse events
Example using canvas 2D context
Use mouse button drag to pan, wheel to zoom
const ctx = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 500;
const rand = (m = 255, M = m + (m = 0)) => (Math.random() * (M - m) + m) | 0;
const objects = [];
for (let i = 0; i < 100; i++) {
objects.push({x: rand(canvas.width), y: rand(canvas.height),w: rand(40),h: rand(40), col: `rgb(${rand()},${rand()},${rand()})`});
}
requestAnimationFrame(drawCanvas);
const view = (() => {
const matrix = [1, 0, 0, 1, 0, 0]; // current view transform
var m = matrix; // alias
var scale = 1; // current scale
var ctx; // reference to the 2D context
const pos = { x: 0, y: 0 }; // current position of origin
var dirty = true;
const API = {
set context(_ctx) { ctx = _ctx; dirty = true },
apply() {
if (dirty) { this.update() }
ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5])
},
get scale() { return scale },
get position() { return pos },
isDirty() { return dirty },
update() {
dirty = false;
m[3] = m[0] = scale;
m[2] = m[1] = 0;
m[4] = pos.x;
m[5] = pos.y;
},
pan(amount) {
if (dirty) { this.update() }
pos.x += amount.x;
pos.y += amount.y;
dirty = true;
},
scaleAt(at, amount) { // at in screen coords
if (dirty) { this.update() }
scale *= amount;
pos.x = at.x - (at.x - pos.x) * amount;
pos.y = at.y - (at.y - pos.y) * amount;
dirty = true;
},
};
return API;
})();
view.context = ctx;
function drawCanvas() {
if (view.isDirty()) {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
view.apply(); // set the 2D context transform to the view
for (i = 0; i < objects.length; i++) {
var obj = objects[i];
ctx.fillStyle = obj.col;
ctx.fillRect(obj.x, obj.y, obj.h, obj.h);
}
}
requestAnimationFrame(drawCanvas);
}
canvas.addEventListener("mousemove", mouseEvent, {passive: true});
canvas.addEventListener("mousedown", mouseEvent, {passive: true});
canvas.addEventListener("mouseup", mouseEvent, {passive: true});
canvas.addEventListener("mouseout", mouseEvent, {passive: true});
canvas.addEventListener("wheel", mouseWheelEvent, {passive: false});
const mouse = {x: 0, y: 0, oldX: 0, oldY: 0, button: false};
function mouseEvent(event) {
if (event.type === "mousedown") { mouse.button = true }
if (event.type === "mouseup" || event.type === "mouseout") { mouse.button = false }
mouse.oldX = mouse.x;
mouse.oldY = mouse.y;
mouse.x = event.offsetX;
mouse.y = event.offsetY
if(mouse.button) { // pan
view.pan({x: mouse.x - mouse.oldX, y: mouse.y - mouse.oldY});
}
}
function mouseWheelEvent(event) {
var x = event.offsetX;
var y = event.offsetY;
if (event.deltaY < 0) { view.scaleAt({x, y}, 1.1) }
else { view.scaleAt({x, y}, 1 / 1.1) }
event.preventDefault();
}
body {
background: gainsboro;
margin: 0;
}
canvas {
background: white;
box-shadow: 1px 1px 1px rgba(0, 0, 0, .2);
}
<canvas id="canvas"></canvas>
Example using element.style.transform
This example uses the element style transform property to zoom and pan.
Note that I use a 2D matrix rather than the 3d matrix as that can introduce many problems not compatible with the simple zoom and pan used below.
Note that CSS transforms are not applied to the top left of the element in all cases. In the example below the origin is in the center of the element. Thus when zooming the zoom at point must be adjusted by subtracting half the elements size. The element size is not effected by the transform.
Note borders, padding, and margins will also change the location of the origin. To work with view.scaleAt(at, amount) at must be relative to the top left most pixel of the element
Note there are many more problems and caveats you need to consider when you zoom and pan elements, too many to fit in a single answer. That is why this answer starts with a canvas example as it is by far the safer method to managing zoom-able visual content.
Use mouse button drag to pan, wheel to zoom. If you lose your position (zoom too far in out or panned of the page restart the snippet)
const view = (() => {
const matrix = [1, 0, 0, 1, 0, 0]; // current view transform
var m = matrix; // alias
var scale = 1; // current scale
const pos = { x: 0, y: 0 }; // current position of origin
var dirty = true;
const API = {
applyTo(el) {
if (dirty) { this.update() }
el.style.transform = `matrix(${m[0]},${m[1]},${m[2]},${m[3]},${m[4]},${m[5]})`;
},
update() {
dirty = false;
m[3] = m[0] = scale;
m[2] = m[1] = 0;
m[4] = pos.x;
m[5] = pos.y;
},
pan(amount) {
if (dirty) { this.update() }
pos.x += amount.x;
pos.y += amount.y;
dirty = true;
},
scaleAt(at, amount) { // at in screen coords
if (dirty) { this.update() }
scale *= amount;
pos.x = at.x - (at.x - pos.x) * amount;
pos.y = at.y - (at.y - pos.y) * amount;
dirty = true;
},
};
return API;
})();
document.addEventListener("mousemove", mouseEvent, {passive: false});
document.addEventListener("mousedown", mouseEvent, {passive: false});
document.addEventListener("mouseup", mouseEvent, {passive: false});
document.addEventListener("mouseout", mouseEvent, {passive: false});
document.addEventListener("wheel", mouseWheelEvent, {passive: false});
const mouse = {x: 0, y: 0, oldX: 0, oldY: 0, button: false};
function mouseEvent(event) {
if (event.type === "mousedown") { mouse.button = true }
if (event.type === "mouseup" || event.type === "mouseout") { mouse.button = false }
mouse.oldX = mouse.x;
mouse.oldY = mouse.y;
mouse.x = event.pageX;
mouse.y = event.pageY;
if(mouse.button) { // pan
view.pan({x: mouse.x - mouse.oldX, y: mouse.y - mouse.oldY});
view.applyTo(zoomMe);
}
event.preventDefault();
}
function mouseWheelEvent(event) {
const x = event.pageX - (zoomMe.width / 2);
const y = event.pageY - (zoomMe.height / 2);
if (event.deltaY < 0) {
view.scaleAt({x, y}, 1.1);
view.applyTo(zoomMe);
} else {
view.scaleAt({x, y}, 1 / 1.1);
view.applyTo(zoomMe);
}
event.preventDefault();
}
body {
user-select: none;
-moz-user-select: none;
}
.zoomables {
pointer-events: none;
border: 1px solid black;
}
#zoomMe {
position: absolute;
top: 0px;
left: 0px;
}
<img id="zoomMe" class="zoomables" src="https://i.stack.imgur.com/C7qq2.png?s=328&g=1">
This zoom in the 2nd link is a bit extreme so I tried to add some constraints. You can uncomment them and play more. For now looks and works exactly the same IMHO.
const container = document.querySelector('.container');
const image = document.querySelector('.image');
const speed = 0.5;
let size = {
w: image.offsetWidth,
h: image.offsetHeight
};
let pos = { x: 0, y: 0 };
let target = { x: 0, y: 0 };
let pointer = { x: 0, y: 0 };
let scale = 1;
window.addEventListener('wheel', event => {
event.preventDefault();
pointer.x = event.pageX - container.offsetLeft;
pointer.y = event.pageY - container.offsetTop;
target.x = (pointer.x - pos.x) / scale;
target.y = (pointer.y - pos.y) / scale;
scale += -1 * Math.max(-1, Math.min(1, event.deltaY)) * speed * scale;
// Uncomment to constrain scale
// const max_scale = 4;
// const min_scale = 1;
// scale = Math.max(min_scale, Math.min(max_scale, scale));
pos.x = -target.x * scale + pointer.x;
pos.y = -target.y * scale + pointer.y;
// Uncomment for keeping the image within area (works with min scale = 1)
// if (pos.x > 0) pos.x = 0;
// if (pos.x + size.w * scale < size.w) pos.x = -size.w * (scale - 1);
// if (pos.y > 0) pos.y = 0;
// if (pos.y + size.h * scale < size.h) pos.y = -size.h * (scale - 1);
image.style.transform = `translate(${pos.x}px,${pos.y}px) scale(${scale},${scale})`;
}, { passive: false });
.container {
width: 400px;
height: 400px;
overflow: hidden;
outline: 1px solid gray;
}
.image {
width: 100%;
height: 100%;
transition: transform .3s;
transform-origin: 0 0;
}
img {
width: auto;
height: auto;
max-width: 100%;
}
<div class="container">
<div class="image">
<img src="https://picsum.photos/400/400" />
</div>
</div>
Here's my version, support pan and zoom (hold CTRL key).
let editor = document.getElementById("editor");
let editorCanvas = editor.querySelector(".canvas");
let scale = 1.0;
const minScale = 0.1;
const maxScale = 8;
const scaleStep = 0.003;
let ctrlDown = false;
let dragging = false;
let dragStartX = 0;
let dragStartY = 0;
let previousScrollLeft = 0;
let previousScrollTop = 0;
window.addEventListener("keydown", (e) => {
if (e.ctrlKey) {
ctrlDown = true;
editorCanvas.style.cursor = "move";
}
});
window.addEventListener("keyup", (e) => {
ctrlDown = false;
editorCanvas.style.cursor = "default";
});
editor.addEventListener("mousedown", (e) => {
dragging = true;
dragStartX = e.x - editor.offsetLeft;
dragStartY = e.y - editor.offsetTop;
previousScrollLeft = editor.scrollLeft;
previousScrollTop = editor.scrollTop;
});
editor.addEventListener("mouseup", (e) => {
dragging = false;
});
editor.addEventListener("mousemove", (e) => {
if (ctrlDown && dragging) {
requestAnimationFrame(() => {
let currentX = e.x - editor.offsetLeft;
let currentY = e.y - editor.offsetTop;
let scrollX = previousScrollLeft + (dragStartX - currentX)
let scrollY = previousScrollTop + (dragStartY - currentY);
editor.scroll(scrollX, scrollY);
});
}
});
editor.addEventListener("wheel", (e) => {
e.preventDefault();
requestAnimationFrame(() => {
if (e.ctrlKey) {
scale -= e.deltaY * scaleStep;
if (scale < minScale) {
scale = minScale;
}
if (scale > maxScale) {
scale = maxScale;
}
if (scale < 1) {
editorCanvas.style.transformOrigin = "50% 50% 0";
} else {
editorCanvas.style.transformOrigin = "0 0 0";
}
editorCanvas.style.transform = `matrix(${scale}, 0, 0, ${scale}, 0, 0)`;
let rect = editorCanvas.getBoundingClientRect();
let ew = rect.width;
let eh = rect.height;
let mx = e.x - editor.offsetLeft;
let my = e.y - editor.offsetTop;
editor.scroll((ew - editor.offsetWidth) * (mx / editor.clientWidth), (eh - editor.offsetHeight) * (my / editor.clientHeight));
} else {
editor.scrollTop += e.deltaY;
editor.scrollLeft += e.deltaX;
}
});
}, { passive: false });
body {
background-color: lightgray;
}
#editor {
position: relative;
width: 1024px;
height: 768px;
box-sizing: border-box;
border: 1px solid darkgray;
background-color: gray;
overflow: auto;
}
.canvas {
position: relative;
width: 100%;
height: 100%;
background-color: white;
}
.frame {
position: absolute;
box-sizing: border-box;
border: 1px solid darkslategrey;
transition: all 0.25s;
}
.frame.one {
top: 80px;
left: 400px;
width: 300px;
height: 250px;
background-color: pink;
}
.frame.two {
top: 350px;
left: 150px;
width: 200px;
height: 150px;
background-color: gold;
}
.frame.three {
top: 130px;
left: 70px;
width: 100px;
height: 150px;
background-color: cyan;
}
.frame.four {
top: 368px;
left: 496px;
width: 32px;
height: 32px;
background-color: lime;
}
.frame:hover {
cursor: pointer;
border: 3px solid darkslategrey;
}
.frame:active {
filter: invert();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Zoom Editor</title>
</head>
<body>
<div id="editor">
<div class="canvas">
<div class="frame one"></div>
<div class="frame two"></div>
<div class="frame three"></div>
<div class="frame four"></div>
</div>
</div>
</body>
</html>
I think you need to use an external jquery plugin to achieve this:
js file :
https://ariutta.github.io/svg-pan-zoom/dist/svg-pan-zoom.js
working demo :
https://ariutta.github.io/svg-pan-zoom/
for more clarification please visit:
https://github.com/ariutta/svg-pan-zoom

Zoom based on cursor using javascript

I've both tried to solve the problem as well as search StackOverflow for multiple solutions, none that seemed to work properly. I have what appears to be a close but not quite the end result I'm looking for. I'm trying to make it so when the user zooms using the mousewheel, the zoom being based on the cursor's position.
Could someone explain what I'm doing wrong here. Somewhere in my calculation for the image offset im doing something wrong which you'll see when you test it.
// offset image based on cursor position
var width = img_ele.getBoundingClientRect().width;
var height = img_ele.getBoundingClientRect().height;
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
var x = img_ele.offsetLeft;
var y = img_ele.offsetTop;
// Calculate displacement of zooming position.
var dx = x - ((x_cursor - x) * (factor - 1.0));
var dy = y - ((y_cursor - y) * (factor - 1.0));
img_ele.style.left = dx + 'px';
img_ele.style.top = dy + 'px';
Below is the full code. Just change the src image to one of your liking.
<!DOCTYPE html>
<html>
<body>
<div id="container">
<img ondragstart="return false" id="drag-img" src="map.jpg" />
</div>
<input type="button" id="zoomout" class="button" value="Zoom out">
<input type="button" id="zoomin" class="button" value="Zoom in">
<input type="button" id="zoomfit" class="button" value="Zoom fit">
</body>
</html>
<script>
var img_ele = null,
x_cursor = 0,
y_cursor = 0,
x_img_ele = 0,
y_img_ele = 0;
function zoom(factor) {
img_ele = document.getElementById('drag-img');
// Zoom into the image.
var width = img_ele.getBoundingClientRect().width;
var height = img_ele.getBoundingClientRect().height;
img_ele.style.width = (width * factor) + 'px';
img_ele.style.height = (height * factor) + 'px';
// offset image based on cursor position
var width = img_ele.getBoundingClientRect().width;
var height = img_ele.getBoundingClientRect().height;
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
var x = img_ele.offsetLeft;
var y = img_ele.offsetTop;
// Calculate displacement of zooming position.
var dx = x - ((x_cursor - x) * (factor - 1.0));
var dy = y - ((y_cursor - y) * (factor - 1.0));
img_ele.style.left = dx + 'px';
img_ele.style.top = dy + 'px';
console.log('MAP SIZE : ' + width, height);
console.log('MAP TOP/LEFT : ' + x, y, 'NEW:', dx, dy);
console.log('CURSOR : ' + x_cursor, y_cursor);
img_ele = null;
}
function zoom_fit() {
bb_el = document.getElementById('container')
img_el = document.getElementById('drag-img');
var width = bb_el.getBoundingClientRect().width;
var height = bb_el.getBoundingClientRect().height;
img_el.style.width = width + 'px';
img_el.style.height = height + 'px';
img_el.style.left = '0px';
img_el.style.top = '0px';
img_el = null;
}
document.getElementById('zoomout').addEventListener('click', function() {
zoom(0.9);
});
document.getElementById('zoomin').addEventListener('click', function() {
zoom(1.1);
});
document.getElementById('zoomfit').addEventListener('click', function() {
zoom_fit();
});
document.addEventListener('mousewheel', function(event) {
event.preventDefault();
x_cursor = window.event.clientX;
y_cursor = window.event.clientY;
// console.log('ZOOM : ' + 'X:', x_cursor, 'Y:', y_cursor);
if (event.deltaY < 0) {
// console.log('scrolling up');
zoom(1.1);
}
if (event.deltaY > 0) {
// console.log('scrolling down');
zoom(0.9);
}
});
function start_drag() {
img_ele = this;
// console.log('inside start_drag var img_ele set to : ' + this);
x_img_ele = window.event.clientX - document.getElementById('drag-img').offsetLeft;
y_img_ele = window.event.clientY - document.getElementById('drag-img').offsetTop;
// console.log('start_drag : ' + 'x_img_ele:', x_img_ele, 'y_img_ele:', y_img_ele);
}
function stop_drag() {
// console.log('stop drag');
img_ele = null;
}
function while_drag() {
// console.log('while_drag: ', window.event);
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
if (img_ele !== null) {
img_ele.style.left = (x_cursor - x_img_ele) + 'px';
img_ele.style.top = ( window.event.clientY - y_img_ele) + 'px';
// console.log('while_drag: ','x_cursor', x_cursor, 'x_img_ele', x_img_ele, 'y_cursor', y_cursor, 'y_img_ele', y_img_ele,'Image left and top', img_ele.style.left+' - '+img_ele.style.top);
}
}
document.getElementById('drag-img').addEventListener('mousedown', start_drag);
document.getElementById('container').addEventListener('mousemove', while_drag);
document.getElementById('container').addEventListener('mouseup', stop_drag);
function while_drag() {
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
if (img_ele !== null) {
img_ele.style.left = (x_cursor - x_img_ele) + 'px';
img_ele.style.top = ( window.event.clientY - y_img_ele) + 'px';
// console.log(img_ele.style.left+' - '+img_ele.style.top);
}
}
document.getElementById('drag-img').addEventListener('mousedown', start_drag);
document.getElementById('container').addEventListener('mousemove', while_drag);
document.getElementById('container').addEventListener('mouseup', stop_drag);
</script>
<style>
#drag-img {
cursor: move;
position: relative;
width: 400px;
height: 400px;
}
#container {
overflow: hidden;
background: red;
width: 400px;
height: 400px;
}
.button {
width: 80px;
height: 25px;
}
</style>

How to make a div follow the cursor, but shifted by Xpx towards the center of window?

Div should follow the cursor, but shifted 20px by X and Y axis toward the center of the screen, based on the quarter in which is the mouse cursor?
Like this: https://i.imgur.com/XaDk1hI.png
I used trigonometry to find vector from cursor to center of the window, so I have cursor coordinates, center coordinates, and third point C, but div moves in strange circles and I don't where I made mistake.
var lt = document.getElementById('lt')
var ltPosition = lt.getBoundingClientRect();
var element = document.getElementById('element');
var mousePosX = 0;
var mousePosY = 0;
document.onmousemove = function(e){
function angle(xCursor, yCursor, xCenter, yCenter){
var distanceA = xCursor - xCenter;
var distanceB = yCursor - yCenter;
var distanceC = Math.sqrt(distanceA*distanceA + distanceB*distanceB);
var theta = Math.atan2(distanceA, distanceB);
theta *= 180 / Math.PI;
var offsetX = distanceC * Math.sin(theta);
var offsetY = distanceC * Math.cos(theta);
function follow(x,y){
element.style.left = x + "px";
element.style.top = y +"px";
}
follow(e.clientX + offsetX, e.clientY + offsetY);
}
angle(e.clientX, e.clientY, ltPosition.right, ltPosition.bottom);
}
Here is fiddle: https://jsfiddle.net/sgvpvqhc/
What else should I do here in order to have this functionality?
What is that theta *= 180 / Math.PI; doing there? sin and cos take the angle in radians, just like atan returns it. If you want to display it, sure, convert it to degrees, but inside the Math API no conversion are needed.
(updated fiddle demo)
I though you might like this. I put it here too. https://jsfiddle.net/sgvpvqhc/5/
function mouseMover(element, offX, offY) {
var e = element,
bc = e.getBoundingClientRect();
var ox = offX,
oy = offY;
if (ox === undefined && oy === undefined) {
ox = -Math.round(bc.width / 2);
oy = -Math.round(bc.height / 2);
}
e.parentNode.onmousemove = function(eventObj) {
var ev = eventObj,
b = this.getBoundingClientRect();
var x = Math.round(ev.clientX - b.left);
var y = Math.round(ev.clientY - b.top);
e.style.left = x + (ox) + 'px';
e.style.top = y + (oy) + 'px';
}
}
mouseMover(document.getElementById('element'), 20, 20)
html, body {
margin: 0;
height: 100%;
}
.container {
width: 100%;
height: 100%;
}
#lt, #rt, #ld, #rd {
float: left;
width: 50%;
height: 50%;
display: inline-block;
}
#element {
background-color: red;
width: 50px;
height: 50px;
position: absolute;
}
#lt, #rd {
background-color: green;
}
#rt, #ld {
background-color: yellow;
}
<div id='container' class='container'>
<div id='element'></div>
<div id='lt'></div>
<div id='rt'></div>
<div id='ld'></div>
<div id='rd'></div>
</div>
<div class='box'></div>

how to make a div follow cursor inside another div, on mousemove with pure JS

I'm a beginner when it comes to pure Javascript. I would like to create an effect such as this one created with jquery:
var mouseX = 0, mouseY = 0, limitX, limitY, containerWidth;
$(document).ready(function() {
//Declaring the container size variable when we dom is ready
//Grabbing the size of an element gives a number no longer a percentage
containerWidth = $(".container").width();
containerHeight = $(".container").height();
$("#debug").html('Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight);
// cache the selector
var follower = $("#follower");
var xp = 0, yp = 0;
// limitX is now the difference between the #container's width (=80%) and 15px
limitX = containerWidth-15;
limitY = containerHeight-15;
var loop = setInterval(function(){
// change 12 to alter damping higher is slower
xp += (mouseX - xp) / 6;
yp += (mouseY - yp) / 6;
follower.css({left:xp, top:yp});
}, 15);
//Since changing the window size affects the width, we need to redefine the container size variable so that's it's current
$(window).resize(function() {
//this makes limiX change based on container width
limitX = $(".container").width()-15;
$("#debug").html('Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight);
}).resize();
$(document).on('mousemove', function (e) {
mouseX = Math.min(e.pageX, limitX);
mouseY = Math.min(e.pageY, limitY);
});
});
link to user's fiddle : http://jsfiddle.net/alexchopjian/5QfYL/5/,
but using pure Javascript. Is it possible?
I will be very grateful for any clues as how to get at this.
This is not the exact copy but it is a starting point:
var mouseX = 0, mouseY = 0, limitX, limitY, containerWidth;
window.onload = function(e) {
var containerObjStyle = window.getComputedStyle(document.querySelectorAll(".container")[0]);
containerWidth = parseFloat(containerObjStyle.width).toFixed(0);
containerHeight = parseFloat(containerObjStyle.height).toFixed(0);
document.getElementById('debug').innerHTML = 'Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight;
var follower = document.getElementById("follower");
var xp = 0, yp = 0;
limitX = containerWidth-15;
limitY = containerHeight-15;
var loop = setInterval(function(){
xp = (mouseX == limitX) ? limitX : mouseX -7;
xp = (xp < 0) ? 0 : xp;
yp = (mouseY == limitY) ? limitY : mouseY -7;
yp = (yp < 0) ? 0 : yp;
follower.style.left = xp + 'px';
follower.style.top = yp + 'px';
}, 15);
window.onresize = function(e) {
limitX = parseFloat(window.getComputedStyle(document.querySelectorAll(".container")[0]).width).toFixed(0);
document.getElementById("debug")[0].innerHTML='Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight;
}
document.onmousemove = function(e) {
mouseX = Math.min(e.pageX, limitX);
mouseY = Math.min(e.pageY, limitY);
}
};
#follower{
position : relative;
background-color : yellow;
width:15px;
height:15px;
border-radius:50px;
}
.container {
width:80%;
height:150px;
position:absolute;
top:0;
left:0;
overflow:hidden;
border:1px solid #000000;
}
<p id="debug"></p>
<div class="container">
<div id="follower"></div>
</div>

Categories

Resources