Hay varios esquemas de adaptación de pantalla para pantallas grandes visuales, siempre hay uno que necesitas

Supongamos que estamos desarrollando una plataforma de construcción visual de arrastrar y soltar, que puede generar un banco de trabajo o una pantalla de visualización a gran escala arrastrando y soltando, o directamente desarrollar una pantalla a gran escala. cómo adaptar la página a la pantalla, porque estamos construyendo o desarrollando Generalmente, se basa en un ancho y alto fijo, pero el tamaño real de la pantalla puede variar. A continuación, probaremos varias soluciones simples y comunes, y analizaremos brevemente el pros y contras.

manifestación

Primero escriba uno básico demopara su uso posterior:

<script setup>
import {
      
       ref } from "vue";
import Widget from "./components/Widget.vue";
import LineChart from "./components/LineChart.vue";
import BarChart from "./components/BarChart.vue";
import PieChart from "./components/PieChart.vue";
import FunnelChart from "./components/FunnelChart.vue";

// 画布宽高
const canvasWidth = ref(1920);
const canvasHeight = ref(1080);
// 组件宽高
const widgetWidth = ref(960);
const widgetHeight = ref(540);
</script>

<template>
  <div class="canvasBox">
    <div
      class="canvas"
      :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
    >
      <Widget :width="widgetWidth" :height="widgetHeight" :left="0" :top="0">
        <LineChart></LineChart>
      </Widget>
      <Widget :width="widgetWidth" :height="widgetHeight" :left="widgetWidth" :top="0">
        <BarChart></BarChart>
      </Widget>
      <Widget :width="widgetWidth" :height="widgetHeight" :left="0" :top="widgetHeight">
        <PieChart></PieChart>
      </Widget>
      <Widget :width="widgetWidth" :height="widgetHeight" :left="widgetWidth" :top="widgetHeight">
        <FunnelChart></FunnelChart>
      </Widget>
    </div>
  </div>
</template>

<style scoped>
.canvasBox {
      
      
  width: 100vw;
  height: 100vh;
}
.canvas {
      
      
  position: relative;
}
</style>

El ancho y el alto de cada componente del gráfico se establecen 100%y luego Widgetse envuelven por el componente, por lo que el ancho y el alto reales dependen del Widgetcomponente, Widgetel componente está absolutamente posicionado y el ancho, el alto y la posición se pasan propspara simular nuestro arrastre y operación drop Para simplificar, establecemos el ancho y el alto de todos los gráficos para que sean iguales.

WidgetComponentes:

<script setup>
const props = defineProps({
      
      
  width: {
      
      
    type: Number,
    default: 0,
  },
  height: {
      
      
    type: Number,
    default: 0,
  },
  left: {
      
      
    type: Number,
    default: 0,
  },
  top: {
      
      
    type: Number,
    default: 0,
  },
});
</script>

<template>
  <div
    class="widgetBox"
    :style="{
      width: width + 'px',
      height: height + 'px',
      left: left + 'px',
      top: top + 'px',
    }"
  >
    <slot></slot>
  </div>
</template>

<style scoped>
.widgetBox {
      
      
  position: absolute;
}
</style>

El contenedor general del componente es el elemento con el nombre de clase canvas, que está relativamente posicionado, y el ancho y el alto también se configuran dinámicamente. El ancho y el alto canvasdel canvasBoxelemento principal del elemento se configuran para que sean consistentes con el ancho de la pantalla y altura.

tamaño fijo

Es decir, el ancho y el alto son fijos, y si el ancho y el alto son más pequeños que el ancho y el alto de la pantalla, se centrará en la pantalla.

Esta es la solución más simple, que equivale a no ajustar la pantalla. El tamaño de la configuración del lienzo es en realidad el tamaño y no cambia con el cambio de pantalla. Por lo tanto, el ancho y la altura de cada componente no cambiarán después configuración Generalmente se usa para tamaño fijo y una gran pantalla visual que no cambiará más tarde.

Nuestra demoinicial anterior es así:

Por supuesto, si el ancho y el alto son más pequeños que la pantalla, se debe agregar la lógica del centrado. Hay muchos métodos de centrado, se pueden pasar ambos cssy jspuede hacerlo de acuerdo con sus preferencias:

// 画布的位置
const canvasLeft = ref(0);
const canvasTop = ref(0);
// 如果屏幕的宽或高比画布的大,那么居中显示
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
if (windowWidth > canvasWidth.value) {
    
    
    canvasLeft.value = (windowWidth - canvasWidth.value) / 2;
}
if (windowHeight > canvasHeight.value) {
    
    
    canvasTop.value = (windowHeight - canvasHeight.value) / 2;
}
<div
      class="canvas"
      :style="{
        width: canvasWidth + 'px',
        height: canvasHeight + 'px',
        left: canvasLeft + 'px',
        top: canvasTop + 'px',
      }"
    >
</div>

Determine si el ancho y la altura de la ventana son mayores que el ancho y la altura del lienzo, en caso afirmativo, ajuste con lefto :top

ancho adaptable

Es decir, el ancho se adapta a la pantalla, y la altura se mantiene sin cambios.La desventaja de esta solución es que habrá barras de desplazamiento en la dirección vertical.

Por ejemplo, si el ancho del lienzo se establece en 1920, pero el ancho real de la pantalla es 1280, 1.5entonces el ancho del lienzo y cada componente deben reducirse en 1.5un factor de 2, y leftel valor de cada componente también debe ajustarse. dinamicamente.

Primero implemente canvasel ajuste de tamaño del elemento contenedor:

// 保存原始画布的宽度
const originCanvasWidth = ref(canvasWidth.value);
// 宽度缩放比例
const ratioWidth = ref(1);

// 当前窗口的宽度
let windowWidth = window.innerWidth;
// 将画布宽度设置为当前窗口的宽度
canvasWidth.value = windowWidth;
// 计算当前宽度和原始宽度的比例
ratioWidth.value = windowWidth / originCanvasWidth.value;

Luego pase esta relación al Widgetcomponente para el ajuste:

<Widget :ratioWidth="ratioWidth">
    <LineChart></LineChart>
</Widget>
<Widget :ratioWidth="ratioWidth">
    <BarChart></BarChart>
</Widget>
<Widget :ratioWidth="ratioWidth">
    <PieChart></PieChart>
</Widget>
<Widget :ratioWidth="ratioWidth">
    <FunnelChart></FunnelChart>
</Widget>

En Widgetel componente, solo leftnecesitamos multiplicar el ancho y la suma por esta razón. ¿Por qué se multiplica? Es muy simple:

newWidth / width = ratioWidth = windowWidth / originCanvasWidth
newWidth = width * ratioWidth

// left同样看做是一个距左侧的宽度即可
<div
    class="widgetBox"
    :style="{
      width: width * ratioWidth + 'px',
      height: height + 'px',
      left: left * ratioWidth + 'px',
      top: top + 'px',
    }"
  >
    <slot></slot>
</div>

pantalla adaptativa

Es decir, el ancho y el alto son adaptables. En comparación con la solución anterior, no habrá barras de desplazamiento de esta manera y puede llenar completamente la pantalla.

La implementación también es muy simple, solo agregue la adaptación de altura sobre la base del [Ancho adaptable] anterior.

// 画布原始宽高
const originCanvasWidth = ref(canvasWidth.value);
const originCanvasHeight = ref(canvasHeight.value);
// 缩放比例
const ratioWidth = ref(1);
const ratioHeight = ref(1);

// 当前窗口的宽高
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
// 将画布宽高设置为当前窗口的宽高
canvasWidth.value = windowWidth;
canvasHeight.value = windowHeight;
// 计算当前宽高和原始宽高的比例
ratioWidth.value = windowWidth / originCanvasWidth.value;
ratioHeight.value = windowHeight / originCanvasHeight.value;

También pase la relación al Widgetcomponente para el ajuste:

<Widget :ratioWidth="ratioWidth" :ratioHeight="ratioHeight">
    <LineChart></LineChart>
</Widget>
<Widget :ratioWidth="ratioWidth" :ratioHeight="ratioHeight">
    <BarChart></BarChart>
</Widget>
<Widget :ratioWidth="ratioWidth" :ratioHeight="ratioHeight">
    <PieChart></PieChart>
</Widget>
<Widget :ratioWidth="ratioWidth" :ratioHeight="ratioHeight">
    <FunnelChart></FunnelChart>
</Widget>
<div
    class="widgetBox"
    :style="{
      width: width * ratioWidth + 'px',
      height: height * ratioHeight + 'px',
      left: left * ratioWidth + 'px',
      top: top * ratioHeight + 'px',
    }"
  >
    <slot></slot>
</div>

Escalado general

Es decir, el contenedor del componente se escala como un todo a través del atributo, manteniendo la proporción original y mostrándolo en el centro de la pantalla. Por supuesto, puede optar por escalar solo el ancho o el alto, pero esto se cssdeformará transform.canvas

Para las dos soluciones anteriores, debemos considerar el ancho y la altura del contenedor al desarrollar componentes, es decir, debemos adaptarnos, pero la relación de aspecto es demasiado extrema para ser honesto, es difícil de tratar y el efecto de visualización es definitivamente relativamente pobre, pero este tipo de La adaptación proporcional general no necesita considerar esta situación.

En proyectos reales, si hay una pantalla grande que necesita adaptarse a la pantalla, suelo usar este método, la ventaja es que es simple, y la desventaja es que puede haber un espacio en blanco en el espacio horizontal o vertical, pero el fondo es pantalla completa, por lo que el efecto no será malo.

La implementación también es muy simple. Calcule la proporción original del lienzo, luego calcule la proporción de la pantalla y luego juzgue si el ancho es consistente con la pantalla y la altura es adaptable, o si la altura es consistente con la pantalla y el el ancho es adaptativo:

// 当前窗口宽高比例
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
let windowRatio = windowWidth / windowHeight;
// 画布原始宽高比例
const canvasRatio = canvasWidth.value / canvasHeight.value;
// 计算画布适应后的新宽高
let newCanvasWidth = 0;
let newCanvasHeight = 0;
if (canvasRatio > windowRatio) {
    
    // 画布的宽高比大于屏幕的宽高比
    // 画布的宽度调整为屏幕的宽度
    newCanvasWidth = windowWidth;
    // 画布的高度根据画布原比例进行缩放
    newCanvasHeight = windowWidth / canvasRatio;
} else {
    
    // 画布的宽高比小于屏幕的宽高比
    // 画布的高度调整为屏幕的高度
    newCanvasHeight = windowHeight;
    // 画布的宽度根据画布原比例进行缩放
    newCanvasWidth = windowHeight * canvasRatio;
}
// ...

Suponiendo que la pantalla tiene el mismo ancho y alto, entonces la relación es 1.

En el primer caso, suponiendo que el ancho del lienzo es el doble de la altura, entonces la relación es 2, para mantener la relación original 2para ajustarse a la pantalla, obviamente solo el ancho es el mismo que la pantalla, y la altura es adaptativa, porque si la altura es la misma que la pantalla, entonces el ancho debe ser la altura el doble del tamaño, la pantalla obviamente no puede mostrar:

En el segundo caso, suponiendo que la altura del lienzo es el doble del ancho, entonces la relación es 0.5, para mantener la relación para que 0.5se ajuste a la pantalla, la altura debe ser consistente con la pantalla y el ancho es adaptable:

Después de calcular el nuevo ancho y alto del lienzo adaptado a la pantalla, puede calcular su relación de escala en relación con el ancho y el alto originales del lienzo:

// ...
// 相对于画布原始宽高的缩放比例
const canvasStyle = reactive({
    
    
    transform: "",
});
const scaleX = newCanvasWidth / canvasWidth.value;
const scaleY = newCanvasHeight / canvasHeight.value;
canvasStyle.transform = `scale(${
      
      scaleX}, ${
      
      scaleY})`

Simplemente agregue el estilo canvasal elemento contenedor:

<div
      class="canvas"
      :style="{
        width: canvasWidth + 'px',
        height: canvasHeight + 'px',
        ...canvasStyle
      }"
    >
</div>

La posición que se muestra parece ser un poco problemática. Esto se debe a que, de forma predeterminada, la transformación del elemento se transforma con su propio punto central como origen:

Solo necesitamos cambiar la esquina superior izquierda como origen:

const canvasStyle = reactive({
    
    
  transform: "",
  transformOrigin: `left top`// 改成以左上角为变换原点
});

Finalmente centrémoslo:

// 居中
const translateX = (windowWidth - newCanvasWidth) / 2 / scaleX;
const translateY = (windowHeight - newCanvasHeight) / 2 / scaleY;
canvasStyle.transform = `scale(${
      
      scaleX}, ${
      
      scaleY}) translate(${
      
      translateX}px, ${
      
      translateY}px)`;

El ancho y el alto de la ventana menos el nuevo ancho y alto después de adaptar el lienzo, es decir, el espacio restante, y luego dividirlo por la 2pantalla centrada, ¿por qué debería dividirse por el valor del zoom, porque translateel valor de también lo hará? scaleser escalado en consecuencia, por ejemplo, translateXcalculado como 100, scaleXpara 0.5, entonces el desplazamiento final real es 100*0.5=50, lo que obviamente es incorrecto, por lo que dividimos un valor de escala para compensar.

Esta solución parece ser perfecta, entonces, ¿hay algún problema? Obviamente, hay un pequeño problema de que el texto puede estar borroso después de hacer zoom, lo cual no es un gran problema. Otro problema que encontré es que si el método se usa para obtener elementos información getBoundingClientRect, la intención original es obtener los datos del tamaño original del elemento, pero después de hacer zoom, se devuelven los datos ampliados, por lo que puede desviarse de nuestra intención original, por ejemplo, hay uno como sigue div:

<div ref="el1" style="width: 200px; height: 200px; background: red; position: absolute; left: 50px; top: 50px;"></div>

Queremos divhacer dinámicamente una copia basada en este tamaño y posición div:

<div ref="el2" style="background: green; position: absolute"></div>
const {
    
     width, height } = el1.value.getBoundingClientRect();
const {
    
     left, top } = window.getComputedStyle(el1.value);
el2.value.style.width = `${
      
      width}px`;
el2.value.style.height = `${
      
      height}px`;
el2.value.style.left = left;
el2.value.style.top = top;

Se puede ver que la relación de aspecto obtenida es un poco más pequeña que la real, que obviamente no es lo que necesitamos. La solución es no usar el getBoundingClientRectmétodo, usar offsetWdithun método o atributo que no se verá afectado por la escala para obtener el tamaño del elemento, o utilice los datos obtenidos divididos por el valor de escala.

Por supuesto, puede haber otros atributos o métodos que también tengan este problema, lo que requiere que lo pruebe durante el desarrollo real.

Resumir

Este artículo resume brevemente varios métodos de adaptación a la pantalla grande, ninguno de los cuales es el mejor, y nadie es perfecto. No hay manera, y en muchos casos se requiere un cierto compromiso.

demoDirección: https://wanglin2.github.io/visual-drag-platform-fit-demo/

demoDirección del almacén: https://github.com/wanglin2/visual-drag-platform-fit-demo

Supongo que te gusta

Origin blog.csdn.net/sinat_33488770/article/details/127836884
Recomendado
Clasificación