Gradually Increasing Circles CSS, HTML and Javascript - javascript

I added a legend / Key in the map which is alright in case of squares but in circles, they are not aligned with the text, is there any way to align the text and the circles properly.
Image
Here is the code
function getsizeLabel(d)
{
return d > 90 ? 18 :
d > 60 ? 14 :
d > 30 ? 9 :
5 ;
}
function AddLDLegend() {
legendLD = L.control({position: 'bottomright'});
legendLD.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend');
labels = ['<strong>Lockdown Days</strong>'],
grades = [0, 30, 60, 90],
categories = ['1-30','31-60','61-90'];
for (var i = 0; i < grades.length; i++) {
div.innerHTML +=
labels.push(
'<i style="border-radius: 50%; border: 1px solid #8A2BE2; width:' + getsizeLabel(grades[i] + 1) +'px; height:' + getsizeLabel(grades[i] + 1) +'px;"></i> ' +
(grades[i] + grades[i+1] ? categories[i] : '91-100'));
}
div.innerHTML = labels.join('<br>');
return div;
};
legendLD.addTo(map);
}
The map is leaflet map I am just calling this function to add legend from another function but the design and everything related to the small legend div is in this function.
the preference for the text and circle alignment is in this image
enter image description here

I think this is what you was trying to achieve. Please let me know if you have any doubt.
const grades = [0, 30, 60, 90];
const categories = ['1-30', '31-60', '61-90'];
function getSize(g) {
return (
g > 90 ? 18 :
g > 60 ? 14 :
g > 30 ? 9 : 5
);
}
function getLabel(i) {
const size = getSize(grades[i] + 1);
const grade = (grades[i] + grades[i + 1] ? categories[i] : '91-100');
const bulletStyle = [
'display: inline-block;',
'vertical-align: middle;',
'border-radius: 50%;',
'border: 1px solid #8A2BE2;',
`height: ${size}px;`,
`width: ${size}px;`
];
const valueStyle = [
'display: inline-block;',
'vertical-align: middle;'
];
const bullet = `<i style="${bulletStyle.join(' ')}"></i>`;
const value = `<span style="${valueStyle.join(' ')}">${grade}</span>`
return bullet + ' ' + value;
}
function getDiv() {
const div = L.DomUtil.create('div', 'info legend');
const labels = ['<strong>Lockdown Days</strong>'];
for (var i = 0; i < grades.length; i++) {
div.innerHTML += labels.push(getLabel(i));
}
div.innerHTML = labels.join('<br>');
return div;
};
document.getElementsByTagName('BODY')[0].appendChild(getDiv());
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"></script>

Related

How to get postition highlighted text in textarea (coords) angular?

I want to get something like this, in textarea. I cant change textarea to contentaditable div. How do I get the position of the selected text? I need this to show this pop-up from above
You should be able to easily convert this into angular code.
This is the basics of what you need to do, its not thoroughly tested but it bare minimum works.
const textarea = document.getElementById('text')
const result = document.getElementById('selected')
const tooltip = document.getElementById('tooltip')
const cols = document.getElementById('text').cols;
const width = document.getElementById('text').clientWidth;
const height = window.getComputedStyle(textarea).lineHeight;
textarea.onclick = function getSelection() {
const pos = {
top: textarea.offsetTop,
left: textarea.offsetLeft,
};
result.textContent = `${textarea.selectionStart}, ${textarea.selectionEnd}`;
let selection
if (textarea.selectionStart) {
selection = textarea.selectionStart;
} else if (document.selection) {
textarea.focus();
const r = document.selection.createRange();
if (r == null) {
selection = 0;
}
let re = textarea.createTextRange();
let rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
selection = rc.text.length;
} else {
selection = 0
}
const row = Math.floor((selection - 1) / cols);
const col = (selection - (row * cols));
const x = Math.floor((col * (width / cols)));
const y = (parseInt(height) * row);
tooltip.innerHTML = "<b>row: " + row + "<br>columns" + col + "<br>width: " + width + "</b>";
tooltip.style.top = `${pos.top+y}px`;
tooltip.style.left = `${pos.left+x+10}px`;
}
textarea {
height: 80px;
line-height: 12px;
overflow-y: scroll;
display: block;
}
#tooltip {
position: absolute;
background:red;
color: white;
}
<textarea id="text">Lopsum</textarea>
<span id="tooltip"></span>
<span id="selected"></span>
The only way I imagine is create a duplicate of the text area (very similar to this SO, (the Owen Kelvin's response) about highligth words in a text area
As we only need the position, we can split the "texarea" and the "background". Futhermore, using the Yurzui response in this another SO we can control when resize the textarea
We can imagine an .html like
<div class="container">
<div
#backdrop
class="backdrop"
[style.width.px]="textWidth"
[style.height.px]="textHeight"
>
<div
class="highlights"
[innerHTML]="sanitizer.bypassSecurityTrustHtml(highlightedText)"
></div>
</div>
</div>
<textarea
#textarea
spellcheck="false"
(resize)="rect = null;"
(select)="applyHighlights(textarea.value)"
(mousedown)="mouseDown()"
(blur)="rect = null"
[ngModel]="textValue"
(ngModelChange)="textValue = $event; applyHighlights(textarea.value)"
(scroll)="handleScroll(); applyHighlights(textarea.value)"
></textarea>
<div
class="tooltip"
*ngIf="rect"
[style.top.px]="rect.y"
[style.left.px]="rect.x"
></div>
See that the "text" is hidden because we has a div container like
.container {
overflow:hidden;
width:0;
height:0;
}
And we make that the dimensions of "text" are condition by the two variables "textWidth" and "textHeight"
The code is
ngOnInit() {
this.resize();
}
resize() {
const event = {
width: this.$textarea.nativeElement.getBoundingClientRect().width,
height: this.$textarea.nativeElement.getBoundingClientRect().height,
};
this.textWidth = event.width;
this.textHeight = event.height;
}
mouseDown() {
setTimeout(() => {
const start = this.$textarea.nativeElement.selectionStart;
const end = this.$textarea.nativeElement.selectionEnd;
if (start == end) this.rect = null;
});
}
applyHighlights(text: string) {
if (text) {
let start = this.$textarea.nativeElement.selectionStart;
let end = this.$textarea.nativeElement.selectionEnd;
if (start == end) this.highlightedText = text;
else {
const selected = text.substr(start, end - start);
this.toolTipText=this.getTooltipText(selected)
this.highlightedText =
text.substr(0, start) +
"<span id='mark'>" +
selected +
'</span>' +
text.substr(end);
this.resize();
setTimeout(() => {
const recArea = this.$textarea.nativeElement.getBoundingClientRect();
const recText = this.$backdrop.nativeElement.getBoundingClientRect();
const rect = document.getElementById('mark').getBoundingClientRect();
rect.y += window.scrollY;
rect.x+=rect.width/2
this.rect = rect.y - window.scrollY < recArea.y ? null : rect;
});
}
}
}
handleScroll() {
var scrollTop = this.$textarea.nativeElement.scrollTop;
this.$backdrop.nativeElement.scrollTop = scrollTop;
var scrollLeft = this.$textarea.nativeElement.scrollLeft;
this.$backdrop.nativeElement.scrollLeft = scrollLeft;
}
And in the stackblitz I put in a custom form component (the reason is that Owen make this work for me

Vis JS Timeline - Freeze horizontal time axis when vertically scrolling

I'm using the following options in Vis JS Timeline to produce a horizontal axis at the top of the timeline with time labels:
orientation: {
axis: 'both'
},
The horizontal axis looks like this:
My timeline has many rows, so the user needs to vertically scroll down the page to see everything. The problem is that the horizontal axis at the top does not stay in view when scrolling down the page.
Question: How can I freeze the horizontal axis at the top so that the time labels stay in view when scrolling down?
The following code snippet, or jsfiddle.net/nj1647tb, is my timeline:
const seed = '11';
Math.seedrandom(seed);
const nGroups = 40;
const maxSubGroups = 2;
const maxItemsPerSubGroup = 1;
const metaEventCount = 2;
const itemLengthScale = 200;
let now = moment().minutes(0).seconds(0).milliseconds(0);
var groupCount = 12;
var itemCount = 70;
var tcCrashProbability = 0.2;
function randInt(min, max) {
return Math.round(min + Math.random() * (max - min));
}
function getStartEnd(earliestStart) {
if (earliestStart === undefined) {
earliestStart = 0;
}
let startAdd = earliestStart + Math.random() * 200;
let length = Math.random() * itemLengthScale;
let endAdd = startAdd + length;
return {
startAdd: startAdd,
endAdd: endAdd
}
}
const stackTrace = `Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 756, in urlopen
method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
File "/usr/local/lib/python3.6/site-packages/urllib3/util/retry.py", line 532, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/usr/local/lib/python3.6/site-packages/urllib3/packages/six.py", line 769, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 706, in urlopen
chunked=chunked,
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 445, in _make_request
six.raise_from(e, None)
File "<string>", line 3, in raise_from
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 440, in _make_request
httplib_response = conn.getresponse()
File "/usr/lib64/python3.6/http/client.py", line 1346, in getresponse
response.begin()
File "/usr/lib64/python3.6/http/client.py", line 307, in begin
version, status, reason = self._read_status()
File "/usr/lib64/python3.6/http/client.py", line 268, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/lib64/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
File "/usr/lib64/python3.6/ssl.py", line 971, in recv_into
`;
// create a data set with groups
var group_names = [];
var groups = new vis.DataSet();
for (let i = 0; i < nGroups; i++) {
group_names.push('GROUP_' + i);
groups.add({
id: group_names[i],
content: group_names[i]
});
}
// add meta group
groups.add({
id: -1,
content: ' '
});
// create a dataset with items
let items = new vis.DataSet();
for (let i = 0; i < nGroups; i++) {
let nSubGroups = randInt(1, maxSubGroups);
//console.log('group='+i+' nSubGroups='+nSubGroups);
let lastStartAdd = 0;
for (let sg = 0; sg < nSubGroups; sg++) {
let start_end = getStartEnd(lastStartAdd);
let start = now.clone().add(start_end['startAdd'], 'hours');
let end = now.clone().add(start_end['endAdd'], 'hours');
let itemID = 'G' + i + '_S' + sg + '_item';
let subgroupID = 'G' + i + '_S' + sg;
let subgroupOrder = sg;
let newItem = {
id: itemID,
group: group_names[i],
subgroup: subgroupID,
subgroupOrder: subgroupOrder,
content: 'ITEM_DU_' + 'G' + i + '_S' + sg,
start: start,
end: end,
title: 'ITEM_DU_' + 'G' + i + '_S' + sg
};
//console.log(group_names[i] + ', ' + 'S' + sg + ', ' +start_end['startAdd'] + ', ' + start_end['endAdd']);
items.add(newItem);
lastStartAdd = start_end['startAdd'];
// random crashes
if(Math.random() <= tcCrashProbability) {
let crashStart = now.clone().add(randInt(start_end['startAdd'], start_end['endAdd']), 'hours');
let newCrashItem = {
id: 'crash_' + itemID,
group: group_names[i],
subgroup: subgroupID,
subgroupOrder: subgroupOrder,
content: 'Crash',
start: crashStart,
type: 'box',
className: 'timeline-tc-crash',
title: '<pre>' + stackTrace + '</pre>'
};
items.add(newCrashItem);
}
}
}
// generate some meta events
for (let i = 0; i < metaEventCount; i++) {
let start = now.clone().add(Math.random() * 200, 'hours');
items.add({
id: 'M' + i,
group: -1,
content: 'Crash',
title: '<pre>' + stackTrace + '</pre>',
className: 'timeline-event-crash',
start: start,
type: 'box'
});
}
// create visualization
var container = document.getElementById('visualization');
var options = {
groupOrder: 'content',
stack: false,
stackSubgroups: true,
orientation: {
axis: 'both'
},
showCurrentTime: false
};
var timeline = new vis.Timeline(container);
timeline.setOptions(options);
timeline.setGroups(groups);
timeline.setItems(items);
#visualization {
box-sizing: border-box;
width: 100%;
height: 300px;
}
.timeline-event-crash {
background-color: red !important;
border-color: darkred !important;
color: white !important;
font-family: monospace;
box-shadow: 0 0 10px gray;
}
.timeline-tc-crash {
color: red !important;
border-color: red !important;
background-color: #F4BBB5 !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.3.10/seedrandom.min.js"></script>
<link href="https://visjs.github.io/vis-timeline/styles/vis-timeline-graph2d.min.css" rel="stylesheet" />
<script src="https://visjs.github.io/vis-timeline/standalone/umd/vis-timeline-graph2d.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<html>
<head>
<title>Timeline</title>
</head>
<body>
<div id="visualization"></div>
</body>
</html>
I don't know if you ever tried this, but when i am investigating the issue, when my mouse is over the left column i was able to scroll vertically. So not a fix from code side, but if you could not find a proper solution maybe you can add some guidance for your users like "if you want to see groups down below you should scroll when the mouse is over them".
P.S Though i did not deeply investigated this yet but i think this is an expected behavior from vis side, because as far as i have seen from their examples they do not have any option to horizontal scroll when mouse is over timeline

How to get coordinates in MapCenterCoord leaflet plugin?

I am currently using MapCenterCoord plugin for my leaflet project https://github.com/xguaita/Leaflet.MapCenterCoord
The plugin works fine but I am trying to extract the coordinates it produced as a value (and to show it on console.log() so I can reuse it for placing a marker on the map).
However, I cannot for the life of me figure out how to get the value out of the plugin. Anyone got any tips?
This is the script (I have tried placing console.log in onAdd as console.log(this._getMapCenterCoord()) but to no effect, as it only gives the current GPS onload rather than updated on the console whenever I move the window):
L.Control.MapCenterCoord = L.Control.extend({
// Defaults
options: {
position: 'bottomleft',
icon: true,
onMove: false,
template: '{y} | {x}', // https://en.wikipedia.org/wiki/ISO_6709
projected: false,
formatProjected: '#.##0,000',
latlngFormat: 'DD', // DD, DM, DMS
latlngDesignators: false,
latLngFormatter: undefined
},
onAdd: function (map) {
if (this.options.icon) {
// create a DOM element and put it into overlayPane
this._iconEl = L.DomUtil.create('div', 'leaflet-control-mapcentercoord-icon leaflet-zoom-hide');
map.getPanes().overlayPane.appendChild(this._iconEl);
// add a viewreset event listener for updating icon's position
map.on('viewreset', this._onReset, this);
this._onReset();
}
// Control container
this._container = L.DomUtil.create('div', 'leaflet-control-mapcentercoord');
L.DomEvent.disableClickPropagation(this._container);
// Add events listeners for updating coordinates & icon's position
map.on('move', this._onMapMove, this);
map.on('moveend', this._onMapMoveEnd, this);
this._container.innerHTML = this._getMapCenterCoord();
return this._container;
},
onRemove: function (map) {
// remove icon's DOM elements and listeners
if (this.options.icon) {
map.getPanes().overlayPane.removeChild(this._iconEl);
map.off('viewreset', this._onReset, this);
}
map.off('move', this._onMapMove, this);
map.off('moveend', this._onMapMove, this);
},
_onReset: function (e) {
// update icon's position
var pos = this._map.latLngToLayerPoint(this._map.getCenter());
L.DomUtil.setPosition(this._iconEl, pos);
},
_onMapMove: function (e) {
if (this.options.icon) {
// update icon's position
var pos = this._map.latLngToLayerPoint(this._map.getCenter());
L.DomUtil.setPosition(this._iconEl, pos);
}
if (this.options.onMove) {
// update coordinates
this._container.innerHTML = this._getMapCenterCoord();
}
},
_onMapMoveEnd: function (e) {
if (this.options.icon) {
// update icon's position
var pos = this._map.latLngToLayerPoint(this._map.getCenter());
L.DomUtil.setPosition(this._iconEl, pos);
}
// update coordinates
this._container.innerHTML = this._getMapCenterCoord();
},
_getMapCenterCoord: function () {
if (this.options.projected) return this._getProjectedCoord(this._map.options.crs.project(this._map.getCenter()));
return this._getLatLngCoord(this._map.getCenter());
},
_getProjectedCoord: function (center) {
return L.Util.template(this.options.template, {
x: this._format(this.options.formatProjected, center.x),
y: this._format(this.options.formatProjected, center.y)
});
},
_getLatLngCoord: function (center) {
if (this.options.latLngFormatter != undefined) return this.options.latLngFormatter(center.lat, center.lng);
var lat, lng, deg, min;
//make a copy of center so we aren't affecting leaflet's internal state
var centerCopy = {
lat: center.lat,
lng: center.lng
};
// 180 degrees & negative
if (centerCopy.lng < 0) {
centerCopy.lng_neg = true;
centerCopy.lng = Math.abs(centerCopy.lng);
} else centerCopy.lng_neg = false;
if (centerCopy.lat < 0) {
centerCopy.lat_neg = true;
centerCopy.lat = Math.abs(centerCopy.lat);
} else centerCopy.lat_neg = false;
if (centerCopy.lng > 180) {
centerCopy.lng = 360 - centerCopy.lng;
centerCopy.lng_neg = !centerCopy.lng_neg;
}
// format
if (this.options.latlngFormat === 'DM') {
deg = parseInt(centerCopy.lng);
lng = deg + 'º ' + this._format('00.000', (centerCopy.lng - deg) * 60) + "'";
deg = parseInt(centerCopy.lat);
lat = deg + 'º ' + this._format('00.000', (centerCopy.lat - deg) * 60) + "'";
} else if (this.options.latlngFormat === 'DMS') {
deg = parseInt(centerCopy.lng);
min = (centerCopy.lng - deg) * 60;
lng = deg + 'º ' + this._format('00', parseInt(min)) + "' " + this._format('00.0', (min - parseInt(min)) * 60) + "''";
deg = parseInt(centerCopy.lat);
min = (centerCopy.lat - deg) * 60;
lat = deg + 'º ' + this._format('00', parseInt(min)) + "' " + this._format('00.0', (min - parseInt(min)) * 60) + "''";
} else { // 'DD'
lng = this._format('#0.00000', centerCopy.lng) + 'º';
lat = this._format('##0.00000', centerCopy.lat) + 'º';
}
return L.Util.template(this.options.template, {
x: (!this.options.latlngDesignators && centerCopy.lng_neg ? '-' : '') + lng + (this.options.latlngDesignators ? (centerCopy.lng_neg ? ' W' : ' E') : ''),
y: (!this.options.latlngDesignators && centerCopy.lat_neg ? '-' : '') + lat + (this.options.latlngDesignators ? (centerCopy.lat_neg ? ' S' : ' N') : '')
});
},
_format: function (m, v) {
if (!m || isNaN(+v)) {
return v; //return as it is.
}
//convert any string to number according to formation sign.
var v = m.charAt(0) == '-' ? -v : +v;
var isNegative = v < 0 ? v = -v : 0; //process only abs(), and turn on flag.
//search for separator for grp & decimal, anything not digit, not +/- sign, not #.
var result = m.match(/[^\d\-\+#]/g);
var Decimal = (result && result[result.length - 1]) || '.'; //treat the right most symbol as decimal
var Group = (result && result[1] && result[0]) || ','; //treat the left most symbol as group separator
//split the decimal for the format string if any.
var m = m.split(Decimal);
//Fix the decimal first, toFixed will auto fill trailing zero.
v = v.toFixed(m[1] && m[1].length);
v = +(v) + ''; //convert number to string to trim off *all* trailing decimal zero(es)
//fill back any trailing zero according to format
var pos_trail_zero = m[1] && m[1].lastIndexOf('0'); //look for last zero in format
var part = v.split('.');
//integer will get !part[1]
if (!part[1] || part[1] && part[1].length <= pos_trail_zero) {
v = (+v).toFixed(pos_trail_zero + 1);
}
var szSep = m[0].split(Group); //look for separator
m[0] = szSep.join(''); //join back without separator for counting the pos of any leading 0.
var pos_lead_zero = m[0] && m[0].indexOf('0');
if (pos_lead_zero > -1) {
while (part[0].length < (m[0].length - pos_lead_zero)) {
part[0] = '0' + part[0];
}
} else if (+part[0] == 0) {
part[0] = '';
}
v = v.split('.');
v[0] = part[0];
//process the first group separator from decimal (.) only, the rest ignore.
//get the length of the last slice of split result.
var pos_separator = (szSep[1] && szSep[szSep.length - 1].length);
if (pos_separator) {
var integer = v[0];
var str = '';
var offset = integer.length % pos_separator;
for (var i = 0, l = integer.length; i < l; i++) {
str += integer.charAt(i); //ie6 only support charAt for sz.
//-pos_separator so that won't trail separator on full length
if (!((i - offset + 1) % pos_separator) && i < l - pos_separator) {
str += Group;
}
}
v[0] = str;
}
v[1] = (m[1] && v[1]) ? Decimal + v[1] : "";
return (isNegative ? '-' : '') + v[0] + v[1]; //put back any negation and combine integer and fraction.
}
});
L.Map.mergeOptions({
MapCenterCoordControl: false
});
L.Map.addInitHook(function () {
if (this.options.MapCenterCoordControl) {
this.MapCenterCoordControl = new L.Control.MapCenterCoord();
this.addControl(this.MapCenterCoordControl);
}
});
L.control.mapCenterCoord = function (options) {
return new L.Control.MapCenterCoord(options);
};
Below is an example of how to easily determine the center of the map. This is a reworked one of my examples so it's more goodies but you can simplify yourself.
/* eslint-disable no-undef */
/**
* Obtaining coordinates of the visible map
*/
// config map
let config = {
minZoom: 7,
maxZomm: 18,
};
// magnification with which the map will start
const zoom = 18;
// co-ordinates
const lat = 52.22977;
const lng = 21.01178;
// calling map
const map = L.map('map', config).setView([lat, lng], zoom);
// Used to load and display tile layers on the map
// Most tile servers require attribution, which you can set under `Layer`
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
}).addTo(map);
const markerPlace = document.querySelector('.marker-position');
// on drag end
map.on('dragend', setRentacle);
// second option, by dragging the map
map.on('dragstart', updateInfo);
// on zoom end
map.on('zoomend', setRentacle);
// update info about bounds when site loaded
document.addEventListener('DOMContentLoaded', function() {
const bounds = map.getBounds();
updateInfo(bounds._northEast, bounds._southWest);
});
// set rentacle function
function setRentacle() {
const bounds = map.getBounds();
// update info about bounds
updateInfo(bounds._northEast, bounds._southWest);
// set rentacle
L.rectangle(bounds, {
color: randomColor(),
weight: 20,
fillOpacity: 0.1,
}).addTo(map);
// set map
map.fitBounds(bounds);
}
// generate random color
function randomColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
function updateInfo(north, south) {
const center = map.getCenter();
markerPlace.textContent =
south === undefined ?
'We are moving the map...' :
`Center: ${center}, SouthWest: ${north}, NorthEast: ${south}`;
}
#import url(https://fonts.googleapis.com/css?family=Lato&display=swap);
*,
:after,
:before {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html {
height: 100%;
}
body,
html,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#map:before {
position: absolute;
content: "+";
font-size: 3rem;
font-weight: 400;
display: flex;
justify-content: center;
align-items: center;
color: red;
z-index: 9999999;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
border: 10px;
}
body {
position: relative;
height: 100%;
font-family: Lato, sans-serif;
min-height: 100%;
padding: 0;
margin: 0;
}
.marker-position {
position: absolute;
bottom: 0;
left: 0;
z-index: 999;
padding: 20px 10px;
font-size: 10px;
background-color: #fff;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js"></script>
<div class="marker-position"></div>
<div id="map"></div>
As for your problem, console.log is working. I tested locally and the coordinates appear.
onAdd: function(map) {
...
this._container.innerHTML = this._getMapCenterCoord();
// works
console.log(this._getMapCenterCoord());
return this._container;
},
_onMapMoveEnd: function(e) {
...
// update coordinates
this._container.innerHTML = this._getMapCenterCoord();
// works
console.log(this._getMapCenterCoord());
},

Detect collision between two elements

I want to detect a collision between two divs and I've tried to do that using the offsetLeft and offsetTop of each one of the divs and by using getBoundingClientRect(). But none of these work.
Is there a way I can get the exact coordinates in which these two elements touch?
const bigDiv = document.querySelector(".big")
const blue = document.querySelector(".blue")
const startBtn = document.querySelector("button")
const red = document.querySelector(".red")
const bigDivDimensions = bigDiv.getBoundingClientRect();
let speed = 5;
//let counter = 0;
let bigDivLeft = bigDivDimensions.left;
startGame();
function random() {
return Math.floor(Math.random() * (bigDivDimensions.width - 40));
}
function startGame() {
//let randomSnake = Math.floor(Math.random()*(bigDivDimensions.width-40));
//let randomApple = Math.ceil(Math.random()*(bigDivDimensions.width -40));
blue.style.left = random() + "px"
blue.style.top = random() + "px"
red.style.left = random() + "px"
red.style.top = random() + "px"
}
function move(e) {
let blueX = blue.offsetLeft;
let blueY = blue.offsetTop;
let key = e.keyCode;
if (key !== 37 && key !== 38 && key !== 39 && key !== 40) {
return
} else if (key === 37 && blueX > 3) {
blueX -= speed;
} else if (key === 38 && blueY > 3) {
blueY -= speed;
} else if (key === 39 && blueX < (bigDivDimensions.width - 25)) {
blueX += speed;
} else if (key === 40 && blueY < (bigDivDimensions.height - 23)) {
blueY += speed;
}
blue.style.left = blueX + "px";
blue.style.top = blueY + "px";
colision(blueX, blueY)
}
function colision(blueX, blueY) {
/* let redX = red.offsetLeft;
let redY = red.offsetTop;
if(redY === blueY || redX == blueX){console.log("hit")} */
let redRect = red.getBoundingClientRect();
let blueRect = blue.getBoundingClientRect();
if ((redRect.top < blueRect.bottom) || (redRect.bottom < blueRect.top) || (redRect.right > blueRect.left) || (redRect.left < blueRect.right)) {
console.log("hit")
}
}
startBtn.addEventListener("click", startGame)
document.addEventListener("keydown", move)
.big {
width: 400px;
height: 400px;
outline: 1px solid red;
margin: 0 auto;
position: relative;
}
.blue {
width: 20px;
height: 20px;
background: blue;
position: absolute;
}
.red {
width: 20px;
height: 20px;
background: red;
position: absolute;
}
<button type="button">Start Game</button>
<div class="big">
<div class="blue"></div>
<div class="red"></div>
</div>
codepen
Two rectangles do collide when their
horizontal side and vertical side
overlap.
Consider the following answer: Checking for range overlap
// l1 (line 1) --> [x1, x2]
// l2 (line 2) --> [x1, x2]
function checkOverlap(l1, l2) {
return ((l1[1] - l2[0]) > 0 && (l2[1] - l1[0]) > 0) ? true : false;
}
Check collision with range overlap for the x-side and y-side:
// Rectangle a --> [[x1, x2], [y1, y2]]
// Rectangle b --> [[x1, x2], [y1, y2]]
function collide(a, b) {
return (checkOverlap(a[0], b[0]) && checkOverlap(a[1], b[1]));
}
Spoiler
SVG-Example
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var width = 200;
var height = 200;
svg.setAttribute("width", width);
svg.setAttribute("height", height);
document.body.appendChild(svg);
function createRect(svg, width, height, x, y, style, id) {
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("width", width);
rect.setAttribute("height", height);
rect.setAttribute("x", x);
rect.setAttribute("y", y);
rect.setAttribute("style", style);
rect.setAttribute("id", id);
svg.appendChild(rect);
}
function createSquare(svg, side, x, y, style, id) {
createRect(svg, side, side, x, y, style, id);
}
function getRandomNumber(a, b) {
return Math.round(Math.random() * (b - a)) + a;
}
function createRandomSquare(svg, xRange, yRange, side, style, id) {
var x = getRandomNumber(xRange[0], xRange[1]);
var y = getRandomNumber(yRange[0], yRange[1]);
createSquare(svg, side, x, y, style, id);
return [
[x, x + side],
[y, y + side]
];
}
function checkOverlap(l1, l2) {
return ((l1[1] - l2[0]) > 0 && (l2[1] - l1[0]) > 0) ? true : false;
}
// [[x1, x2], [y1, y2]]
function collide(a, b) {
return (checkOverlap(a[0], b[0]) && checkOverlap(a[1], b[1]));
}
function getCoordinates(arr) {
return {
"top-left": [arr[0][0], arr[1][0]],
"top-right": [arr[0][1], arr[1][0]],
"bottom-left": [arr[0][1], arr[1][1]],
"bottom-right": [arr[0][0], arr[1][1]]
}
}
function run() {
var bs = document.getElementById("blueSquare");
var rs = document.getElementById("redSquare");
var output = document.getElementById("output");
output.innerHTML = "";
if (bs !== null && rs !== null) {
var parent = bs.parentNode;
parent.removeChild(bs);
parent.removeChild(rs);
}
var side = 30;
var blueSquare = createRandomSquare(svg, [0, (width - side)], [0, (height - side)], side, "fill:blue", "blueSquare");
var redSquare = createRandomSquare(svg, [0, (width - side)], [0, (height - side)], side, "fill:red", "redSquare");
var output1 = "Collision? " + collide(blueSquare, redSquare);
var output2 = "Blue square: " +
JSON.stringify(getCoordinates(blueSquare));
var output3 = "Red square: " + JSON.stringify(getCoordinates(redSquare));
output.innerHTML = output1 + "<br>" + output2 + "<br>" + output3 + "<br>";
}
var button = document.createElement("button");
button.setAttribute("id", "button");
button.textContent = "Run";
button.addEventListener("click", run);
document.body.appendChild(button);
svg {
border: 1px solid;
}
<div id="output"></div>

Unable to update image position in css using javascript

There are some runner(animation-image) in my program which move from position x to y when clicked on start button, i want to add a (reverse)button on completion that when clicked on that the image moves from y to x.
Here is the link of my js-fiddle: https://jsfiddle.net/o6egL4qr/
I have added the reverse button but when clicked on that the image doesn't move at all.
class raceManager {
raceCount = 0;
races = [];
addRace() {
var mainContainer = document.getElementById('mainContainer');
mainContainer.appendChild(document.createElement('br'));
var race = new raceClass(this.raceCount);
this.races.push(race);
this.raceCount++;
}
}
class raceClass {
runners = [];
count;
runnerCount = 0;
raceDiv = document.createElement('div');
raceNum = document.createElement('div');
startRaceButton = document.createElement('input');
addRunnerButton = document.createElement('input');
revRaceButton = document.createElement('input');
tableDiv = document.createElement('div');
tableNum = document.createElement('div');
startInterval;
startTime;
revStartTime;
reverseInterval;
constructor(number) {
// store the race no.
this.count = number;
// delcare the race div id
this.raceNum.id = 'raceNum' + this.count;
// delcare the table div id
this.tableNum.id = 'tableNum' + this.count;
// Add raceDiv to the race
document.getElementById('races').appendChild(this.raceDiv);
// Add tableDiv to the race
document.getElementById('tables').appendChild(this.tableDiv);
this.applyDivProperty();
this.initializeButtons();
}
applyDivProperty() {
// apply properties to the tableNum
this.tableNum.style.display = "inline-block";
// apply properties to the raceDiv
this.raceDiv.id = "Race" + this.count;
document.getElementById(this.raceDiv.id).classList.add("raceDivClass");
this.raceDiv.appendChild(this.raceNum);
document.getElementById(this.raceNum.id).innerHTML = '<p>Race: ' + this.count + '</p>';
// append the add race button
this.raceDiv.appendChild(this.addRunnerButton);
// apply properties to the tableDiv
this.tableDiv.id = "Table" + this.count;
document.getElementById(this.tableDiv.id).classList.add("tableClass");
this.tableDiv.appendChild(this.tableNum);
document.getElementById(this.tableNum.id).innerHTML = '<p>Table: ' + this.count + '</p>';
}
initializeButtons() {
// initialize add runner button
this.addRunnerButton.type = 'Button';
this.addRunnerButton.value = 'Add Runner';
this.addRunnerButton.id = 'AddRunner' + this.count;
this.addRunnerButton.onclick = this.addRunner.bind(this);
// initialize start race buttton
this.startRaceButton.type = 'Button';
this.startRaceButton.value = 'Start Race';
this.startRaceButton.id = "startRaceButton" + this.count;
this.startRaceButton.onclick = this.startRace.bind(this);
// initialize reverse race buttton
this.revRaceButton.type = 'Button';
this.revRaceButton.value = 'Reverse Race';
this.revRaceButton.id = "revRaceButton" + this.count;
this.revRaceButton.onclick = this.revRace.bind(this);
}
addRunner() {
var track = new Runner(this); //Initialize the runner object
this.runners.push(track); //Store the runner object in runners array of Race class
if (this.runnerCount > 0) {
// append the start race button
this.raceDiv.appendChild(this.startRaceButton);
}
this.runnerCount++;
}
startRace() {
this.startTime = Date.now();
this.startInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animate();
});
document.getElementById(this.startRaceButton.id).disabled = "true";
document.getElementById(this.addRunnerButton.id).disabled = "true";
}, 50);
}
stop() {
clearInterval(this.startInterval);
// append the start race button
this.raceDiv.appendChild(this.revRaceButton);
}
revRace() {
this.revStartTime = Date.now();
this.reverseInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animateReverse();
});
document.getElementById(this.revRaceButton.id).disabled = "true";
}, 50);
}
stopRev() {
clearInterval(this.reverseInterval);
}
}
class Runner {
count = 0;
parent;
track;
sprite;
timeTaken;
trackWidth;
element;
speed;
table;
printCount = 1;
stepCount = 1;
trackNum;
tbl;
lastStep;
constructor(race) {
// initialize the divs
this.parent = race;
this.track = document.createElement('div');
this.sprite = document.createElement('div');
this.table = document.createElement('table');
// assigns #id to table and track corresponding with parent div.
this.table.id = race.tableNum.id + '_Table_' + this.parent.runnerCount;
this.track.id = race.raceNum.id + '_Track_' + this.parent.runnerCount;
this.createUI();
this.timeTaken = ((Math.random() * 5) + 3);
this.speed = this.trackWidth / (this.timeTaken * 1000);
console.log(this.trackWidth, this.timeTaken);
console.log(this.timeTaken * 100);
}
createUI() {
this.count = this.parent.runnerCount;
this.createTable();
this.createTrack();
this.createSprite();
}
createTable() {
var parentDiv1 = document.getElementById(this.parent.tableNum.id);
parentDiv1.appendChild(this.table);
this.table.setAttribute = "border"
this.table.border = "1";
document.getElementById(this.table.id).classList.add("tableClass");
this.tbl = document.getElementById(this.table.id);
this.addRow("Track " + (this.count + 1), "");
this.addRow("Time", "Distance");
}
addCell(tr, val) {
var td = document.createElement('td');
td.innerHTML = val;
tr.appendChild(td)
}
addRow(val_1, val_2) {
var tr = document.createElement('tr');
this.addCell(tr, val_1);
this.addCell(tr, val_2);
this.tbl.appendChild(tr)
}
createTrack() {
var parentDiv = document.getElementById(this.parent.raceNum.id);
parentDiv.appendChild(this.track);
this.track.appendChild(this.sprite);
document.getElementById(this.track.id).classList.add("trackClass");
this.trackWidth = this.track.getBoundingClientRect().width;
}
createSprite() {
this.sprite.id = this.track.id + "_Runner";
document.getElementById(this.sprite.id).classList.add("spriteClass");
this.element = document.getElementById(this.sprite.id);
}
animate() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.startTime;
var diff = Math.floor(this.timeTaken * 100);
// step is position of sprite.
var step = timespent * this.speed;
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step > this.trackWidth - 23) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stop();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
// we use the ES6 template literal to insert the variable "position"
this.element.style.backgroundPosition = `${position}px 0px`;
}
animateReverse() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.revStartTime;
var diff = Math.floor(this.timeTaken * 100);
console.log(this.count + " position of step " + this.element.style.left);
while (this.stepCount < 2) {
this.lastStep = parseFloat(this.element.style.left);
this.stepCount++;
}
console.log(this.count + " this is lastStep " + this.lastStep);
// step is position of sprite.
var step = this.lastStep - (this.speed * timespent);
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step < 25) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stopRev();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
//var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
//this.element.style.backgroundPosition = position + 'px 0px';
}
}
manager = new raceManager();
#tableContainer {
float: left;
}
#addRaces {
text-align: center;
}
.raceDivClass {
margin: 1% auto;
width: 60%;
text-align: center;
border: 1px solid;
}
.tableClass {
text-align: center;
border: 1px solid;
margin: 5px;
float: left;
}
.trackClass {
background-color: black;
height: 30px;
width: 98%;
margin: 1%;
position: relative;
}
.spriteClass {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGgAAAAeCAYAAADAZ1t9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASwSURBVGhD7Zq/axRBFMfv9u4MxATUSgsVm3QWigYbexuxUkiaKIqNoIUiwRSJoJLCxpSCaJoEYimo/4AgQVRIZxdBEIREYwzc5X74vndvlrm5mdnZ3dm9oPnAsDubu52Z93373pvNFQsJOXO9NUKHsU4vZPH90+IXPt/FA2kEmqbDTKcX8pza7K5I/vAtEJghge7zeSrwlDYbtYlmfWuILxWC8uBmUNoz/784wY4WaPRq9SGJcY+7Mt7GEOzUkB0pkGHi4Ci1K53TEK8h7tTE+pPywL6b3JXJQqBcQ7arQwR87AE34ElPUsPE1ZapODsErFHnnD7AfVWb9oylFYjVFcKoQuQC5kD55hB3Qxrbf17RYbHT+/fpCXGSOEmEaYcevofwhkRxXM0/VCi8azXr3+q1Xw8+LRxZ4cte4PneoHaQ2iVck0gVThVbyOhSRM9YOoFMyR9eW6KmLkAGYW6Vmjx47AViUfSkPC5V9p7nS23q1Z9zH+b33+KuF9iAOocUa0lcKFjubQJ2h51D5zbmIAVM9gc1mzgAE0kdFlFaq+JkQYQBV+FYOYoDGy9Tw3dgQ7QxnUBQUHxAtJfUhqllDhbWam4f525mJDCgMynufZFa13d6BILHsOeEjS6PUjMNtsRHFXgExI2V0PN6egiEkTzFMdlJgM/3zMd1H2Tzhjlqa53TLhLFbsvep9Cob70uFsuffbxJoHWZcq1A5CCZyDUZ7gtxotKDCsafdRHIZSFe9j9wBl1xoIJSuxhUVpIK5eB0JiILHo29EouDtVmLBF4IKjIbWOQkfzYVruENn+ESXFe+upBJeDMQVfWiyXQ5fFQV57oQLyLJL0VlsAfi06yJyhMuIOci7Efdqy0ENzxxonVFI22IY0NDHN1mykaX+nHAmKbw1qhtLLVaze8U1o6Jv9OmdaEYlI1lsLQGGVGwmMKbKZ8KXHIQxnUJn062CgVSFmQTRjySpr8n2nlb3lxTztl8W6+u3x0YOlylrpij1Vi0Hl3uxNx/U9MWIYSPtwZxclukSG2B4qreOTV+3skzBBgbuafVrJ0sVYbO8eUe4r5FMAgEbEnbSSC2l/p0grgRB1jHDGKqjt019kkwvoid4okS4D7O+Qji4MmxiQMonI2cGP/qYwMbt6LSAXFEzpCbyYaJcxuKBAwWJQ5EwATCTScLBeUhVGKRTIWBCgQsVYavcdcF8UZEnVveYPwXfIwNBMJCdF/GNeEZCFnahMzX1A0dgEi6MJALigP1SyiMCdu9wZH7sZBzkGpM5zcBljAZGdNPX964UAhKt0vlwbN8SQs2p/Xq2lTSfzU4hvK0OUily4b0PV1etI4Z+SbBFYMBrIPjO1QuT1N+GedLbVC1FYM9Hyk31fgScHYYE5JhD1Dz/r+fKPoqEJAMILAa1VRaU+HwaPnZwBR3vWJwJCDCUSonsKERKHJMrwLFAYbSbUwRyujanawMZfBikPXTEzvCgKhXPZmhe+/W2ZCuTWXpxQbgyWGFmhGILLb8p6V/AmnKa+Qd3783cCDz0JaGvgmEX4jyaRu8W6N8NM/dPGlvvvk8T5ye2r7mIIQ5PEl5/pyXc4FzIeOLZOMWCn8Bh1eBvOSZzIIAAAAASUVORK5CYII=');
position: absolute;
height: 30px;
width: 25px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="mainContainer">
<div id="addRaces">
<input type="Button" value="Add Race" onclick="manager.addRace()">
</div>
<div id="races">
</div>
<br>
</div>
<div id="tableContainer">
<div id="tables"></div>
</div>
</body>
</html>
I expect it to move from y to x after clicking the reverse button, but it is not moving.
When you run the reverse function the elements are no longer referencing the dom elements.
I am actually not sure why that is, maybe someone else can chime in.
Anyway, this will fix your problem:
Replace this.element.style.left = step + 'px';
With: document.getElementById(this.element.id).style.left = step + 'px';

Categories

Resources