Selecting a div that are overlaying - javascript

I have side tabs that are overlaying. I want to be able to click one and do something with it, but I am having trouble getting my event handlers to register correct div.
<div class="tabs">
<div class="blueTab">
<div class="blueTab__container">
</div>
</div>
<div class="brownTab">
<div class="brownTab__container">
</div>
</div>
</div>
.tabs {
position: relative;
margin-left: 853px;
}
.brownTab {
position: absolute;
.brownTab__container {
background-image: url(https://i.imgur.com/Fd49HkH.png) !important;
background-repeat: no-repeat !important;
width: 400px;
height: 853px;
}
}
.blueTab {
position: absolute;
.blueTab__container {
background-image: url(https://i.imgur.com/F5qg6xo.png) !important;
background-repeat: no-repeat !important;
width: 400px;
height: 873px;
}
}
let brownTabElement = document.getElementsByClassName('brownTab')[0]
let blueTabElement = document.getElementsByClassName('blueTab')[0]
brownTabElement.addEventListener('click', brownTabHandler, false)
blueTabElement.addEventListener('click', blueTabHandler, false)
function brownTabHandler() {
alert('brownTab')
}
function blueTabHandler() {
alert('blueTab')
}
When ever I click both the blue or brown tab, only the event handler for the browntab gets called. How can I fix this?
https://jsfiddle.net/Le80rvL0/3/

Your problem is that, even though you can see both tabs (because their backgrounds are partially transparent), the .brownTab__container element is overlapping the .blueTab__container, as they are in the exact same position, so you always click on that one. You can see that using the developer tools' inspector.
One solution to your problem would be to actually create different, non-overlapping elements that look like tabs. Maybe something like this or like this.
Another solution could be to use a single HTML element with a single background image of all the tabs, get the color of the clicked pixel and use it to distinguish the clicked tab. Something like this:
const message = document.getElementById('message');
// Get the tabs element:
const tabs = document.getElementById('tabs');
// Get its computed styles:
const style = window.getComputedStyle(tabs);
// Extract the background-image's url:
const backgroundImage = style.getPropertyValue('background-image');
const url = backgroundImage.substring(5, backgroundImage.length - 2);
// Create an image with that url:
const img = document.createElement('IMG');
img.src = url;
// Create a canvas with the original size of the image:
const canvas = document.createElement('CANVAS');
const width = canvas.width = 1;
const height = canvas.height = 123;
// Draw that image on it:
canvas.getContext('2d').drawImage(img, 0, 0, width, height);
// Listen for click events:
document.getElementById('tabs').addEventListener('click', (e) => {
// Get clicked pixel's RGBA value, taking into account the image on the tabs element is
// repeated, while the one on the canvas it's not:
const rgba = canvas.getContext('2d').getImageData(e.offsetX % width, e.offsetY % height, 1, 1).data;
// Set color thresholds for each tab (as in your images the colors are not uniform as
// they are here:
if (rgba[2] > 200) {
message.innerText = 'You clicked the blue tab.';
} else if (rgba[2] < 150 && rgba[1] > 50) {
message.innerText = 'You clicked the brown tab.';
} else if (rgba[1] > 200) {
message.innerText = 'You clicked the gold tab.';
} else if (rgba[1] < 50) {
message.innerText = 'You clicked the purple tab.';
} else {
message.innerText = 'Unknown tab clicked.';
}
});
body {
position: relative;
margin: 0;
height: 800px;
}
#message {
position: fixed;
top: 0;
left: 0;
right: 90px;
padding: 16px;
font-size: 32px;
}
#tabs {
position: absolute;
width: 90px;
height: 100%;
top: 0;
right: 0;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAB7CAYAAAC1rOouAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAqSURBVChTYzAOPfN/kBJnGtIGK/H+yYbBSpzRBjkSRNzUTkfmDhyR9h8AMPtPIMUTD3YAAAAASUVORK5CYII=);
}
<div id="message"></div>
<div id="tabs"></div>
Keep in mind that with the first approach it will be way easier to add other effects and features like hover/active/focus styles, add/remove tabs, move tabs, drag tabs...

Related

On image change magnifier's image is not changing

But When i select the other picture it did not show in magnifier box, instead it show the default picture in magnifier. how i can fix that?. I want to change the image after selecting from below and magnifier should work on that image.
and magnifier position is very downside, can we also make the appropriate position
HTML
Css
.product-image {
height: 300px;
cursor: zoom-in;
}
.magnifier-container {
display: inline-block;
position: relative;
}
.magnifier {
display: none;
position: absolute;
top: 0;
left: 100%;
overflow: hidden;
height: 300px;
width: 300px;
border: 1px solid #ddd;
border-radius: 10px;
background-color: white;
}
.magnifier__img {
width: 1000px;
transform-origin: 150px 150px;
}
js
// most efficient way to add HTML, faster than innerHTML
const parseHTML = (htmlStr) => {
const range = document.createRange();
range.selectNode(document.body); // required in Safari
return range.createContextualFragment(htmlStr);
};
// pass this function any image element to add magnifying functionality
const makeImgMagnifiable = (img) => {
const magnifierFragment = parseHTML(`
<div class="magnifier-container">
<div class="magnifier">
<img class="magnifier__img" src="${img.src}"/>
</div>
</div>
`);
// This preserves the original element reference instead of cloning it.
img.parentElement.insertBefore(magnifierFragment, img);
const magnifierContainerEl = document.querySelector(".magnifier-container");
img.remove();
magnifierContainerEl.appendChild(img);
// query the DOM for the newly added elements
const magnifierEl = magnifierContainerEl.querySelector(".magnifier");
const magnifierImg = magnifierEl.querySelector(".magnifier__img");
// set up the transform object to be mutated as mouse events occur
const transform = {
translate: [0, 0],
scale: 1,
};
// shortcut function to set the transform css property
const setTransformStyle = (el, { translate, scale }) => {
const [xPercent, yRawPercent] = translate;
const yPercent = yRawPercent < 0 ? 0 : yRawPercent;
// make manual pixel adjustments to better center
// the magnified area over the cursor.
const [xOffset, yOffset] = [
`calc(-${xPercent}% + 250px)`,
`calc(-${yPercent}% + 70px)`,
];
el.style = `
transform: scale(${scale}) translate(${xOffset}, ${yOffset});
`;
};
// show magnified thumbnail on hover
img.addEventListener("mousemove", (event) => {
const [mouseX, mouseY] = [event.pageX + 40, event.pageY - 20];
const { top, left, bottom, right } = img.getBoundingClientRect();
transform.translate = [
((mouseX - left) / right) * 100,
((mouseY - top) / bottom) * 100,
];
magnifierEl.style = `
display: block;
top: ${mouseY}px;
left: ${mouseX}px;
`;
setTransformStyle(magnifierImg, transform);
});
// zoom in/out with mouse wheel
img.addEventListener("wheel", (event) => {
event.preventDefault();
const scrollingUp = event.deltaY < 0;
const { scale } = transform;
transform.scale =
scrollingUp && scale < 3
? scale + 0.1
: !scrollingUp && scale > 1
? scale - 0.1
: scale;
setTransformStyle(magnifierImg, transform);
});
// reset after mouse leaves
img.addEventListener("mouseleave", () => {
magnifierEl.style = "";
magnifierImg.style = "";
});
};
const img = document.querySelector(".product-image");
makeImgMagnifiable(img);

How do I move an element with mouse event movement without changing its size in Javascript?

I am developing a custom element representing a window in an operating system. Like a window, it should be moveable/draggable. I can successfully move the window with this code:
moveVertically(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.setTop(boundingClientRect.top + movement)
this.setBottom(boundingClientRect.bottom + movement)
}
moveHorizontally(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.setLeft(boundingClientRect.left + movement)
this.setRight(boundingClientRect.right + movement)
}
The argument movement is mouse event variable movementY and movementX, respectively. The problem is that, if I move the window to quickly, it resizes as well.
How do I move the window without resizing it?
Edit: With this code:
moveVertically(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.style.transform =
`translateY(${boundingClientRect.top + movement}px)`
}
moveHorizontally(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.style.transform =
`translateX(${boundingClientRect.left + movement}px)`
}
the window kind of just moves up and down, when I try to move it. If I comment one of the methods out, it works perfectly, but I can't get both to work at the same time.
I haven't changed my resizing method yet, but that probably doesn't matter.
The reason why your second attempt doesn't work is because you are overwriting the CSS transform. You will need to persist the values on either axis: this can be done by using CSS custom properties for example.
The example below is an adapted example based on your code. The --translate-x and --translate-y are CSS custom properties that can be adjusted individually and they are simply being assigned to the CSS transform property using transform: translate(var(--translate-x, 0), var(--translate-y, 0)); (the fallback value is set to 0):
const stage = document.querySelector('#stage');
const el = document.querySelector('#el');
function moveVertically(movement) {
el.style.setProperty('--translate-y', `${movement}px`);
}
function moveHorizontally(movement) {
el.style.setProperty('--translate-x', `${movement}px`);
}
stage.addEventListener('mousemove', e => {
moveHorizontally(e.clientX);
moveVertically(e.clientY);
});
body {
margin: 0;
padding: 0;
}
#stage {
position: relative;
width: 100vw;
height: 100vh;
}
#el {
position: absolute;
width: 100px;
height: 100px;
background-color: steelblue;
transform: translate(var(--translate-x, 0), var(--translate-y, 0));
}
<div id="stage">
<div id="el"></div>
</div>
Alternatively you can also store the XY coordinates into a variable:
const stage = document.querySelector('#stage');
const el = document.querySelector('#el');
const elCoords = { x: 0, y: 0 };
function moveVertically(movement) {
elCoords.y = movement;
}
function moveHorizontally(movement) {
elCoords.x = movement;
}
stage.addEventListener('mousemove', e => {
moveHorizontally(e.clientX);
moveVertically(e.clientY);
el.style.transform = `translate(${elCoords.x}px, ${elCoords.y}px)`;
});
body {
margin: 0;
padding: 0;
}
#stage {
position: relative;
width: 100vw;
height: 100vh;
}
#el {
position: absolute;
width: 100px;
height: 100px;
background-color: steelblue;
}
<div id="stage">
<div id="el"></div>
</div>

Padding-top prevents dragging elements

I have created a card tracker for a game.
It is based on a grid pattern of different divs that overlay a background image. Within these divs are smaller images that represent the cards and can be dragged from one div to the next.
I would like the divs to scale with the window, but they need to retain their aspect ratio so that they still overlay the correct parts of the background image as that scales.
I can get this working using "padding-top" for the divs; however, this then makes the smaller appear at the very bottom of that div and extends the div, and prevents them being dragged out and I can't see why it has this effect.
Many thanks in advance for any help!
Here's an example div without padding-top applied:
#div33 {
position: absolute;
top: 250px;
left: 542px;
width: 270px;
height: 350px;
margin: 2px;
padding: 2px;
background-color: rgba(255, 184, 53, 0.);
}
The draggable elements:
.draggable {
padding: 0px;
background-color: rgba(255, 255, 255, 0);
cursor: move;
padding: 1px;
}
.draggable.dragging {
opacity: .1;
}
and the script for dragging and dropping:
<script>
const draggables = document.querySelectorAll('.draggable')
const containers = document.querySelectorAll('.container')
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', () => {
draggable.classList.add('dragging')
})
draggable.addEventListener('dragend', () => {
draggable.classList.remove('dragging')
})
})
containers.forEach(container => {
container.addEventListener('dragover', e => {
e.preventDefault()
const afterElement = getDragAfterElement(container, e.clientY)
const draggable = document.querySelector('.dragging')
if (afterElement == null) {
container.appendChild(draggable)
} else {
container.insertBefore(draggable, afterElement)
}
})
})
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect()
const offset = y - box.top - box.height / 2
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child }
} else {
return closest
}
}, { offset: Number.NEGATIVE_INFINITY }).element
}
</script>
I think I have answered my own question. I've just found out about the newer "aspect-ratio" property.

Trying to get this smoother and more natural in behavior

My implementation,
http://kodhus.com/kodnest/land/PpNFTgp
I am curious, as I am not able for some reason to figure this out, how to get my JavaScript to make my slider behave more natural and smoother, if someone knows, how to, or can make this, feel free. I'd be happy to understand.
JavaScript:
const thumb = document.querySelector('.thumb');
const thumbIndicator = document.querySelector('.thumb .thumb-indicator');
const sliderContainer = document.querySelector('.slider-container');
const trackProgress = document.querySelector('.track-progress');
const sliderContainerStart = sliderContainer.offsetLeft;
const sliderContainerWidth = sliderContainer.offsetWidth;
var translate;
var dragging = false;
var percentage = 14;
document.addEventListener('mousedown', function(e) {
if (e.target.classList.contains('thumb-indicator')) {
dragging = true;
thumbIndicator.classList.add('focus');
}
});
document.addEventListener('mousemove', function(e) {
if (dragging) {
console.log('moving', e)
if (e.clientX < sliderContainerStart) {
translate = 0;
} else if (e.clientX > sliderContainerWidth + sliderContainerStart) {
translate = sliderContainerWidth;
} else {
translate = e.clientX - sliderContainer.offsetLeft;
}
thumb.style.transform = 'translate(-50%) translate(' + translate + 'px)';
trackProgress.style.transform = 'scaleX(' + translate / sliderContainerWidth + ')'
}
});
function setPercentage() {
thumb.style.transform = 'translate(-50%) translate(' + percentage/100 * sliderContainerWidth + 'px)';
trackProgress.style.transform = 'scaleX(' + percentage/100 + ')';
}
function init() {
setPercentage();
}
init();
document.addEventListener('mouseup', function(e) {
dragging = false;
thumbIndicator.classList.remove('focus');
});
EDIT: Is there a way to smoothly and naturally increment by one for every slow move?
Is it possible to make to behave as if, like when one clicks the progress bar so that it jumps there?
The kodhus site is very janky in my browser, so I can't tell if your code lacks responsiveness or whether it's the site itself. I feel that your code is a bit convoluted: translate and width / height are mixed unnecessarily; no need to use a dragging boolean when that information is always stored in the classlist. The following slider performs nicely, and has a few considerations I don't see in yours:
stopPropagation when clicking the .thumb element
drag stops if window loses focus
pointer-events: none; applied to every part of the slider but the .thumb element
let applySliderFeel = (slider, valueChangeCallback=()=>{}) => {
// Now `thumb`, `bar` and `slider` are the elements that concern us
let [ thumb, bar ] = [ '.thumb', '.bar' ].map(v => slider.querySelector(v));
let changed = amt => {
thumb.style.left = `${amt * 100}%`;
bar.style.width = `${amt * 100}%`;
valueChangeCallback(amt);
};
// Pressing down on `thumb` activates dragging
thumb.addEventListener('mousedown', evt => {
thumb.classList.add('active');
evt.preventDefault();
evt.stopPropagation();
});
// Releasing the mouse button (anywhere) deactivates dragging
document.addEventListener('mouseup', evt => thumb.classList.remove('active'));
// If the window loses focus dragging also stops - this can be a very
// nice quality of life improvement!
window.addEventListener('blur', evt => thumb.classList.remove('active'));
// Now we have to act when the mouse moves...
document.addEventListener('mousemove', evt => {
// If the drag isn't active do nothing!
if (!thumb.classList.contains('active')) return;
// Compute `xRelSlider`, which is the mouse position relative to the
// left side of the slider bar. Note that *client*X is compatible with
// getBounding*Client*Rect, and using these two values we can quickly
// get the relative x position.
let { width, left } = slider.getBoundingClientRect();
// Consider mouse x, subtract left offset of slider, and subtract half
// the width of the thumb (so drags position the center of the thumb,
// not its left side):
let xRelSlider = evt.clientX - left - (thumb.getBoundingClientRect().width >> 1);
// Clamp `xRelSlider` between 0 and the slider's width
if (xRelSlider < 0) xRelSlider = 0;
if (xRelSlider > width) xRelSlider = width;
// Apply styling (using percents is more robust!)
changed(xRelSlider / width);
evt.preventDefault();
evt.stopPropagation();
});
slider.addEventListener('mousedown', evt => {
let { width, left } = slider.getBoundingClientRect();
// Clicking the slider also activates a drag
thumb.classList.add('active');
// Consider mouse x, subtract left offset of slider, and subtract half
// the width of the thumb (so drags position the center of the thumb,
// not its left side):
let xRelSlider = evt.clientX - left - (thumb.getBoundingClientRect().width >> 1);
// Apply styling (using percents is more robust!)
changed(xRelSlider / width);
evt.preventDefault();
evt.stopPropagation();
});
changed(0);
};
let valElem = document.querySelector('.value');
applySliderFeel(document.querySelector('.slider'), amt => valElem.innerHTML = amt.toFixed(3));
.slider {
position: absolute;
width: 80%; height: 4px; background-color: rgba(0, 0, 0, 0.3);
left: 10%; top: 50%; margin-top: -2px;
}
.slider > .bar {
position: absolute;
left: 0; top: 0; width: 0; height: 100%;
background-color: #000;
pointer-events: none;
}
.slider > .thumb {
position: absolute;
width: 20px; height: 20px; background-color: #000; border-radius: 100%;
left: 0; top: 50%; margin-top: -10px;
}
.slider > .thumb.active {
box-shadow: 0 0 0 5px rgba(0, 0, 0, 0.5);
}
<div class="slider">
<div class="bar"></div>
<div class="thumb"></div>
</div>
<div class="value"></div>

Making a fix scaled timeline in HTML/CSS/JS

Sorry, this is going to be a little long...
A bit of context
As part of a larger project I'm trying to make a project timeline to include in a webpage used to remote control a music making program (called Reaper for those who are interested). I'm trying to get it to display the current play position, the project markers, and project regions. These are all served straight from the program's API, no problem getting the info. For starters I'm just trying to display the project markers, however I've been pulling my hair out for over a week now trying to get it to work.
Here's a quick screencap from inside the software to illustrate what I'm trying to emulate: Reaper ruler screencap
Normally I would use a progress bar for something like this, or one of the thousands of examples from the web, however I have no way of knowing the length of the project as the software doesn't limit it. As a result I fell back onto using a fixed scale of 10px per bar. Kind of arbitrary, I chose that as it's the optimal for a 5 minute song at 120 bpm. Not too worried about looks for the moment, I just want to get it to work haha.
The problem I have (code is included at the bottom) is that because I'm using absolute positioning for the markers in order to align them all from the left of the screen, they are pulled from the document flow and so I can't wrap them in the parent div. In the end I intend setting the parent div to an 80% width with a scrollbar to see the rest of the markers, so obviously I'm doing it wrong. However I can't seem to find any coded snippets of anything similar to what I'm trying to achieve.
So here is the actual question:
What sort of display/position/float CSS should I be using to do this instead of position: absolute and float: left? If I need JS to do it, then how to I go about it?
Thanks for any help you can bring me, be it actual code or just a nudge in the right direction!
Here's my (relevant) code:
index.html
<html>
<body>
<div id="timeline">
<div id="labels"></div>
<div id="markers"></div>
</div>
</body>
</html>
script.js:
// hardcoded for debugging purposes
// See section below about the API for info about how I get this data
var markers = [
{label: "Start", pos: "20.00000000000000"},
{label: "First", pos: "50.00000000000000"},
{label: "Second", pos: "200.00000000000000"},
{label: "Last", pos: "576.845412000000000"}
];
function draw_markers(marker_list) {
var label_html = "";
var marker_html = "";
$.each(marker_list, function(index, obj) {
var label = obj.label;
var offset = parseFloat(obj.pos) * 7; // obj.pos is mesured in bars, not px
label_html = label_html +
"<span class='label' style='margin-left:"+offset+"px'>" +
label + "</span>";
marker_html = marker_html +
"<span class='marker' style='margin-left:"+offset+"px'>|</span>";
});
document.getElementById("labels").innerHTML = label_html;
document.getElementById("markers").innerHTML = marker_html;
}
draw_markers(markers);
style.css:
html, body {
background: #eeeeee;
}
#timeline {
height: 4em;
width: 100%;
background-color: #9E9E9E;
}
#labels {
border-bottom: 1px solid black;
height: 50%;
width: 100%;
}
#markers {
height: 50%;
width: 100%;
}
.label {
position: absolute;
float: left;
}
.marker {
position: absolute;
float: left;
}
About the API
We're given a bunch of functions that poll the server at regular intervals and parse the (cleartext) responses. A typical response looks something like this:
MARKERLIST_BEGINMARKER_LIST
MARKER \t label \t ID \t position
...
MARKER_LIST_END
TRANSPORT \t playstate \t position_seconds \t isRepeatOn \t position_string \t position_string_beats
...
Using JS I split each line and use a switch statement to figure out what to do with each line. I then build up a global array containing all the marker in the project with just the info I need.
Alternatively you could use <canvas> to draw the timeline from Javascript (this is what I use for Song Switcher's web interface). Also you can get the project length using the GetProjectLength API function (for example, by calling a script to put the length into a temporary extstate then reading it from the web interface).
function Timeline(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.length = 0;
this.markers = [];
}
Timeline.prototype.resize = function() {
this.canvas.width = this.canvas.clientWidth;
this.canvas.height = this.canvas.clientHeight;
this.scale = this.length / this.canvas.width;
}
Timeline.prototype.update = function() {
this.resize();
this.ctx.fillStyle = '#414141';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.textBaseline = 'hanging';
for(var marker of this.markers)
this.drawMarker(marker);
}
Timeline.prototype.drawMarker = function(marker) {
const MARKER_WIDTH = 2;
const FONT_SIZE = 14;
const PADDING = MARKER_WIDTH * 2;
var xpos = this.timeToPx(marker.pos);
this.ctx.strokeStyle = this.ctx.fillStyle = 'red';
this.ctx.lineWidth = MARKER_WIDTH;
this.ctx.beginPath();
this.ctx.moveTo(xpos, 0);
this.ctx.lineTo(xpos, this.canvas.height);
this.ctx.stroke();
if(marker.name.length > 0) {
this.ctx.font = `bold ${FONT_SIZE}px sans-serif`;
var boxWidth = this.ctx.measureText(marker.name).width + PADDING;
this.ctx.fillRect(xpos, 0, boxWidth, FONT_SIZE + PADDING);
this.ctx.fillStyle = 'white';
this.ctx.fillText(marker.name, xpos + MARKER_WIDTH, PADDING);
}
}
Timeline.prototype.timeToPx = function(time) {
return time / this.scale;
}
var timeline = new Timeline(document.getElementById('timeline'));
timeline.length = 30; // TODO: Fetch using GetProjectLength
timeline.markers = [
{pos: 3, name: "Hello"},
{pos: 15, name: "World!"},
{pos: 29, name: ""},
];
timeline.update();
window.addEventListener('resize', timeline.update.bind(timeline));
#timeline {
height: 50px;
line-height: 50px;
image-rendering: pixelated;
width: 100%;
}
<canvas id="timeline"></canvas>
you can use divs as display: inline-block and set their width as percentages of deltas of the overlaping absolute timeline positions:
function draw_markers(marker_list) {
var label_html = "";
var marker_html = "";
var total = null;
var prev = 0;
$.each(marker_list, function(index, obj) {
var delta = parseFloat(obj.pos) - prev;
obj.delta = delta;
prev += parseFloat(obj.pos);
total += delta;
})
$.each(marker_list, function(index, obj) {
var label = obj.label;
var offset = parseFloat(obj.delta) / (total / 100); // obj.pos is mesured in bars, not px
label_html = label_html +
"<div class='label' style='width:"+offset+"%'>" +
label + "</div>";
marker_html = marker_html +
"<div class='marker' style='width:"+offset+"%'>|</div>";
});
document.getElementById("labels").innerHTML = label_html;
document.getElementById("markers").innerHTML = marker_html;
}
draw_markers(markers);
css:
html, body {
background: #eeeeee;
}
#timeline {
height: 4em;
width: 100%;
background-color: #9E9E9E;
}
#labels {
border-bottom: 1px solid black;
height: 50%;
width: 100%;
}
#markers {
height: 50%;
width: 100%;
}
.label {
position: relative;
display: inline-block;
}
.marker {
position: relative;
display: inline-block;
}

Categories

Resources