Google Maps API V3 - wiele znaczników w tym samym miejscu


115

Trochę utknęło na tym. Pobieram listę współrzędnych geograficznych przez JSON i umieszczam je na mapie google. Wszystko działa dobrze, z wyjątkiem przypadku, gdy mam dwa lub więcej znaczników dokładnie w tym samym miejscu. API wyświetla tylko 1 znacznik - górny. Przypuszczam, że jest to w porządku, ale chciałbym znaleźć sposób, aby jakoś je wszystkie wyświetlić.

Przeszukałem google i znalazłem kilka rozwiązań, ale w większości wydają się one być przeznaczone dla wersji 2 interfejsu API lub po prostu nie są tak świetne. Idealnie byłoby, gdybyś kliknął jakiś znacznik grupy, a następnie pokazał znaczniki zgrupowane wokół miejsca, w którym się wszyscy znajdują.

Czy ktoś miał ten lub podobny problem i chciałby podzielić się rozwiązaniem?

Odpowiedzi:


116

Spójrz na OverlappingMarkerSpiderfier .
Jest strona demonstracyjna, ale nie pokazują one znaczników, które są dokładnie w tym samym miejscu, tylko niektóre, które są bardzo blisko siebie.

Ale przykład z życia wzięty ze znacznikami dokładnie w tym samym miejscu można zobaczyć na http://www.ejw.de/ejw-vor-ort/ (przewiń w dół, aby zobaczyć mapę i kliknij kilka znaczników, aby zobaczyć efekt pająka ).

To wydaje się być idealnym rozwiązaniem twojego problemu.


Jest to niesamowite i doskonale spełnia wymagania pozostawione w bibliotece klastrów, która nie obsługuje markerów o tej samej dokładnej szerokości / długości.
Justin,

Jeśli używasz OverlappingMarkerSpiderfierw połączeniu z MarkerClusterer, dobrą opcją jest ustawienie maxZoomopcji w konstruktorze klastra. Spowoduje to usunięcie klastrów ze znaczników po określonym poziomie powiększenia.
Diederik

@Tad Nie wiem, czy jesteś twórcą tej strony, ale chciałem poinformować, że mapa na ejw.de jest zepsuta. Otrzymuję błąd JS.
Alex

Sprawdziłem proponowane demo, ale wygląda na to, że nie działa. Po dalszych badaniach znalazłem ten przykład, jak zintegrować klastry markerów i Spiderifier. Brak wersji demonstracyjnej na żywo, ale po prostu sklonuj i postępuj zgodnie z plikiem readme. github.com/yagoferrer/markerclusterer-plus-spiderfier-example
Sax

34

Przesuwanie znaczników nie jest prawdziwym rozwiązaniem, jeśli znajdują się w tym samym budynku. To, co możesz chcieć zrobić, to zmodyfikować markerclusterer.js w następujący sposób:

  1. Dodaj prototypową metodę click w klasie MarkerClusterer, tak jak to pokazano - zastąpimy to później w funkcji inicjalizacji mapy ():

    MarkerClusterer.prototype.onClick = function() { 
        return true; 
    };
  2. W klasie ClusterIcon dodaj następujący kod PO wyzwalaczu clusterclick:

    // Trigger the clusterclick event.
    google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_);
    
    var zoom = this.map_.getZoom();
    var maxZoom = markerClusterer.getMaxZoom();
    // if we have reached the maxZoom and there is more than 1 marker in this cluster
    // use our onClick method to popup a list of options
    if (zoom >= maxZoom && this.cluster_.markers_.length > 1) {
       return markerClusterer.onClickZoom(this);
    }
  3. Następnie w funkcji initialize (), w której inicjalizujesz mapę i deklarujesz obiekt MarkerClusterer:

    markerCluster = new MarkerClusterer(map, markers);
    // onClickZoom OVERRIDE
    markerCluster.onClickZoom = function() { return multiChoice(markerCluster); }

    Gdzie multiChoice () to TWOJA (jeszcze nie napisana) funkcja wyskakująca okno InfoWindow z listą opcji do wyboru. Zauważ, że obiekt markerClusterer jest przekazywany do twojej funkcji, ponieważ będziesz potrzebować tego do określenia, ile znaczników znajduje się w tym klastrze. Na przykład:

    function multiChoice(mc) {
         var cluster = mc.clusters_;
         // if more than 1 point shares the same lat/long
         // the size of the cluster array will be 1 AND
         // the number of markers in the cluster will be > 1
         // REMEMBER: maxZoom was already reached and we can't zoom in anymore
         if (cluster.length == 1 && cluster[0].markers_.length > 1)
         {
              var markers = cluster[0].markers_;
              for (var i=0; i < markers.length; i++)
              {
                  // you'll probably want to generate your list of options here...
              }
    
              return false;
         }
    
         return true;
    }

17

Użyłem tego razem z jQuery i spełnia swoje zadanie:

var map;
var markers = [];
var infoWindow;

function initialize() {
    var center = new google.maps.LatLng(-29.6833300, 152.9333300);

    var mapOptions = {
        zoom: 5,
        center: center,
        panControl: false,
        zoomControl: false,
        mapTypeControl: false,
        scaleControl: false,
        streetViewControl: false,
        overviewMapControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      }


    map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

    $.getJSON('jsonbackend.php', function(data) {
        infoWindow = new google.maps.InfoWindow();

        $.each(data, function(key, val) {
            if(val['LATITUDE']!='' && val['LONGITUDE']!='')
            {                
                // Set the coordonates of the new point
                var latLng = new google.maps.LatLng(val['LATITUDE'],val['LONGITUDE']);

                //Check Markers array for duplicate position and offset a little
                if(markers.length != 0) {
                    for (i=0; i < markers.length; i++) {
                        var existingMarker = markers[i];
                        var pos = existingMarker.getPosition();
                        if (latLng.equals(pos)) {
                            var a = 360.0 / markers.length;
                            var newLat = pos.lat() + -.00004 * Math.cos((+a*i) / 180 * Math.PI);  //x
                            var newLng = pos.lng() + -.00004 * Math.sin((+a*i) / 180 * Math.PI);  //Y
                            var latLng = new google.maps.LatLng(newLat,newLng);
                        }
                    }
                }

                // Initialize the new marker
                var marker = new google.maps.Marker({map: map, position: latLng, title: val['TITLE']});

                // The HTML that is shown in the window of each item (when the icon it's clicked)
                var html = "<div id='iwcontent'><h3>"+val['TITLE']+"</h3>"+
                "<strong>Address: </strong>"+val['ADDRESS']+", "+val['SUBURB']+", "+val['STATE']+", "+val['POSTCODE']+"<br>"+
                "</div>";

                // Binds the infoWindow to the point
                bindInfoWindow(marker, map, infoWindow, html);

                // Add the marker to the array
                markers.push(marker);
            }
        });

        // Make a cluster with the markers from the array
        var markerCluster = new MarkerClusterer(map, markers, { zoomOnClick: true, maxZoom: 15, gridSize: 20 });
    });
}

function markerOpen(markerid) {
    map.setZoom(22);
    map.panTo(markers[markerid].getPosition());
    google.maps.event.trigger(markers[markerid],'click');
    switchView('map');
}

google.maps.event.addDomListener(window, 'load', initialize);

Dzięki dla mnie działa idealnie :) Właśnie tego szukałem od godzin: p
Jicao

Piękne i eleganckie rozwiązanie. Dziękuję Ci!
Concept211

Idealne rozwiązanie trochę kompensujące! Czy to możliwe,
najeżdżamy

14

Rozwijając odpowiedź Chaoleya , zaimplementowałem funkcję, która mając listę lokalizacji (obiektów z lngilat właściwości), których współrzędne są dokładnie takie same, nieco odsuwa je od ich pierwotnego położenia (modyfikując obiekty w miejscu). Następnie tworzą ładny okrąg wokół punktu środkowego.

Zauważyłem, że dla mojej szerokości geograficznej (52 stopnie północy) promień okręgu 0,0003 działa najlepiej i że po przeliczeniu na kilometry należy nadrobić różnicę między stopniami szerokości i długości geograficznej. Można znaleźć przybliżone konwersji dla szerokości geograficznej tutaj .

var correctLocList = function (loclist) {
    var lng_radius = 0.0003,         // degrees of longitude separation
        lat_to_lng = 111.23 / 71.7,  // lat to long proportion in Warsaw
        angle = 0.5,                 // starting angle, in radians
        loclen = loclist.length,
        step = 2 * Math.PI / loclen,
        i,
        loc,
        lat_radius = lng_radius / lat_to_lng;
    for (i = 0; i < loclen; ++i) {
        loc = loclist[i];
        loc.lng = loc.lng + (Math.cos(angle) * lng_radius);
        loc.lat = loc.lat + (Math.sin(angle) * lat_radius);
        angle += step;
    }
};

1
DzinX, spędziłem ostatnie 4 godziny próbując dowiedzieć się, jak mogę zaimplementować twój kod do mojego kodu bez skutku. Doszedłem do wniosku, że jestem do dupy i naprawdę byłbym wdzięczny za twoją pomoc. Oto miejsce, w którym próbuję podłączyć kod: pastebin.com/5qYbvybm - KAŻDA POMOC będzie mile widziana! Dzięki!
WebMW,

WebMW: Po wyodrębnieniu znaczników z XML należy najpierw pogrupować je w listy, tak aby każda lista zawierała znaczniki wskazujące dokładnie to samo położenie. Następnie na każdej liście zawierającej więcej niż jeden element uruchom poprawnąLocList (). Dopiero gdy to zrobisz, utwórz obiekty google.maps.Marker.
DzinX

To nie działa ... Zmienia tylko moje najszersze długie z 37.68625400000000000,-75.71669800000000000na 37.686254,-75.716698również, co jest takie samo dla wszystkich wartości ... Spodziewałem się czegoś takiego ... 37.68625400000000000,-75.71669800000000000na ... 37.6862540000001234,-75.7166980000001234 37.6862540000005678,-75.7166980000005678itd. Próbowałem też zmienić kąt.
Premshankar Tiwari

Hummm, poszukajmy trochę i miejmy nadzieję, że @DzinX nadal jest w okolicy. Czy możesz mate (lub kogokolwiek innego) wyjaśnić, w jaki sposób uzyskałeś te wszystkie liczby? Lng_radius itp.? Wielkie dzięki. :)
Vae

1
@Vae: Promień określa, jak duży ma być okrąg. Chcesz, aby okrąg był zaokrąglony w pikselach, więc musisz wiedzieć, w Twojej lokalizacji, jaka jest proporcja 1 stopnia szerokości geograficznej do 1 stopnia długości geograficznej (w pikselach na mapie). Możesz to znaleźć na niektórych stronach internetowych lub po prostu eksperymentować, aż uzyskasz prawidłową liczbę. Kąt określa, jak bardzo pierwszy kołek znajduje się na prawo od góry.
DzinX

11

Najdoskonalsza odpowiedź @Ignatius, zaktualizowana do pracy z wersją 2.0.7 MarkerClustererPlus.

  1. Dodaj prototypową metodę click w klasie MarkerClusterer, tak jak to pokazano - zastąpimy to później w funkcji inicjalizacji mapy ():

    // BEGIN MODIFICATION (around line 715)
    MarkerClusterer.prototype.onClick = function() { 
        return true; 
    };
    // END MODIFICATION
  2. W klasie ClusterIcon dodaj następujący kod PO wyzwalaczu kliknięcia / kliknięcia klastra:

    // EXISTING CODE (around line 143)
    google.maps.event.trigger(mc, "click", cClusterIcon.cluster_);
    google.maps.event.trigger(mc, "clusterclick", cClusterIcon.cluster_); // deprecated name
    
    // BEGIN MODIFICATION
    var zoom = mc.getMap().getZoom();
    // Trying to pull this dynamically made the more zoomed in clusters not render
    // when then kind of made this useless. -NNC @ BNB
    // var maxZoom = mc.getMaxZoom();
    var maxZoom = 15;
    // if we have reached the maxZoom and there is more than 1 marker in this cluster
    // use our onClick method to popup a list of options
    if (zoom >= maxZoom && cClusterIcon.cluster_.markers_.length > 1) {
        return mc.onClick(cClusterIcon);
    }
    // END MODIFICATION
  3. Następnie w funkcji initialize (), w której inicjalizujesz mapę i deklarujesz obiekt MarkerClusterer:

    markerCluster = new MarkerClusterer(map, markers);
    // onClick OVERRIDE
    markerCluster.onClick = function(clickedClusterIcon) { 
      return multiChoice(clickedClusterIcon.cluster_); 
    }

    Gdzie multiChoice () to TWOJA (jeszcze nie napisana) funkcja wyskakująca okno InfoWindow z listą opcji do wyboru. Zauważ, że obiekt markerClusterer jest przekazywany do twojej funkcji, ponieważ będziesz potrzebować tego do określenia, ile znaczników znajduje się w tym klastrze. Na przykład:

    function multiChoice(clickedCluster) {
      if (clickedCluster.getMarkers().length > 1)
      {
        // var markers = clickedCluster.getMarkers();
        // do something creative!
        return false;
      }
      return true;
    };

1
Dzięki, to działa idealnie! Jeśli chodzi o twój maxZoomproblem, myślę, że jest to problem tylko wtedy, gdy nie ma ustawionego maxZoom lub maxZoom dla klastra jest większy niż powiększenie mapy. Zastąpiłem twój zakodowany na stałe ten fragment i wygląda na to, że działa ładnie:var maxZoom = mc.getMaxZoom(); if (null === maxZoom || maxZoom > mc.getMap().maxZoom) { maxZoom = mc.getMap().maxZoom; if (null === maxZoom) { maxZoom = 15; } }
Pascal

Wiem, że to naprawdę stare, ale próbuję skorzystać z tego rozwiązania. Mam to działające, ale w przypadku wyświetlania okna informacyjnego z danymi klastra ... jak uzyskać pozycję znacznika klastra, który został kliknięty w pierwszej kolejności, aby móc wyświetlić okno informacyjne? markery to moja tablica danych ... ale jak mogę wyświetlić okno informacyjne na ikonie / znaczniku klastra?
user756659

@ user756659 w multiChoice otrzymujesz lat / lng przez: clickedCluster.center_.lat()/clickedCluster.center_.lng()
Jens Kohl

1
@Pascal i przy odrobinie zaciemnienia otrzymujemy to, co może zadziałać, ale jak mówi tao Pythona. „liczy się czytelność”. var maxZoom = Math.min (mc.getMaxZoom () || 15, mc.getMap (). maxZoom || 15);
Nande

6

Powyższe odpowiedzi są bardziej eleganckie, ale znalazłem szybki i brudny sposób, który działa naprawdę niesamowicie dobrze. Możesz to zobaczyć w akcji na www.buildinglit.com

Wszystko, co zrobiłem, to dodanie losowego przesunięcia do szerokości i długości geograficznej na mojej stronie genxml.php, więc za każdym razem zwraca nieco inne wyniki z przesunięciem za każdym razem, gdy mapa jest tworzona ze znacznikami. Brzmi to jak włamanie, ale w rzeczywistości wystarczy, że znaczniki przesuną się nieznacznie w losowym kierunku, aby można je było kliknąć na mapie, jeśli nachodzą na siebie. Właściwie działa naprawdę dobrze, powiedziałbym, że lepiej niż metoda pająka, ponieważ kto chce poradzić sobie z tą złożonością i mieć je wszędzie. Chcesz tylko móc wybrać znacznik. Podsuwanie jej losowo działa idealnie.

Oto przykład tworzenia węzła iteracji instrukcji while w moim php_genxml.php

while ($row = @mysql_fetch_assoc($result)){ $offset = rand(0,1000)/10000000;
$offset2 = rand(0, 1000)/10000000;
$node = $dom->createElement("marker");
$newnode = $parnode->appendChild($node);
$newnode->setAttribute("name", $row['name']);
$newnode->setAttribute("address", $row['address']);
$newnode->setAttribute("lat", $row['lat'] + $offset);
$newnode->setAttribute("lng", $row['lng'] + $offset2);
$newnode->setAttribute("distance", $row['distance']);
$newnode->setAttribute("type", $row['type']);
$newnode->setAttribute("date", $row['date']);
$newnode->setAttribute("service", $row['service']);
$newnode->setAttribute("cost", $row['cost']);
$newnode->setAttribute("company", $company);

Zauważ, że pod szerokością i długością znajduje się przesunięcie +. z 2 zmiennych powyżej. Musiałem podzielić losowo przez 0,1000 na 10000000, aby uzyskać liczbę dziesiętną, która była losowo wystarczająco mała, aby ledwo przesuwać znaczniki. Możesz majstrować przy tej zmiennej, aby uzyskać taką, która jest bardziej precyzyjna dla Twoich potrzeb.


Chłodny! to jest brudny hack, który uważam za bardzo przydatny, nie trzeba mieszać z kodem API Map Google
CuongDC

3

W sytuacjach, gdy w tym samym budynku znajduje się wiele usług, można nieznacznie przesunąć znaczniki (powiedzmy o 0,001 stopnia) w promieniu od rzeczywistego punktu. Powinno to również dać ładny efekt wizualny.


3

Jest to raczej „szybkie i brudne” rozwiązanie, podobne do tego, które sugeruje Matthew Fox, tym razem przy użyciu JavaScript.

W JavaScript możesz po prostu przesunąć szerokość i długość wszystkich swoich lokalizacji, dodając małe losowe przesunięcie do obu np

myLocation[i].Latitude+ = (Math.random() / 25000)

(Odkryłem, że dzieląc przez 25000 zapewnia wystarczającą separację, ale nie przesuwa znacznika znacząco z dokładnej lokalizacji, np. Konkretnego adresu)

Daje to całkiem niezłą robotę polegającą na równoważeniu ich od siebie, ale dopiero po dokładnym powiększeniu. Po pomniejszeniu nadal nie będzie jasne, że istnieje wiele opcji lokalizacji.


1
Lubię to. Jeśli nie potrzebujesz dokładnie reprezentatywnych markerów, po prostu obniż 25000 do 250 lub 25. Proste i szybkie rozwiązanie.
Fid

2

Sprawdź Marker Clusterer for V3 - ta biblioteka skupia pobliskie punkty w znaczniku grupy. Mapa powiększa się po kliknięciu klastrów. Wyobrażam sobie, że po bezpośrednim powiększeniu nadal miałbyś ten sam problem ze znacznikami w tym samym miejscu.


Tak, przyjrzałem się tej poręcznej małej bibliotece, ale nadal wydaje się, że nie rozwiązuje ona problemu. Robię lokalizator usług dla firmy, która czasami ma więcej niż jedną usługę w tym samym biurowcu i stąd te same współrzędne geograficzne. Mogę pokazać różne usługi w jednym oknie informacyjnym, ale to po prostu nie wydaje się być najbardziej eleganckim rozwiązaniem ...
Louzoid

@Louzoid Marker Clusterer nie rozwiązuje problemu, jak właśnie się dowiedziałem. Mam ten sam problem, mam kilka firm w jednym budynku i dlatego pokazuje tylko 1 znacznik.
Rob

1

Zaktualizowano do pracy z MarkerClustererPlus.

  google.maps.event.trigger(mc, "click", cClusterIcon.cluster_);
  google.maps.event.trigger(mc, "clusterclick", cClusterIcon.cluster_); // deprecated name

  // BEGIN MODIFICATION
  var zoom = mc.getMap().getZoom();
  // Trying to pull this dynamically made the more zoomed in clusters not render
  // when then kind of made this useless. -NNC @ BNB
  // var maxZoom = mc.getMaxZoom();
  var maxZoom = 15;
  // if we have reached the maxZoom and there is more than 1 marker in this cluster
  // use our onClick method to popup a list of options
  if (zoom >= maxZoom && cClusterIcon.cluster_.markers_.length > 1) {
    var markers = cClusterIcon.cluster_.markers_;
    var a = 360.0 / markers.length;
    for (var i=0; i < markers.length; i++)
    {
        var pos = markers[i].getPosition();
        var newLat = pos.lat() + -.00004 * Math.cos((+a*i) / 180 * Math.PI);  // x
        var newLng = pos.lng() + -.00004 * Math.sin((+a*i) / 180 * Math.PI);  // Y
        var finalLatLng = new google.maps.LatLng(newLat,newLng);
        markers[i].setPosition(finalLatLng);
        markers[i].setMap(cClusterIcon.cluster_.map_);
    }
    cClusterIcon.hide();
    return ;
  }
  // END MODIFICATION

Takie podejście wymaga od użytkownika kliknięcia ikony klastra i nie obejmuje przypadków użycia, w których nawigacja odbywa się za pomocą suwaka powiększenia lub przewijania myszy. Jakieś pomysły, jak rozwiązać te problemy?
Remi Sture,

1

Lubię proste rozwiązania, więc oto moje. Zamiast modyfikować bibliotekę, co utrudniłoby jej utrzymanie. możesz po prostu obejrzeć to wydarzenie

google.maps.event.addListener(mc, "clusterclick", onClusterClick);

wtedy możesz nim zarządzać

function onClusterClick(cluster){
    var ms = cluster.getMarkers();

i, tj. użyłem bootstrap, aby wyświetlić panel z listą. co uważam za znacznie wygodniejsze i bardziej użyteczne niż spiderfing w „zatłoczonych” miejscach. (jeśli używasz klastra, są szanse, że skończysz z kolizjami po spiderfy). tam też możesz sprawdzić powiększenie.

przy okazji. Właśnie znalazłem ulotkę i wydaje się, że działa znacznie lepiej, klaster ORAZ spiderfy działa bardzo płynnie http://leaflet.github.io/Leaflet.markercluster/example/marker-clustering-realworld.10000.html i jest open-source.



0

Rozwijając odpowiedzi podane powyżej, po prostu upewnij się, że ustawiłeś opcję maxZoom podczas inicjalizacji obiektu mapy.


0

Podanie przesunięcia sprawi, że znaczniki będą daleko, gdy użytkownik powiększy do maks. Więc znalazłem sposób, aby to osiągnąć. może to nie jest właściwy sposób, ale działał bardzo dobrze.

// This code is in swift
for loop markers
{
//create marker
let mapMarker = GMSMarker()
mapMarker.groundAnchor = CGPosition(0.5, 0.5)
mapMarker.position = //set the CLLocation
//instead of setting marker.icon set the iconView
let image:UIIMage = UIIMage:init(named:"filename")
let imageView:UIImageView = UIImageView.init(frame:rect(0,0, ((image.width/2 * markerIndex) + image.width), image.height))
imageView.contentMode = .Right
imageView.image = image
mapMarker.iconView = imageView
mapMarker.map = mapView
}

ustaw zIndex znacznika tak, aby na górze była widoczna ikona markera, którą chcesz zobaczyć, w przeciwnym razie będzie animować znaczniki, jak automatyczna zamiana. gdy użytkownik dotknie markera, uchwyć zIndex, aby przenieść marker na górę za pomocą zIndex Swap.


0

Jak sobie z tym poradzić ... [Swift]

    var clusterArray = [String]()
    var pinOffSet : Double = 0
    var pinLat = yourLat
    var pinLong = yourLong
    var location = pinLat + pinLong

Czy ma powstać nowy znacznik? sprawdź clusterArrayi manipuluj jego przesunięciem

 if(!clusterArray.contains(location)){
        clusterArray.append(location)
    } else {

        pinOffSet += 1
        let offWithIt = 0.00025 // reasonable offset with zoomLvl(14-16)
        switch pinOffSet {
        case 1 : pinLong = pinLong + offWithIt ; pinLat = pinLat + offWithIt
        case 2 : pinLong = pinLong + offWithIt ; pinLat = pinLat - offWithIt
        case 3 : pinLong = pinLong - offWithIt ; pinLat = pinLat - offWithIt
        case 4 : pinLong = pinLong - offWithIt ; pinLat = pinLat + offWithIt
        default : print(1)
        }


    }

wynik

wprowadź opis obrazu tutaj


0

Dodając do podstępnej, genialnej odpowiedzi Matthew Foxa, dodałem małe losowe przesunięcie do każdej szerokości i lng podczas ustawiania obiektu znacznika. Na przykład:

new LatLng(getLat()+getMarkerOffset(), getLng()+getMarkerOffset()),

private static double getMarkerOffset(){
    //add tiny random offset to keep markers from dropping on top of themselves
    double offset =Math.random()/4000;
    boolean isEven = ((int)(offset *400000)) %2 ==0;
    if (isEven) return  offset;
    else        return -offset;
}

-2

Rozszerzając powyższe odpowiedzi, gdy otrzymałeś połączone łańcuchy, nie dodaną / odjętą pozycję (np. "37.12340-0.00069"), przekonwertuj oryginalną szerokość / długość geograficzną na zmiennoprzecinkowe, np. Za pomocą parseFloat (), a następnie dodaj lub odejmij poprawki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.