Intereting Posts
CKEditor – Возможно ли иметь контекстное меню для базовых стилей? PHP SQL: как сохранить данные в несколько баз данных из одной формы html или как автоматически копировать данные из одной базы данных в другую базу данных jQuery получить выбранное значение параметра (не текст, а атрибут «значение») Является ли ошибка в Chrome отображать границу в ячейке, где ни один не определен? Почему данный код вызывает исключение (Jsoup) Ng2-таблица не работает с последней версией Angular2 Как Facebook фиксирует верхний и нижний колонтитулы при загрузке другой страницы? Bootstrap 3 – элемент перетаскивания горизонтальный с вертикальной полосой прокрутки, переполнение-y: прокрутка HTML и PHPMySQL, вставьте много данных в таблицу из textarea ТОЧНЫЙ такой же код не работает должным образом в Dreamweaver Как вызвать class сервлета из HTML-формы под-подменю css Как загрузить изображения с помощью HTML-файла в UIWebView Ошибка символов iframe html Что не так с headerKey = “- 1”?

Элемент масштаба, пропорциональный обложке фона с помощью jQuery

У меня есть сложный вопрос: у меня есть полный профиль на сайте, над которым я работаю. Теперь я хочу привязать div к определенной позиции на изображении, а также, что div масштабируется так же, как и мое фоновое изображение с свойством «background-size: cover». Поэтому в этом примере у меня есть изображение города, которое охватывает окно браузера, и я хочу, чтобы мой div накладывал одно конкретное здание независимо от размера windows.

Мне уже удалось заставить div придерживаться одной позиции, но не могу resize. Что я сделал до сих пор:

http://codepen.io/EmmieBln/pen/YqWaYZ

var imageWidth = 1920, imageHeight = 1368, imageAspectRatio = imageWidth / imageHeight, $window = $(window); var hotSpots = [{ 'x': -160, 'y': -20, 'height': 400, 'width': 300 }]; function appendHotSpots() { for (var i = 0; i < hotSpots.length; i++) { var $hotSpot = $('
').addClass('hot-spot'); $('.container').append($hotSpot); } positionHotSpots(); } function positionHotSpots() { var windowWidth = $window.width(), windowHeight = $window.height(), windowAspectRatio = windowWidth / windowHeight, $hotSpot = $('.hot-spot'); $hotSpot.each(function(index) { var xPos = hotSpots[index]['x'], yPos = hotSpots[index]['y'], xSize = hotSpots[index]['width'], ySize = hotSpots[index]['height'], desiredLeft = 0, desiredTop = 0; if (windowAspectRatio > imageAspectRatio) { yPos = (yPos / imageHeight) * 100; xPos = (xPos / imageWidth) * 100; xSize = (xSize / imageWidth) * 1000; ySize = (ySize / imageHeight) * 1000; } else { yPos = ((yPos / (windowAspectRatio / imageAspectRatio)) / imageHeight) * 100; xPos = ((xPos / (windowAspectRatio / imageAspectRatio)) / imageWidth) * 100; } $(this).css({ 'margin-top': yPos + '%', 'margin-left': xPos + '%', 'width': xSize + 'px', 'height': ySize + 'px' }); }); } appendHotSpots(); $(window).resize(positionHotSpots);

Моя идея: If (imageWidth / windowWidth) <1, то установите значение для var Scale = (windowWidth / imageWidth) else var Scale (windowHeight / imageHeight) и использовать масштаб var Scale for transform: scale (Scale, Scale), но я не смог удастся выполнить эту работу …

Может быть, вы, ребята, могли мне помочь …

Решение для фонового размера: обложка

Я пытаюсь дать вам решение (или рассмотреть как идею). Здесь вы можете проверить рабочую демонстрацию. Измените размер windows, чтобы увидеть результат.

Во-первых, я не понял, почему вы используете transform , top:50% и left:50% для горячей точки. Поэтому я попытался решить эту проблему с использованием минимального варианта использования и скорректировал вашу разметку и CSS для удобства.

Здесь rImage – это соотношение сторон исходного изображения.

  var imageWidth = 1920; var imageHeight = 1368; var h = { x: imageWidth / 2, y: imageHeight / 2, height: 100, width: 50 }; var rImage= imageWidth / imageHeight; 

В обработчике изменения windows вычислите аспектный ракурс windows просмотра r . Далее, трюк заключается в том, чтобы найти размеры изображения при изменении размера windows. Но, видовое окно будет обрезать изображение, чтобы сохранить соотношение сторон. Поэтому для вычисления размеров изображения нам нужна некоторая формула.

При использовании background-size:cover для расчета размеров изображения, используются формулы.

 if(actual_image_aspectratio < = viewport_aspectratio) image_width = width_of_viewport image_height = width_ofviewport / actual_image_aspectratio 

А также

 if(actual_image_aspectratio > viewport_aspectratio) image_width = height_of_viewport * actual_image_aspectratio image_height = height_of_viewport 

Вы можете ссылаться на этот URL, чтобы узнать больше о расчете размеров изображений при использовании background-size:cover .

После получения размеров изображения нам нужно построить координаты «горячей точки» с фактического изображения на новые размеры изображения.

Для соответствия изображению в изображении видового экрана будут обрезаны сверху и снизу / слева и справа от изображения. Поэтому мы должны рассматривать этот размер обрезанного изображения как смещение при построении горячих точек.

 offset_top=(image_height-viewport_height)/2 offset_left=(image_width-viewport_width)/2 

добавьте эти значения смещения в координаты x,y каждого хот-спота

 var imageWidth = 1920; var imageHeight = 1368; var hotspots = [{ x: 100, y: 200, height: 100, width: 50 }, { x: 300, y: 500, height: 200, width: 100 }, { x: 600, y: 600, height: 150, width: 100 }, { x: 900, y: 550, height: 100, width: 25 }]; var aspectRatio = imageWidth / imageHeight; $(window).resize(function() { positionHotSpots(); }); var positionHotSpots = function() { $('.hotspot').remove(); var wi = 0, hi = 0; var r = $('#image').width() / $('#image').height(); if (aspectRatio < = r) { wi = $('#image').width(); hi = $('#image').width() / aspectRatio; } else { wi = $('#image').height() * aspectRatio; hi = $('#image').height(); } var offsetTop = (hi - $('#image').height()) / 2; var offsetLeft = (wi - $('#image').width()) / 2; $.each(hotspots, function(i, h) { var x = (wi * hx) / imageWidth; var y = (hi * hy) / imageHeight; var ww = (wi * (h.width)) / imageWidth; var hh = (hi * (h.height)) / imageHeight; var hotspot = $('
').addClass('hotspot').css({ top: y - offsetTop, left: x - offsetLeft, height: hh, width: ww }); $('body').append(hotspot); }); }; positionHotSpots();
 html, body { height: 100%; padding: 0; margin: 0; } #image { height: 100%; width: 100%; background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg'); background-size: cover; background-repeat: no-repeat; background-position: center; } .hotspot { position: absolute; z-index: 1; background: red; } 
  

Хорошо, поэтому многие люди не знают о CSS-измерениях vh и vw (что означает viewheight и viewwidth). Я создал сценарий, который запускается один раз в pageload (в отличие от некоторых других ответов с ~ 50 строками кода при каждом изменении размера ).

Он вычисляет отношение фонового изображения, применяет две части CSS к overlayContainer , и это делается.

Я также добавил div с square id. Все это создает квадрат для работы с ним, который имеет отношение 1: 1, а не отношение, которое имеет фон. Это гарантирует, что – если вы хотите создать квадрат – вы можете использовать ту же ширину и высоту, вместо того, чтобы вручную пытаться создать один с разными значениями. Это также пригодится, когда вы слегка изменяете размер фонового изображения, потому что с этим квадратом ваши оверлейные divs не потеряют соотношение сторон.

Для background-size: cover , см. Этот скрипт .

Для background-size: contain , см. Этот скрипт .

HTML необходим:

 

CSS необходим:

 #overlayContainer{ position: absolute; /* Fixed if the background-image is also fixed */ min-width: 100vw; /* When cover is applied */ min-height: 100vh; /* When cover is applied */ max-width: 100vw; /* When contain is applied */ max-height: 100vh; /* When contain is applied */ top: 50%; left: 50%; transform: translate(-50%, -50%); } #square{ position: relative; padding-bottom: 100%; } /* When creating divs, make them all absolutely positioned, and work with percentages only */ /* I advise looking at my Fiddle for an example */ 

Необходим JavaScript:

 var image = new Image() image.src = $('body').css('background-image').replace(/url\((['"])?(.*?)\1\)/gi,'$2').split(',')[0] /* When cover is applied, use this: */ $('#overlayContainer').css({'height':100/(image.width/image.height)+'vw','width':100/(image.height/image.width)+'vh'}) /* When contain is applied, use this: */ $('#overlayContainer').css({'height':100*(image.height/image.width)+'vw','width':100*(image.width/image.height)+'vh'}) 

Надеюсь это поможет


Обновление от @LGSon

Я не ожидал найти только CSS- решение, хотя вот оно, скрываясь в этом ответе, поэтому я решил добавить его в то же самое.

Добавив эти 2 строки в правило #overlayContainer (работает как для cover и для contain ), сценарий можно отбросить.

 width: calc(100vh * (1920 / 1368)); height: calc(100vw * (1368 / 1920)); 

Конечно, версия скрипта имеет преимущество автоматического получения значений, хотя, поскольку точка доступа имеет определенную точку местоположения в фоновом режиме, размер изображения, скорее всего, будет известен.

Образец с background-size: cover

 html, body{ height: 100%; overflow: hidden; } body{ margin: 0; background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg'); background-size: cover; background-repeat: no-repeat; background-position: center; } #overlayContainer{ position: absolute; width: calc(100vh * (1920 / 1368)); height: calc(100vw * (1368 / 1920)); min-width: 100vw; /* for cover */ min-height: 100vh; /* for cover */ /* max-width: 100vw; for contain */ /* max-height: 100vh; for contain */ top: 50%; left: 50%; transform: translate(-50%, -50%); } #square{ position: relative; padding-bottom: 100%; } #square div{ position: absolute; top: 19.75%; left: 49.75%; width: 4.75%; height: 4.75%; background-color: rgba(255,0,0,.7); border-radius: 50%; } 
 

Хорошо, поэтому я попытался использовать твою оригинальную идею и модифицировал только несколько бит здесь и там.

Вместо использования процентов, мне было проще использовать значения пикселей. Так:

 $(this).css({ 'margin-top': yPos + 'px', 'margin-left': xPos + 'px', 'width': xSize + 'px', 'height': ySize + 'px' }); 

Тогда все, что нам нужно сделать, это проверить пропорцию видового экрана, чтобы увидеть, как нам нужно модифицировать свойства div

 if (windowAspectRatio > imageAspectRatio) { var ratio = windowWidth / imageWidth; } else { var ratio = windowHeight / imageHeight; } xPos = xPos * ratio; yPos = yPos * ratio; xSize = xSize * ratio; ySize = ySize * ratio; 

Рабочий пример: http://codepen.io/jaimerodas/pen/RaGQVm

Фрагмент стека

 var imageWidth = 1920, imageHeight = 1368, imageAspectRatio = imageWidth / imageHeight, $window = $(window); var hotSpots = [{ x: -210, y: -150, height: 250, width: 120 }, { x: 240, y: 75, height: 85, width: 175 }]; function appendHotSpots() { for (var i = 0; i < hotSpots.length; i++) { var $hotSpot = $('
').addClass('hot-spot'); $('.container').append($hotSpot); } positionHotSpots(); } function positionHotSpots() { var windowWidth = $window.width(), windowHeight = $window.height(), windowAspectRatio = windowWidth / windowHeight, $hotSpot = $('.hot-spot'); $hotSpot.each(function(index) { var cambio = 1, xPos = hotSpots[index]['x'], yPos = hotSpots[index]['y'], xSize = hotSpots[index]['width'], ySize = hotSpots[index]['height'], desiredLeft = 0, desiredTop = 0; if (windowAspectRatio > imageAspectRatio) { var ratio = windowWidth / imageWidth; } else { var ratio = windowHeight / imageHeight; } xPos = xPos * ratio; yPos = yPos * ratio; xSize = xSize * ratio; ySize = ySize * ratio; $(this).css({ 'margin-top': yPos + 'px', 'margin-left': xPos + 'px', 'width': xSize + 'px', 'height': ySize + 'px' }); }); } appendHotSpots(); $(window).resize(positionHotSpots);
 html, body { margin: 0; width: 100%; height: 100%; } .container { width: 100%; height: 100%; position: relative; background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg); background-size: cover; background-repeat: no-repeat; background-position: center; } .hot-spot { background-color: red; border-radius: 0; position: absolute; top: 50%; left: 50%; z-index: 1; opacity: 0.8; content: ""; } 
  

Опираясь на css-преобразования и применяя его к одному элементу, вы получаете гораздо лучшую производительность независимо от количества горячих точек (меньшее количество манипуляций с DOM и значительно меньшее количество повторных streamов). Аппаратное ускорение также неплохое 🙂

Во-первых, метакод:

  1. Создайте .hot-spot--container внутри вашего изображения .container

  2. Создайте .hot-spot и положение / размер их в пределах .hot-spot--container

  3. Transform .hot-spot--container имитирующий background-size: cover поведение background-size: cover

  4. Повторите # 3 всякий раз, когда есть размер

Вычислите коэффициент изображения bg:

 var bgHeight = 1368; var bgWidth = 1920; var bgRatio = bgHeight / bgWidth; 

Всякий раз, когда окно изменено, пересчитайте соотношение контейнеров:

 var containerHeight = $container.height(); var containerWidth = $container.width(); var containerRatio = containerHeight / containerWidth; 

Вычислить масштабные коэффициенты для имитации background-size: cover поведение background-size: cover

 if (containerRatio > bgRatio) { //fgHeight = containerHeight //fgWidth = containerHeight / bgRatio xScale = (containerHeight / bgRatio) / containerWidth } else { //fgHeight = containerWidth / bgRatio //fgWidth = containerWidth yScale = (containerWidth * bgRatio) / containerHeight } 

… и применить преобразование к элементу контейнера с горячими точками, существенно переустановив и переустановив его «в синхронизации» с фоном:

 var transform = 'scale(' + xScale + ', ' + yScale + ')'; $hotSpotContainer.css({ 'transform': transform }); 

Спрятано: https://jsfiddle.net/ovfiddle/a3pdLodm/ (вы можете играть в окне предварительного просмотра довольно эффективно. Обратите внимание, что код можно настроить так, чтобы принимать пиксельные размеры и позиционирование для горячих точек, вам просто нужно рассмотреть контейнер и размеры изображения при расчете значений шкалы)

Обновление: поведение background-size: contain те же вычисления, за исключением случаев, когда containerRatio меньше, чем bgRatio. Достаточно обновить фон css и перевернуть знак .

Ниже представлено решение jQuery, плагин bgCoverTool переопределяет элемент, основанный на масштабе фонового изображения родителя.

 //bgCoverTool Properties $('.hot-spot').bgCoverTool({ parent: $('#container'), top: '100px', left: '100px', height: '100px', width: '100px'}) 

Демо-версия:

 $(function() { $('.hot-spot').bgCoverTool(); }); 
 html, body { height: 100%; padding: 0; margin: 0; } #container { height: 100%; width: 100%; background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg'); background-size: cover; background-repeat: no-repeat; position: relative; } .hot-spot { position: absolute; z-index: 1; background: red; left: 980px; top: 400px; height: 40px; width: 40px; opacity: 0.7; } 
 < !DOCTYPE html>    BG Cover Tool     

Более простой / лучший подход к вашей проблеме заключается в использовании элемента SVG, который лучше подходит для вашего требования. Замечательная вещь о SVG – все будет пропорционально масштабироваться по умолчанию, потому что это векторный объект, а не объект streamа документа.

Этот пример продемонстрирует технику

 < !DOCTYPE html>   SVG             

Вы можете добавлять изображения в SVG для достижения того, что вам нужно.

https://jsfiddle.net/tnt1/3f23amue/