Archiv verlassen und diese Seite im Standarddesign anzeigen : Weltkarte erstellen (dauert ewig)
Hallo Leute,
ich häng schon ne weile an nem Problem.
Ich hab ein Projekt in dem es eine "Weltkarte" gibt.
Jede Koordinate und was sich auf dieser befindet ist in einer Datenbank gespeichert.
Um einen Überblick über die "Welt" zu bekommen - gibt es eine "Weltkarten" Funktion.
Diese habe ich mit vielen Bildern realisiert.
also für jede Koordinate wird ein Bild erzeugt was nur 2px x 2px groß ist und dann durch zb blaue oder grüne Färbung erkennt man ob dort Wasser oder ähnliches ist.
Das klappt auch prima. Problem hab ich nur bei größeren Karten. Ab einer größe von 50x50 dauert es halt ewig eh die Weltkarte aufgebaut ist. - weil ja dann 50x50 = 2500 Bilder geladen werden müssen.
Eigentlich wollte ich Karten bis zu einer Größe von ca 500x500 oder 1000x1000 benutzen. Nur das wird wohl dann leider nix mit der Variante.
Wie kann ich das anders lösen?
Hat da jemand ne idee?
ist hier wohl das falsche forum, daher verschieb ich es mal.
peter
martinm79 07-06-2009, 18:51 Wie lädst du denn die Bilder?
Was genau dauert denn lange?
naja einfach mit <img>
da hab ich dann sozusagen bei 50x50 --- 2500 img tags.
und eh die dann aufgebaut werden im browser dauert es halt (kannst ja mal testen - bei 50 bildern gehts relativ schnell aber sobald es mehr werden wird es mist)
wie sieht es eigentlich mit deinem hosting aus? ist das so ein billig-paket, wo zig tausend auftritte auf einem server liegen? oder arbeitest du derzeit noch lokal? wie wäre es mit einem preloader per javascript? einmal alle bilder laden (auch wenn es dauert) und dann sind sie im browsercache.
peter
also keine ahnung was du jetzt genau meinst mit meinem billig-angebot - aber ja ich teste es direkt bei meinem hoster und nicht lokal. ich kann es ja mal lokal ausprobieren aber ich denke nicht das das einen unterschied machen wird.
und zum preloaden: das ewige gelade will ich mir ja sparen. und da sich die karte immer mal ändert hab ich da auch nicht viel gekonnt.
habs jetzt mal lokal getestet mit xampp - und wie ich mir dachte das selbe problem bleibt
onemorenerd 07-06-2009, 20:33 Du könntest DIVs zeichnen statt IMG.
<?php
$width = 50;
$height = 50;
$scale = 3;
?>
<html>
<head>
<title></title>
<style type="text/css">
.pixel {
width: <?php echo $scale; ?>px;
height: <?php echo $scale; ?>px;
margin: 0;
padding: 0;
border: none;
display: block;
float: left;
}
.green {
background-color: 6c6;
}
.blue {
background-color: 39f;
}
</style>
</head>
<body>
<?php
if (isset($_GET['div'])) {
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
echo '<div class="pixel ' . (($x + $y) % 2 == 0 ? 'green' : 'blue') . '"></div>';
}
echo '<div style="clear: both;"></div>';
}
}
?>
<hr />
<?php
if (isset($_GET['img'])) {
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
echo '<img src="images/pixel_' . (($x + $y) % 2 == 0 ? 'green' : 'blue') . '.gif" class="pixel" />';
}
echo '<div style="clear: both;"></div>';
}
}
?>
</body>
</html>
Aber die meisten Browser haben Schwierigkeiten ab einer bestimmten Zahl sichtbarer Elemente. Mit IMG vielleicht schon bei 100x100, bei DIV vielleicht erst bei 200x200. Das kommt ganz auf den Browser an (und aufs CSS).
Du solltest dir einen anderen Weg suchen. Kennst du schon die mächtigen Image-Funktionen von PHP? ;)
ja hab ich auch schon überlegt.
nur geht das denn "schneller"?
oder hab ich dann das selbe problem?
ach ich verlink jedes bild noch extra - das wäre ja in nem großen bild eher ungünstig oder?
onemorenerd 07-06-2009, 20:39 Es geht in den meisten Browsern einen Tick schneller bzw. der Absturz kommt später (aber er kommt!). Probiers halt mal aus!
Das klappt auch prima. Problem hab ich nur bei größeren Karten. Ab einer größe von 50x50 dauert es halt ewig eh die Weltkarte aufgebaut ist. - weil ja dann 50x50 = 2500 Bilder geladen werden müssen.
Grob rechnet man pro HTP-Request mit einem Overhead von einem Kilobyte - also rechne dir aus, wie viel Daten dein Browser laden muss, wenn das wirklich alles einzelne Grafiken sind.
Dazu kommt natürlich noch, dass immer nur ein paar Ressourcen von einem Server parallel angefordert werden.
also für jede Koordinate wird ein Bild erzeugt was nur 2px x 2px groß ist und dann durch zb blaue oder grüne Färbung erkennt man ob dort Wasser oder ähnliches ist.
Den Ansatz kannst du in die Tonne kloppen. Erzeuge serverseitig ein grosses Bild, welches die entsprechenden Markierungen enthält.
und wie mach ich das dann mit dem verlinken?
also wenn man dann auf ne bestimmte stelle klickt soll man wo anders hinkommen. mit maparea? da hab ich ja dann wieder das selbe problem mit dem großen request
mit maparea? da hab ich ja dann wieder das selbe problem mit dem großen request
Ausprobieren, ob das performanter funktioniert.
Und wenn nicht, dann musst du die Datenmenge wohl oder übel verringern bzw. besser aufteilen.
Wenn du nur die Koordinaten übergeben willst kannst du das mit Javascript ja ganz einfach machen. Wenn du etwas genauer erlklähren würdest was für Links du da willst lässt sich sicher eine Lösung finden.
Beim Bild kannst du ja, wenn es nicht zu viele verschiedene 2x2 Pixel sind ganz gut ein komprimiertes PNG mit Palette erstellen und du wirst sogar bei 1000x1000 px mit relativ kleinen Bilddateien auskommen.
ja ich will in den links nur die koordinaten übergeben.
aber wie soll das gehen mit javascript? kann ich mir grad nich zusammreimen
Das geht sogar mit einem reinen Image-Formularelement (oder wie das hieß): Da werden x- und y-Koordinaten übergeben.
sry ich kann dir da grad nich ganz folgen.
nen beispiel wäre schon oder nach was man googlen soll
Und mit Javascript ist das auch recht einfach machbar (sry, wenns Tippfehler hat):
function elOffset(e){
var t = 0, l = 0;
do{
t += e.offsetTop || 0;
l += e.offsetLeft || 0;
e = e.offsetParent;
if(e && e.tagName.toUpperCase() == "BODY"){break;}
}while(e);
return [l, t];
}
function getRelativePosition(e){
e = e || window.event;
var x, y, t = e.target || e.srcElement, o = elOffset(t);
if(window.attachEvent && navigator.userAgent.indexOf("Opera") == -1){
x = e.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
y = e.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
}else{
x = e.pageX
y = e.pageY
}
x -= o[0];
y -= o[1];
alert("x: " + x + "\ny: " + y)
}
document.getElementById("myImage").onclick = getRelativePosition;
wow klappt 1a
leider kenn ich mich mit javascript nich so gut aus.
aber funzt denk ich so weit. vielen dank.
sry ich kann dir da grad nich ganz folgen.
Wenn dir das noch nicht klar ist:
Erstelle einmal ein Formular mit einem input type="image". Wenn du dann das Formular per GET überträgst lasse dir $_GET einmal mit prin_r ausgeben, wenn per POST mach ein print_r($_POST); (Das Formular muss mit einem Klick auf den Bildbutton abgeschickt werden).
Dann wirst du sehen, was Pekka vorschlug. Sein Vorschlag ist je nach Situation besser als mit Javascript.
fireweasel 07-06-2009, 23:46 Linktipps:
http://de.selfhtml.org/html/grafiken/verweis_sensitive.htm
http://de.selfhtml.org/html/formulare/formularbuttons.htm#grafische
un ich kann mir jezt mit imagefilledrectangle dort 10000 rechtecke in das große bild malen lassen? oder gibs da ne begrenzung?
oder meintet ihr ne andere funktion um das große bild zu malen
ps: weil irgendwie stell ich grad fest das der mir nur (ka ahnung wieviel genau aber so ca 200 rechtecke macht dann is schluss)
Die maximale Ausführungszeit für das Script kann natürlich problematisch werden ...
martinm79 08-06-2009, 05:13 Ich habe schon eine Karte gebaut und diese einfach nur als Bild angezeigt.
Mittels css die Links rübergesetzt und fertig.
Wo ist das Problem?
Und generell sollte man darauf achten, das du nicht zu viele Bilder lädst.
Pro Seite nicht mehr als 20, was man normal auch locker schafft.
Das hilft mir jetzt aber nicht weiter.
An den 30sek wirds nicht liegen. Weil 1.bekommt man ja ne meldung und 2. Wird meine schleife ja diese 10000ma durchlaufen. Nur er malt nur die ersten 200 rechtecke und dann nix mehr aber die schleife läuft weiter.
Ich hab jetzt nur ein bild.
Und wie hast du das gemacht martinm79?
Hast du für jedes feld ein rechteck gemalt oder bin ich da am falschen ansatz?
onemorenerd 08-06-2009, 10:48 Also ich habe gerade testweise ein 1600x800 Bild völlständig übermalt, in dem ich 1.280.000 Mal imagefilledrectangle() aufgerufen habe. Funktioniert 1a und dauert keine ganze Sekunde.
Bist du dir sicher, dass du die Pixel wirklich ins Bild setzt? Wenn man Koordinaten außerhalb des Bildes angibt, dauert es deutlich länger oder schmiert ab.
hm eigentlich schon.
ich guck nochma drüber.
gibt es ansonsten vielleicht ne php.ini einstellung die so etwas begrenzt oder dergleichen?
hm habs grad nochma von vorn getestet.
irgendwie liegts an der farbe. kann mir den fehler nur noch nicht erklären. ich test ma noch weiter.
aber danke für deine hilfe schonma das du es bei dir ausprobiert hast.
ps: ja ich hab in meiner schleife die farbbestimmung mittels imagecolorallocate gemacht. das geht wohl so nicht weil das nur 254 mal geht.
danke für eure hilfe ich habs jetzt ^^
hab einfach die farbdefinition außerhalb der schleife - weil ich hab keine 254 verschiedenen farben - da gehts :) *puhh*
onemorenerd 08-06-2009, 11:12 Du erzeugst jede Farbe hoffentlich nur einmal und nicht etwa für jedes Pixel erneut?!
Hier mein Code zum Vergleich.
$width = 1600;
$height = 800;
$scale = 1;
// http://flatplanet.sourceforge.net/maps/images/earth-living.jpg
$im = imagecreatefromjpeg('images/earth-living.jpg');
$green = imagecolorallocate($im, 0x66, 0xcc, 0x66);
$blue = imagecolorallocate($im, 0x33, 0x99, 0xff);
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
imagefilledrectangle($im,
$x*$scale, $y*$scale,
$x*$scale+$scale, $y*$scale+$scale,
($x+$y)%2 ? $green : $blue);
}
}
header('Content-type: image/jpeg');
imagejpeg($im);
doch ich hatte es vorher für jeden pixel neu erstellt.
das war der fehler.
und ich hab imagecreate statt imagecreatetruecolor benutzt.
eines von beiden ändern und es klappt :)
martinm79 08-06-2009, 20:07 Ich habe ein Bild als Hintergund in einem Formular Imagebutton gehabt.
Durch klick habe ich mir die x y Koordinaten in die DB gespeichern.
Beim auslesen habe ich einfach das Bild als Hintergrund in einem DIV gepackt und mittels CSS die Links rübergepackt.
Das war aber nur zum kennzeichnen einzelner Orte auf einer Karte und es waren nicht tausend.
Und falls du perfomance Probleme hast, dann würde ich den berechnetet Quelltext in der DB zwischenspeichern. ^^
Denn braucht er eine große schleife nicht jedes mal durchlaufen.
wie sieht es eigentlich mit deinem hosting aus? ist das so ein billig-paket, wo zig tausend auftritte auf einem server liegen? oder arbeitest du derzeit noch lokal? wie wäre es mit einem preloader per javascript? einmal alle bilder laden (auch wenn es dauert) und dann sind sie im browsercache.
peter
um das nochmal aufzugreifen.
gibs denn bei so nem "billig-hoster" dann eher die performance-probleme das es ewig lädt - aber nich am script liegt sondern halt am server?
onemorenerd 08-06-2009, 23:07 Zeig doch mal den Code, der die Daten aus der DB holt und dann daraus das notwendige Markup generiert. Dann kann man mehr dazu sagen.
Generell sehe ich das Performanceproblem eher clientseitig. Sofern die Daten schon gut vorbereitet gespeichert sind, so dass serverseitig nicht jedes Mal aufwendig gerechnet werden muss, sollte das auch bei jedem Billighoster flutschen.
Bisher hab ichs so gemacht:
in meiner db gibs ne tabelle "map" in der gibts für jede koordinate nen eintrag: x
y
art
und ne 2. tabelle map_cfg in der dann die arten definiert sind mit ner farbe auf ner weltkarte (und noch mehr)
$im = imagecreatetruecolor(MAP_X*WORLDMAP_GROESSE, MAP_Y*WORLDMAP_GROESSE);
imagefill ($im, "0", "0", imagecolorallocate($im,0,153,0)); // hintergrund gruen
for ($x=1;$x<=MAP_X;$x++) {
for ($y=1;$y<=MAP_Y;$y++) {
$sql2 = "SELECT art FROM map WHERE x = ".$x." AND y = ".$y.";";
$result2 = mysql_query($sql2) OR die("Query: <pre>".$sql2."</pre>\n"."Antwort: ".mysql_error());
while($row2 = mysql_fetch_assoc($result2)) {
$sql3 = "SELECT * FROM map_cfg WHERE art = '".$row2['art']."';";
$result3 = mysql_query($sql3) OR die("Query: <pre>".$sql3."</pre>\n"."Antwort: ".mysql_error());
while($row3 = mysql_fetch_assoc($result3)) {
imagefilledrectangle($im, ($x-1)*WORLDMAP_GROESSE, ($y-1)*WORLDMAP_GROESSE, ($x-1)*WORLDMAP_GROESSE+WORLDMAP_GROESSE, ($y-1)*WORLDMAP_GROESSE+WORLDMAP_GROESSE, farbe($row3['weltkarte'], $im));
}
}
}
}
imagepng($im, MAP_BILDPFAD."worldmap.png");
imagedestroy($im);
echo "<img src=".MAP_BILDPFAD."worldmap.png?".date("U").">";
ach und die funktion farbe:
function farbe($var = "000000", $im) {
$r = hexdec(substr($var, 0, 2));
$g = hexdec(substr($var, 2, 2));
$b = hexdec(substr($var, 4, 2));
$farbe = imagecolorallocate($im, $r, $g, $b);
return $farbe;
}
onemorenerd 08-06-2009, 23:52 Oweia! Mach dich mal zum Thema JOIN schlau!
ja gut daran liegts doch aber nicht mit der performance...
hier mit join:
$sql2 = "SELECT * FROM map INNER JOIN map_art ON map.art = map_art.art WHERE map.x = ".$x." AND map.y = ".$y.";";
wie gesagt bei 50x50 gehts schneller - bei 200x200 dauerts eig schon ewig.
das doch alles mist :(
edit: hier nochma komplett zur übersicht:
for ($x=1;$x<=MAP_X;$x++) {
for ($y=1;$y<=MAP_Y;$y++) {
$sql2 = "SELECT * FROM map INNER JOIN map_art ON map.art = map_art.art WHERE map.x = ".$x." AND map.y = ".$y.";";
$result2 = mysql_query($sql2) OR die("Query: <pre>".$sql2."</pre>\n"."Antwort: ".mysql_error());
while($row2 = mysql_fetch_assoc($result2)) {
imagefilledrectangle($im, ($x-1)*WORLDMAP_GROESSE, ($y-1)*WORLDMAP_GROESSE, ($x-1)*WORLDMAP_GROESSE+WORLDMAP_GROESSE, ($y-1)*WORLDMAP_GROESSE+WORLDMAP_GROESSE, farbe($row2['weltkarte'], $im));
}
}
}
guck zum beispiel mal hier:
Worldmap (http://www.the-crusades.org/bigmap.php) (zoom auf 5 stellen)
wie hat der das gemacht das das so schnell geht?
onemorenerd 09-06-2009, 10:24 ja gut daran liegts doch aber nicht mit der performance...
Doch, daran liegt es! Die Anzahl der DB-Abfragen hängt bei dir von der Dimension des Bildes ab. Das ist Unsinn.
Hole dir alle Daten mit einem JOIN vor der Schleife!
Merke: Niemals DB-Abfragen in Schleifen; das bringt dich um!
achsoooo
ohne schleife
kopf -> tisch
ja ok jetzt ist das problem weg ^^ *lol*
hab jetzt nur noch ne sql und keine for's mehr
klappt tausend mal schneller. das bild ist eigentlich sofort da.
danke ^^
Verwende übrigens kein SELECT *, sondern selektiere genau die Spalten, die du haben willst.
weil?
ist das auch noch nen ticken schneller oder wie?
weil?
ist das auch noch nen ticken schneller oder wie?
jepp!
peter
nichtsooft 19-06-2009, 15:04 Naja; Sollte die Frage nicht eher sein, wie's DB-Seitig aussieht!?
Welche DB-Abfragen verwendest du!? Miss mal die Microtime und verrat' uns wie lange die DB-Geschichte dauert.... :charity:
|