JSFiddle - React, Tailwind, and code Playground
by Danilo Metzker
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js"></script>
<div class="map-container">
<div id="terminal" style="width: 720px; height: 380px;">
<div id="floor" style="top: 0px; left: 0px; position: relative;" class="ui-draggable ui-draggable-handle">
<div class="svg" id="svg-container">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:amcharts="http://amcharts.com/ammap" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="720" height="380" viewBox="0 0 720 380" xml:space="preserve" class="editor">
<defs>
<amcharts:ammap projection="mercator" leftlongitude="-74.008595" toplatitude="5.275696" rightlongitude="-34.789914" bottomlatitude="-33.743888"></amcharts:ammap>
<!-- All areas are listed in the line below. You can use this list in your script. -->
<!--{id:"BR-AC"},{id:"BR-AL"},{id:"BR-AM"},{id:"BR-AP"},{id:"BR-BA"},{id:"BR-CE"},{id:"BR-DF"},{id:"BR-ES"},{id:"BR-GO"},{id:"BR-MA"},{id:"BR-MG"},{id:"BR-MS"},{id:"BR-MT"},{id:"BR-PA"},{id:"BR-PB"},{id:"BR-PE"},{id:"BR-PI"},{id:"BR-PR"},{id:"BR-RJ"},{id:"BR-RN"},{id:"BR-RO"},{id:"BR-RR"},{id:"BR-RS"},{id:"BR-SC"},{id:"BR-SE"},{id:"BR-SP"},{id:"BR-TO"}-->
</defs>
<g>
<path id="BR-AC" title="Acre" class="land"...
CSS
.map-container {
position: relative;
background-color: white;
min-height: 200px;
margin: 0 auto;
padding: 30px;
cursor: move;
overflow: hidden;
}
#terminal{
overflow: hidden;
border: 1px solid #000;
}
.controls {
position: absolute;
bottom: 40px;
left: 40px;
z-index: 1;
}
.controls a {
display: table;
width: 28px;
height: 28px;
background-color: #fff;
text-align: center;
font-size: 20px;
font-weight: 900;
line-height: 1.2;
margin: 5px;
vertical-align: middle;
color: #000;
text-decoration: none;
border-radius: 50%;
border: 1px solid #000;
}
.map{
width: 100%;
height: 100%;
top: 0;
left: 0
}
.svg {
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.svg svg {
width: 100%;
height: 100%;
top: 0;
left: 0;
-webkit-transition: 0.2s all linear;
}
#floor {
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.svg svg path[data-text]{
cursor: pointer;
}
.pin{
width: 220px;
height: 100px;
background: #fff;
border: 2px solid #000;
display: none;
align-items: center;
justify-content: center;
font-size: 22px;
position: fixed;
}
.pin.active{
display: flex;
}
svg path:hover{
fill: rgba(0,0,0,0.3);
cursor: pointer;
}
#terminal .area{
display: flex;
align-items: center;
justify-content: center;
color: #000;
font-weight: bold;
position: absolute;
background: red;
}
.edit-layer{
position: fixed;
background-color: rgba(0,0,0,0.3);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 16px;
display: none;
}
.edit-layer input{
background: transparent;
border: 0;
color: #fff;
text-align: center;
background: #000;
outline: none;
}
.edit-layer input::placeholder{
color: rgba(255,255,255,0.7);
}
.edit-layer a.save{
display: block;
padding: 8px 16px;
background-color: #18864B;
color: #fff;
...
JavaScript
var zoom = 1;
$('#floor').draggable({
cursor: "move",
drag: function(event, ui) {
$(".pin").removeClass("active");
var topPosition = ui.position.top,
leftPosition = ui.position.left,
maxWidth = $('#terminal').width() - $('.svg').width(),
maxHeight = $('#terminal').height() - $('.svg').height();
if (leftPosition <= maxWidth) {
ui.position.left = maxWidth;
} else if (leftPosition >= 0) {
ui.position.left = 0;
}
if (topPosition <= maxHeight) {
ui.position.top = maxHeight;
} else if (topPosition >= 0) {
ui.position.top = 0;
}
$('.office').removeClass('show');
}
});
$('.controls a').on('click', function(evt) {
evt.stopImmediatePropagation();
$(".pin").removeClass("active");
var containerWidth = $('#terminal').width(),
containerHeight = $('#terminal').height(),
mapWidth = $('#floor').width(),
mapHeight = $('#floor').height(),
mapTop = $('#floor').position().top,
mapLeft = $('#floor').position().left,
mapRight = mapLeft + mapWidth,
mapBottom = mapTop + mapHeight,
topCenter = mapTop - (containerHeight / 2),
rightCenter = (containerWidth / 2) - mapRight,
bottomCenter = (containerHeight / 2) - mapBottom,
leftCenter = mapLeft - (containerWidth / 2),
zoomWidth,
zoomHeight,
zoomTop,
zoomLeft;
if ($(this).hasClass('zoom-in') && zoom < 6) {
topPos = containerHeight / 2 + topCenter * 1.4;
leftPos = containerWidth / 2 + leftCenter * 1.4;
$('#floor').css({
'width': mapWidth * 1.4,
'height': mapHeight * 1.4,
'top': topPos,
'left': leftPos
});
zoom++;
} else if ($(this).hasClass('zoom-out') && zoom > 1) {
topPos = containerHeight / 2 + topCenter / 1.4;
if (topPos > 0) {
topPos = 0;
}
bottomPos = topPos + mapHeight / 1.4;
if (bottomPos < containerHeight) {
topPos = topPos + containerHeight - bottomPos;
}
leftPos = containerWidth / 2 + leftCenter / 1.4;
if (leftPos > 0) {
leftPos = 0;
}
rightPos = leftPos + mapWidth / 1.4;
if (rightPos <...