javascript - Fitting image to screen and allow default zoom behavior
问题描述
I want to fit an image to the viewport keeping the aspect ratio and the default zoom behavior of the browser. Basically the wanted behavior is exactly like opening a local image with Chrome or Firefox. Here is the detail of my project :
- I have a huge Unsplash image of ratio 4896x3264
- I want to create kind of a "Where Is Waldo" game where the user has to zoom in to check every detail of the image. By default I want the image to fit the screen (in this case the height at 100% max). Then the user could zoom in/out with ctrl + scroll (or any other shortcut).
- It is displayed in an angular 9 application, the html of the component simply is :
<img src="../../assets/img/Background.webp"/>
And I access this html with my<router-outlet>
.
So right now when navigating to this page the image is displayed with its original size 4896x3264 which is way too tall for a regular screen. With CSS I can set the height and width to fit the viewport accordingly (and center it) as follow :
img {
max-height: 100%;
display: block;
}
However, with this solution I cannot zoom in to see the detail of the image anymore. Even if I zoom to 500% the image will stay fit (on my screen at 1536 x 722).
When opening the local image in the browser (Chrome or Firefox) I obtain the exact wanted behavior :
By default (100% zoom) it fits at 1017x678. I can zoom to 4896x3264 by clicking it. And I can gradually zoom with ctrl + scroll.
When inspecting the console I see that the width and height automatically changes when I zoom in and out :
<img style="-webkit-user-select: none;margin: auto;cursor: zoom-in;"src="file:///D:/Videotec/Background.webp" width="1083" height="722">
Is there a way to get this behavior in my application ? I found a lot of topics on fitting images with css to the viewport but I couldn't find something like my project. As English is not my native language I might have poorly search the web, let me know if something similar has already been addressed.
Actual behavior screenshot : https://ibb.co/DLChrtp
Wanted default behavior screenshot : https://ibb.co/p0hLDxn
Thanks in advance for your help.
EDIT : I am not sure that I described comprehensively the wanted behavior (my vocabulary limits me). Check @NVRM answer for more details
EDIT Workaround :
As I didn't find something out of the box I recreated the behavior with Typescript + CSS. My idea was simply to toggle ngClass from a responsive class (max-height: 100%) to a raw class with no width and height limitations. As in my game I have to retrieve the exact position of a click I used it also with scrollTo in order to center the view on the wanted coordinates.
I had to use lifecycleHook AfterViewChecked as I needed to scroll the view after the class was toggled.
I had to use a scrolled flag (boolean), otherwise the scrollTo(x,y) was also triggered when I clicked to scrollOut.
I know it is not a clean solution (I actually have more code than below, handling other stuff like dblclick etc. so some part might not seems optimal to you) but it does exactly the wanted behavior so I'll stick to it for now.
In .html
<div #videotecContainer class="videotec-container">
<img
#videotecImage
src="../../assets/img/Videotec.webp"
[ngClass]="zoomed ? 'zoomedIn' : 'zoomedOut'"
(click)="onClick($event)"
/>
</div>
In .ts :
zoomed: boolean = false;
scrolled: boolean = false;
xPosition: number;
yPosition: number;
@ViewChild("videotecImage", { static: true }) videotecImage: ElementRef;
@ViewChild("videotecContainer", { static: true }) videotecContainer: ElementRef;
onClick(event: any) {
const coordinates = this.getPixelPositions(event);
this.xPosition = coordinates.px - coordinates.clientWidth / 2;
this.yPosition = coordinates.py - coordinates.clientHeight / 2;
this.zoomImage();
}
zoomImage() {
if (this.zoomed && this.scrolled) this.scrolled = false;
this.zoomed = !this.zoomed;
}
ngAfterViewChecked() {
if (this.zoomed && !this.scrolled) {
this.videotecContainer.nativeElement.scrollTo(
this.xPosition,
this.yPosition
);
this.scrolled = true;
}
getPixelPositions(event) {
//do some calculation based on Wolfgang Fahl answer here :
//questions/34867066
}
In .css :
.zoomedOut {
max-height: 100%;
max-width: 100%;
display: block;
margin: auto;
}
.zoomedIn {
display: block;
}
#videotecImage {
overflow: scroll;
}
.videotec-container {
height: 100vh;
overflow: scroll;
background-color: black;
}
解决方案
不确定,如果这是你所追求的?但基本上,一个 div 背景和一个固定的 witdh,使用一个不响应的绝对单位(如 px),几乎是缩放时的默认行为,它也会缩放图像吗?
单击«整页»查看它与缩放的作用。
div {
height: 100vh;
background-image: url("https://i.imgur.com/p2dQlq7.jpg");
background-size: 500px auto;
background-repeat: no-repeat;
}
<body>
<div></div>
</body>
推荐阅读
- python - 将两个 PNG 图像转换为 numpy 数组会产生两种不同的形状
- angular - Angular根服务重复
- decorator - 为什么 AutoFac 多余地装饰我的服务
- jmeter - 如何在 Jmeter 中解析以 {} && 开头的 JSON 响应
- c++ - 如何将字符串与对象匹配?
- node.js - Node.js:为什么纯黑色 (#000000) 会被检测为 RGB 4、4、4?
- android-studio - 如何将 getIntent.getStringExtra("username") 放入 android 适配器 onBindViewHolder(@NonNull final ViewHolder holder, final int position)
- pandas - 使用多索引计算数据框中数字连续出现的次数
- excel - 根据另一个工作表上的数据标准填充工作表
- typescript - 如何缩小 Typescipt 中的泛型并将泛型参数强制为具体值?