Δημιουργία σελίδων και εφαρμογών με Javascript και HTML 5
Εισαγωγή
Τα βασικά
Το ελάχιστο περιεχόμενο που χρειάζεται μια σελίδα HTML5 είναι:
<!DOCTYPE html>
<html>
<head>
<title>περιγραφή</title>
</head>
<body>
περιεχόμενο......
</body>
</html>
Ουσιαστικά η μόνη διαφορά από την παραδοσιακή HTML 4 είναι το: <!DOCTYPE html>
Στην πραγματικότητα βέβαια χρειάζεται και το: <meta http-equiv=Content-Type content="text/html; charset=utf-8"> διαφορετικά δεν θα φαίνονται σωστά τα ελληνικά (θεωρούμε ως δεδομένο πως το κείμενο είναι σε μορφή Unicode).
Τα νέα χαρακτηριστικά της HTML 5
• Το <canvas> element για ζωγραφική 2D (2 διαστάσεων)
• Τα <video> και <audio> elements
• Υποστήριξη για local storage
• Νέες ειδικές tags (elements όπως τα αποκαλούν τώρα) όπως <article>, <footer>, <header>, <nav>, <section>
• Νέας μορφής controls, όπως calendar, date, time, email, url, search
Δυστυχώς όλα αυτά δεν υποστηρίζονται από παλιούς browsers.
Καταργημένα τμήματα της HTML 4
• <acronym>
• <applet>
• <basefont>
• <big>
• <center>
• <dir>
• <font>
• <frame>
• <frameset>
• <noframes>
• <strike>
• <tt>
Στοιχεία προγραμματισμού σε Javascript
Εισαγωγή στην Javascript
Το πρώτο πράγμα που πρέπει να γνωρίζει κανείς για την Javascript είναι ότι δεν έχει καμία απολύτως σχέση με τη γλώσσα προγραμματισμού Java πέραν του πρώτου συνθετικού του ονόματός της.
Η Javascript είναι μια απλή στη χρήση και λειτουργία της γλώσσα προγραμματισμού που έχει ως κύρια λειτουργία την αύξηση των δυνατοτήτων των web σελίδων.
Αν γνωρίζετε HTML κώδικα (που το ελπίζω γιατί διαφορετικά θα δυσκολευτείτε αρκετά σε αυτά τα μαθήματα) θα ξέρετε ότι η γλώσσα HTML είναι περιγραφική. Εξηγεί στον Web browser (Internet Explorer, Mozilla, Netscape κ.λπ.) πώς να εμφανίσει το περιεχόμενο της σελίδας, αλλά δεν μπορεί να εκτελέσει εργασίες του τύπου: «Πάρε αυτά τα στοιχεία από τον χρήστη, επεξεργάσου τα με αυτόν τον τρόπο και ανάλογα με το αποτέλεσμα της επεξεργασίας εκτέλεσε αυτή ή εκείνη την ενέργεια».
Το μεγάλο πλεονέκτημα (και πολλές φορές μπελάς) του κώδικα Javascript είναι ότι εκτελείται από τον Web Browser του επισκέπτη της σελίδας. Αυτό έχει το πλεονέκτημα της ελάφρυνσης του φόρτου του Web Server αφού οι εργασίες γίνονται όλες από το PC του χρήστη.
Δυστυχώς με τον τρόπο αυτό δεσμευόμαστε από τις δυνατότητες της έκδοσης και του είδους του Browser που διαθέτει ο χρήστης και έτσι υπάρχουν περιπτώσεις που ο κώδικάς μας δεν θα λειτουργεί σωστά. Το πρόβλημα αυτό δεν είναι πολύ διαδεδομένο, αλλά υπάρχει και καλό είναι να το γνωρίζουμε πριν κατασκευάσουμε κάτι περίπλοκο, χρησιμοποιώντας την Javascript γιατί ο κίνδυνος να απαιτηθούν σοβαρές αλλαγές μετά το τέλος της κατασκευής δεν μπορεί να αποκλειστεί.
Objects – Methods – Events
Objects (αντικείμενα) ονομάζουμε την ίδια τη σελίδα, καθώς και τα σαφώς ορισμένα μέρη της (π.χ. tables, forms, buttons, images, ή links). Κάθε object έχει ορισμένες ιδιότητες (properties). Για παράδειγμα το document.bgcolor="red" ορίζει ότι το φόντο του body της σελίδας μας θα είναι κόκκινο.
Methods ονομάζουμε τα πράγματα (εργασίες) που μπορούν να εκτελέσουν τα Objects. Για παράδειγμα ανοίγουμε ένα νέο έγγραφο με τη μέθοδο document.open(). Για να γράψετε "Hello World" σε ένα έγγραφο δίνεται τη μέθοδο: document.write("Hello World") .
Events ονομάζουμε τις ενέργειες που βάζουν σε κίνηση το μηχανισμό εκτέλεσης των Methods. Για παράδειγμα όταν κάνει κλικ ο χρήστης να τρέχει ένα υποπρόγραμμα: onClick="run_my_function()".
Το πρώτο μου πρόγραμμα Javascript
Ο κώδικας που δημιουργούμε μπορεί είτε να τοποθετηθεί μέσα στη web σελίδα, είτε να βρίσκεται σε κάποιο ξεχωριστό αρχείο και να καλείται κάθε φορά που φορτώνεται η σελίδα. Ο δεύτερος τρόπος είναι καλύτερος όταν θέλουμε να χρησιμοποιήσουμε τον ίδιο κώδικα από πολλές σελίδες. Ωστόσο τα πρώτα μας παραδείγματα θα είναι αρκετά απλά και γι’ αυτό θα προτιμήσουμε να τοποθετούμε τον κώδικα απ’ ευθείας στις σελίδες που μας ενδιαφέρουν.
Πριν ξεκινήσουμε το πρώτο μας πρόγραμμα πρέπει να γνωρίζετε ότι:
1. Η Javascript είναι case Sensitive, δηλαδή τα πεζά και τα κεφαλαία αποτελούν διαφορετικά γράμματα Για παράδειγμα τα test, Test, TEST, TesT αποτελούν γι’ αυτήν 4 διαφορετικές λέξεις. Για να αποφύγετε τα λάθη φροντίστε να αποκτήσετε τη συνήθεια της εγγραφής με ένα συγκεκριμένο τρόπο (π.χ. όλα να γράφονται με πεζά δηλαδή με μικρά γράμματα).
2. Αν και μπορείτε να γράφετε τις εντολές τη μια κάτω από την άλλη καλό είναι να υποδηλώνετε το τέλος της γραμμής με ένα ελληνικό ερωτηματικό (semicolon).
3. Αφήστε κενούς χώρους γύρω από τον κώδικά σας. Με τον τρόπο αυτό θα είναι πιο ευανάγνωστος.
Το πρώτο μας πρόγραμμα θα είναι ένα alert box που θα λέει:
Ελπίζω να σας άρεσε η σελίδα μας
Ο κώδικας ολόκληρης της σελίδα μέσα στην οποία θα το δημιουργήσουμε είναι:
<html>
<head><title>Δοκιμή Javascript</title>
<script>
alert("Ελπίζω να σας άρεσε η σελίδα μας");
</script>
</head>
<body>
Το περιεχόμενο της σελίδας
</body>
</html>
Παρατηρούμε ότι:
1. Ο Javascript κώδικάς μας αποτελείται από μια μόνο γραμμή. Η semicolon στο τέλος θα μπορούσε να απαλειφθεί αλλά τις καλές συνήθειες πρέπει να τις αρχίζουμε από νωρίς.
2. Ο κώδικας βρίσκεται μέσα στις οδηγίες (tags) <script> και </script>
3. Η οδηγία script βρίσκεται μέσα στην οδηγία <head>. Θα μπορούσε όμως να βρίσκεται και σε οποιοδήποτε άλλο σημείο της σελίδας αρκεί να είναι μέσα στο <body> (μεταξύ <body> και </body>). Ο browser διαβάζει τη σελίδα από πάνω προς τα κάτω. Έτσι στο συγκεκριμένο παράδειγμα το alert box Ελπίζω να σας άρεσε η σελίδα μας εμφανίστηκε πριν ακόμη ο χρήστης δει την ίδια τη σελίδα. Γι’ αυτό θα ήταν καλύτερο ο κώδικας να δομηθεί όπως παρακάτω:
<html>
<head><title>Δοκιμή Javascript</title>
</head>
<body>
Το περιεχόμενο της σελίδας
<script>
alert("Ελπίζω να σας άρεσε η σελίδα μας");
</script>
</body>
</html>
Έτσι, η ερώτηση του alert box έχει νόημα αφού ο χρήστης πρώτα βλέπει τη σελίδα και μετά ερωτάται αν του αρέσει.
Προβλήματα:
Αν δοκιμάσατε αυτόν τον κώδικα μόνοι σας πιθανώς να αντιμετωπίσατε τα ακόλουθα προβλήματα:
1. Ο Browser (π.χ. Internet Explorer) δεν εμφανίζει το παράθυρο
Ανάλογα με τις ρυθμίσεις του ο Browser μπορεί να μην επιτρέπει την εμφάνιση alert boxes για λόγους προστασίας από ανεπιθύμητες διαφημίσεις. Εδώ μόνο ο χρήστης μπορεί να επιτρέψει την εμφάνιση του σχετικού παραθύρου.
2. Διαχείριση Ελληνικών
Ενώ ο Internet Explorer εμφανίζει κανονικά το alert box στον Mozilla τα ελληνικά συνήθως έχουν χαθεί:
Δυστυχώς αυτό είναι ένα συχνό πρόβλημα και συχνά δεν μπορούμε να κάνουμε εμείς κάτι για να το αποφύγουμε. Τις περισσότερες φορές πάντως το πρόβλημα διορθώνεται αν δηλώσουμε την ελληνική ως γλώσσα της web σελίδας μας με κάποια οδηγία όπως <meta http-equiv=Content-Type content="text/html; charset=windows-1253">
Τα ελληνικά θα εμφανιστούν σωστά στους περισσότερους browsers αν ο κώδικας γίνει:
<html>
<meta http-equiv=Content-Type content="text/html; charset=windows-1253">
<head><title>Δοκιμή Javascript</title>
</head>
<body>
Το περιεχόμενο της σελίδας
<script>
alert("Ελπίζω να σας άρεσε η σελίδα μας");
</script>
</body>
</html>
Γενικά
<!DOCTYPE html>
<head><meta charset=utf-8><title>Εισαγωγή στην JavaScript</title></head><body>
<script language="javascript" type="text/javascript">
<!-- Βάζουμε τον JavaScript κώδικα μέσα σε commend για όσους browsers δεν τον υποστηρίζουν
/* Η JavaScript είναι case sensitive - Variables & Functions πρέπει να έχουν το ίδιο capitalization. Οι Variables πρέπει να ξεκινάνε με γράμμα, _, or $ και μετά αριθμούς. Υπάρχουν 4 Datatypes- Numbers, Strings, Booleans, Objects */
// Maximum - Minimum Numbers (Ακρίβεια μέχρι 16 digits)
document.write(Number.MAX_VALUE+"<br />");
document.write(Number.MIN_VALUE+"<br />");
// Strings = Ακολουθίες χαρακτήρεων με quotes γύρω τους.
var samp_str = "Εδώ έχουμε escaped characters \' \" \\ \t \n";
document.write(samp_str+"<br />"); // Η html αγνοεί τις αλλαγές γραμμών.
// String Functions
var first_str = "First String ";
var second_str = "and Second String";
var combined = first_str + second_str;
document.write(combined+"<br />");
document.write("Length of string: " + combined.length+"<br />");
document.write("Substring " + combined.substring(6,12) +"<br />");
// Πηγαίνετε ένα παραπάνω απ' ό,τι χρειάζεστε.
document.write("Last character " + combined.charAt(combined.length-1)+"<br />");
document.write("Index of T " + combined.indexOf('t') +"<br />");
// Αυτόματο Variable Conversion
var str_var = "5";
var num_var = 10;
var total = num_var + str_var; // Το number γίνεται string
var mult_total = num_var * str_var; // Το number γίνεται string
document.write("5 + 10 = " + total +"<br />");
document.write("5 * 10 = " + mult_total +"<br />");
// Force Datatype Conversion
total = num_var + Number(str_var);
document.write("5 + 10 = " + total +"<br />");
var num_var2 = String(num_var);
document.write(num_var + num_var +"<br />");
document.write(num_var + num_var2 +"<br />");
// Μετατροπή Float σε Fixed Length String
var float_var = 3.141592653589793238;
var float_str = float_var.toFixed(5);
document.write("Shortened PI " + float_str +"<br />");
document.write("Integer PI " + parseInt(float_var) +"<br />");
// Βρες το Datatype μιας Variable
document.write("Datatype of float_var " + typeof(float_var) +"<br />");
document.write("Datatype of float_str " + typeof(float_str) +"<br />");
// Boolean Variables είναι false (0 or NaN) ή true (οτιδήποτε άλλο)
bool_var = Boolean(23);
document.write("Boolean of 23 " + bool_var +"<br />");
-->
</script>
<noscript>
<h3>Χρειάζεστε JavaScript</h3>
</noscript></body></html>
Τοποθέτηση του κώδικα σε ξεχωριστό αρχείο
Για να αποφύγουμε την επανάληψη του ίδιου κώδικα σε πολλές σελίδες (κάτι που καθιστά δύσκολη την τροποποίησή του στο μέλλον) μπορούμε να τον τοποθετήσουμε σε ένα ξεχωριστό αρχείο. Στο προηγούμενο παράδειγμα ο κώδικας ήταν:
alert("Ελπίζω να σας άρεσε η σελίδα μας");
Δημιουργούμε λοιπόν ένα ξεχωριστό αρχείο που περιέχει μόνο αυτή τη γραμμή και ονομάζεται kati.js. Φυσικά αντί για kati εσείς μπορείτε να του δώσετε όποιο όνομα θέλετε. Η επέκταση όμως θα πρέπει να είναι πάντοτε .js
Σε αυτή την περίπτωση η σελίδα μας γίνεται:
<html>
<meta http-equiv=Content-Type content="text/html; charset=windows-1253">
<head><title>Δοκιμή Javascript</title>
</head>
<body>
Το περιεχόμενο της σελίδας
<script src="kati.js"></script>
</body>
</html>
Η αλλαγή εδώ βρίσκεται στην οδηγία script που τώρα έγινε:
<script src="kati.js"></script>
Εννοείται ότι σε αυτή την περίπτωση το αρχείο kati.js βρίσκεται στον ίδιο φάκελο με τη web σελίδα. Αν βρισκόταν αλλού θα έπρεπε να δηλωθεί η πλήρης διαδρομή για το αρχείο για παράδειγμα: <script src="fakelos/ypofakelos/kati.js"></script>.
Μαθηματικές πράξεις
Στο παράδειγμα που ακολουθεί διαδοχικά pop ups μας δίνουν το αποτέλεσμα κάποιων εργασιών.
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE>Δοκιμές</TITLE></HEAD></BODY>
<SCRIPT type="text/javascript">
var numsums = 10 + 2;
alert("10 + 2 is " + numsums)
var x = 10
alert("ten is " + x)
var y = x * 2
alert("10 X 2 = " + y)
var z = "Hello " + "Good Bye"
alert(z)
divide = 10 / 2
alert (divide)
var subtract = 10 - 2;
alert (subtract)
</SCRIPT><h2>Παραδείγματα μαθηματικών πράξεων</h2></BODY></HTML>
To script λειτουργεί πολύ απλά και ο τρόπος εκτέλεσης των μαθηματικών πράξεων και της ένωσης κειμένων (concatenation) είναι προφανής.
Χρησιμοποιώντας τον τελεστή var δηλώνουμε μεταβλητές (π.χ. numsums, x, subtract). Αν και η δημιουργία της μεταβλητής divide μας δείχνει πως ο var δεν είναι υποχρεωτικός, καλό είναι για λόγους συγκροτημένης δομής του προγράμματος.
Τέλος παρατηρούμε ότι το πρόγραμμα με μια εξαίρεση δεν έχει ελληνικά ερωτηματικά (semicolon) στο τέλος κάθε γραμμής. Αν και είναι προαιρετικά βοηθούν στην καλύτερη ανάγνωση του κώδικα και καλό είναι να χρησιμοποιούνται.
Μαθηματικοί Τελεστές
+ Addition x=y+2 7 5
- Subtraction x=y-2 3 5
* Multiplication x=y*2 10 5
/ Division x=y/2 2.5 5
% Modulus (division remainder) x=y%2 1 5
++ Increment x=++y 6 6
x=y++ 5 6
-- Decrement x=--y 4 4
x=y-- 5 4
Απόδοση τιμών (Assignment Operators)
Operator Παράδειγμαe Ίδιο με: Αποτέλεσμα
= x=y Δεν υπάρχει x=5
+= x+=y x=x+y x=15
-= x-=y x=x-y x=5
*= x*=y x=x*y x=50
/= x/=y x=x/y x=2
%= x%=y x=x%y x=0
Τελεστές Σύγκρισης
Operator Περιγραφή Σύγκριση (αν x=5) Αποτέλεσμα
== is equal to x==8 false
x==5 true
=== is exactly equal to (value and type) x==="5" false
x===5 true
!= is not equal x!=8 true
!== is not equal (neither value nor type) x!=="5" true
x!==5 false
> is greater than x>8 false
< is less than x<8 true
>= is greater than or equal to x>=8 false
<= is less than or equal to x<=8 true
Λογικοί Τελεστές
Operator Περιγραφή Παράδειγμα
&& and (x < 10 && y > 1) is true
|| or (x==5 || y==5) is false
! not !(x==y) is true
Javascript Debugging
Στο προηγούμενο παράδειγμα αντικαθιστούμε τα alert με console.info και ανοίγουμε Firebug – Κονσόλα – Όλα (κάντε ενεργοποίηση αν το ζητήσει).
Τώρα μπορούμε να βλέπουμε μηνύματα από το πρόγραμμα στα σημεία που επιθυμούμε.
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE>Δοκιμές</TITLE></HEAD></BODY>
<SCRIPT type="text/javascript">
var numsums = 10 + 2;
console.info("X=" + numsums); //Firebug Κονσόλα
var x = 10
console.info("ten=" + x);
var y = x * 2
console.info("10 X 2 = " + y)
var z = "Hello " + "Good Bye"
console.info(z)
divide = 10 / 2
console.info(divide)
var subtract = 10 - 2;
console.info(subtract)
</SCRIPT><h2>Παραδείγματα μαθηματικών πράξεων</h2></BODY></HTML>
Επίσης από το σημείο του κώδικα και μετά που θέλετε να ελέγξετε μπορείτε να γράψετε απλώς debugger; (σκέτο χωρίς κάτι άλλο) Για να το δούμε ανοίγουμε Firebug – Σενάριο Ενεργειών (κάντε ενεργοποίηση ή ανανέωση αν το ζητήσει). Μετά με F11 μπορείτε να κινείστε βήμα βήμα στο πρόγραμμά σας.
Javascript Functions
Μια function είναι ένα block κώδικα (μια σειρά εντολών) που θα εκτελεστεί όταν ζητηθεί.
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<button onclick="myFunction('Μαρία Παπαδοπούλου','καθητήτρια HTML')">Πάτησέ με</button>
<script>
function myFunction(name,job)
{
alert("Καλώς Όρισες " + name + ", που είσαι " + job);
}
</script></body></html>
Η function μπορεί να πάρει εξωτερικές τιμές και να τις επεξεργαστεί.
Functions που μεταφέρουν δεδομένα η μια στην άλλη.
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<button onclick="messagefunction()">Πάτησέ με</button>
<script>
var name = 'Μαρία Παπαδοπούλου';
var job = 'καθητήτρια HTML';
function messagefunction (){
var thismessage= myFunction(name,job);
alert(thismessage);
}
function myFunction(localname,localjob){
return("Καλώς Όρισες " + localname + ", που είσαι " + localjob);
}
</script></body></html>
Τα δεδομένα μεταφέρονται με την return.
Αν δηλώσουμε return χωρίς κάποια τιμή επιστροφής τότε αυτό σημαίνει πως θέλουμε να τελειώσει η εκτέλεση της fuction κάτι που γίνεται στην ίδια γραμμή (ό,τι κώδικας υπάρχει παρακάτω δεν εκτελείται).
Callbacks
Η callback στην πραγματικότητα παίρνει μια τιμή και τη δίνει για εκτέλεση. Το πλεονέκτημα της χρήσης της είναι ο ασύγχρονος χαρακτήρας της που επιτρέπει να τρέχουν και άλλα πράγματα ταυτόχρονα.
Η javascript μπορεί να χρησιμοποιεί αυτή τη σύνταξη διότι θεωρεί τις functions ως objects και μπορεί να τις δώσει από δω και εκεί για εκτέλεση.
<html><meta charset="utf-8"><body>
<script>
// Ορίζουμε τη function που έχει callback argument
function some_function(arg1, arg2, callback) {
/* θα φτιάξουμε έναν τυχαίο αριθμό μεταξύ του arg1 και του arg2 */
var my_number = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
/* Η Math.ceil() στρογγυλοποιεί ένα νούμερο στον ανώτερο ακέραιο. π.χ. Math.ceil(1.4) = 2*/
/* Τώρα καλούμε την callback για να δώσουμε το αποτέλεσμα */
callback(my_number);
}
// Καλούμε τη function που ορίσαμε παραπάνω.
some_function(5, 15, function(num) {
/* Το τρίτο argument είναι μια ανώνυμη function που θα τρέξει όταν κληθεί η callback */
alert("callback called! " + num);
});
</script>
</body></html>
For loop
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
for (var i=0; i<5; i++)
{
x= "The number is " + i + "<br>";
document.write(x + "<br>");
}
</script></body></html>
While loop
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
var i = '0';
while (i<5)
{
x= "The number is " + i + "<br>";
document.write(x + "<br>");
i++;
}
</script></body></html>
Do While
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
var i = '0';
do
{
x= "The number is " + i + "<br>";
document.write(x + "<br>");
i++;
}
while (i<5);
</script></body></html>
Break Loop
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
for (i=0;i<10;i++)
{
if (i==3)
{
break;
}
x= "The number is " + i + "<br>";
document.write(x + "<br>");
}
</script></body></html>
Το loop σταματάει στο σημείο που έχουμε ορίσει.
Continue Loop
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
for (i=0;i<10;i++)
{
if (i==3) continue;
x= "The number is " + i + "<br>";
document.write(x + "<br>");
}
</script></body></html>
Το loop «πηδάει» ένα iteration και συνεχίζει μέχρι το σημείο που έχουμε ορίσει.
Δημιουργία ενός Message Box
Κατασκευάζουμε ένα input box που όταν κάνουμε κλικ επάνω του μας δίνει το input που δώσαμε.
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<SCRIPT LANGUAGE="JavaScript">
<!-- Beginning of JavaScript -
function MsgBox (textstring) {
alert (textstring) }
// - End of JavaScript - -->
</SCRIPT></HEAD><BODY>
<FORM><INPUT NAME="text1" TYPE=Text>
<INPUT NAME="submit" TYPE=Button VALUE="Show Me" onClick="MsgBox(form.text1.value)">
</FORM></BODY></HTML>
Επεξήγηση του κώδικα:
Σχόλια: Οποιαδήποτε γραμμή ξεκινάει από // μέσα στην οδηγία <Script> δεν εκτελείται. Το // υποδηλώνει πως σε αυτή τη γραμμή ο προγραμματιστής έγραψε παρατηρήσεις (κείμενο) για χρήση δική του ή άλλων.
Θέση του script: Αν και θεωρητικά μπορεί να τοποθετηθεί οπουδήποτε στη σελίδα συνήθως προτιμούμε τον HEADER όπου αυτό είναι δυνατό:
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
< !-- Beginning of JavaScript -
(Εδώ μπαίνουν οι JavaScript functions)
// - End of JavaScript - -->
</SCRIPT>
</HEAD>
Σύνταξη της function:
Function = υποπρόγραμμα (σύνολο εντολών – εργασιών)
MyFunction = το όνομα της function
Variable = μεταβλητή (μια τιμή που θα επεξεργαστούμε)
function MyFunction (variable) {
εργασίες που θα εκτελεστούν σε αυτή την variable
}
Η επεξήγηση της:
function MsgBox (textstring) {
alert (textstring)
}
είναι:
MsgBox = το όνομα της function.
Textstring = το όνομα της μεταβλητής
alert (textstring) = Η εντολή alert θα εφαρμοστεί πάνω στη μεταβλητή textstring
Περιεχόμενο της variable:
Η μεταβλητή textstring πρέπει να έχει μια τιμή. Αυτή θα μπορούσε να οριστεί απευθείας από τον κώδικα. Για παράδειγμα: textstring = “This is a text string” (προσέξτε ότι το κείμενο βρίσκεται μέσα σε εισαγωγικά).
Εκτέλεση της εργασίας:
Από τη standard HTML αναγνωρίζουμε τις γραμμές 1,2,4.
1. <FORM>
2. <INPUT NAME="text1" TYPE=Text>
3. <INPUT NAME="submit" TYPE=Button VALUE="Show Me" onClick="MsgBox(form.text1.value)">
4. </FORM>
Το μυστικό της γραμμής 3 είναι το: onClick="MsgBox(form.text1.value)". Τα υπόλοιπα αποτελούν standard HTML. To onClick λέει στον browser πως όταν ο χρήστης κάνει κλικ θα πρέπει να εκτελέσει την function MsgBox.
Το form.text1.value σημαίνει πως ο browser θα πρέπει να πάρει από τη φόρμα το object (αντικείμενο) που ονομάζεται text1 και να δώσει στην MsgBox το περιεχόμενό του (δηλαδή αυτό που έγραψε ο χρήστης).
Για να γίνει πιο εμφανής η διαφορά, αν θέλαμε να μάθουμε το μήκος του κειμένου που έγραψε ο χρήστης θα δίναμε: form.text1.length.
Παραπομπή με message box
Με τον ακόλουθο απλό κώδικα μόλις ο χρήστης κάνει κλικ στην παραπομπή θα εμφανιστεί ένα μήνυμα. Όταν κάνει κλικ στο ΟΚ του μηνύματος τότε θα μεταφερθεί στη σχετική σελίδα.
<a href="http://www.eexi.gr" onClick="alert('Hi'); return true;">Click Me</a>
Αν το return ήταν false αντί για true η ενέργεια της παραπομπής δεν θα εκτελούνταν (όλα θα τελείωναν στο οκ).
Αλλαγή του φόντου μιας σελίδας
Στόχος αυτού του παραδείγματος είναι καταλάβουμε την έννοια της μεταβλητής και τις διαφορετικές τιμές που μπορεί να λάβει. Για τον λόγο αυτό θα δημιουργήσουμε μια σελίδα με 4 κουμπιά. Κάθε φορά που θα πατάμε ένα κουμπί θα αλλάζει το φόντο της σελίδας.
Ο κώδικας είναι:
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<SCRIPT LANGUAGE="JavaScript">
<!-- Beginning of JavaScript -
function changecolor(code) {
document.bgColor=code
}
// - End of JavaScript - -->
</SCRIPT>
</HEAD>
<BODY>
<form>
<input type="button" name="Button1" value="RED" onclick="changecolor('red')">
<input type="button" name="Button2" value="GREEN" onclick="changecolor('green')">
<input type="button" name="Button3" value="BLUE" onclick="changecolor('blue')">
<input type="button" name="Button4" value="WHITE" onclick="changecolor('white')">
</form>
</BODY></HTML>
Εδώ έχουμε μόνο μια συνάρτηση που ονομάζεται changecolor. Η variable ονομάζεται code και της δίνουμε μια τιμή με το onclick="changecolor('κάποιο χρώμα')" δηλαδή όταν ο χρήστης κάνει κλικ θεώρησε ότι code = το χρώμα τάδε και εκτέλεσε την function changecolor(code)
IF – ELSE
Σε αυτό το παράδειγμα θα δούμε με ποιο τρόπο μπορούμε να δώσουμε στην Javascript όρους λειτουργίας της μορφής: Αν συμβαίνει αυτό κάνε το Α, διαφορετικά κάνε το Β.
Για να γίνει αυτό θα δημιουργήσουμε μια σελίδα με password. Όταν ο χρήστης δώσει το σωστό συνθηματικό τότε θα φορτώνεται μια άλλα σελίδα.
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE> If-then statements</TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!-- Beginning of JavaScript -
function password() {
Ret = prompt('Type the word eexi',"");
if(Ret=="eexi") {
location = 'reply.htm';
} else {
alert("Please try again")
}
}
// - End of JavaScript - -->
</SCRIPT>
</HEAD>
<BODY>
<A HREF="javascript:password()"><IMG SRC="pict1.gif" NAME="pic1" ALT="about us!" BORDER="0" align="left"></A>
<H3>Click to enter a password protected document</H3> </BODY></HTML>
Το πρώτο κομμάτι κώδικα που πρέπει να δούμε είναι το:
Ret = prompt('Type the word eexi',"");
Αυτό λέει στον browser να εμφανίσει το prompt με αυτές τις ιδιότητες όταν ο χρήστης κάνει κλικ στην παραπομπή <A HREF="javascript:password()"> που καλεί την function με το όνομα password. Η παραπομπή γίνεται από γραφικό, αλλά θα μπορούσε κάλλιστα να είναι μια απλή παραπομπή κειμένου.
Ενδιαφέρον είναι να παρατηρήσουμε τα εισαγωγικά που ακολουθούν το 'Type the word eexi. Σε αυτά μπορούμε να βάλουμε ένα default password, που θα εμφανίζεται αυτόματα στο prompt π.χ. Ret = prompt('Type the word eexi',"eexi");
if(Ret=="eexi") {
location = 'reply.htm';
} else {
alert("Please try again")
}
Εδώ λέμε στην function πως αν η μεταβλητή Ret έχει την τιμή eexi τότε θα εκτελέσει μια ενέργεια (προσέξτε το διπλό = που σημαίνει ίδιο). Διαφορετικά θα εκτελέσει μια άλλη.
Στην περίπτωση που Ret == eexi φορτώνουμε μια νέα web σελίδα. Διαφορετικά εμφανίζουμε ένα μήνυμα στο alert box.
Εκτός από τον τελεστή == πολύ δημοφιλείς είναι και οι μαθηματικοί τελεστές. Για παράδειγμα μπορούμε να έχουμε μια φόρμα όπου ο χρήστης δίνει την ηλικία του. Αν ονομάζουμε το input box age τότε με ageinput=form.age.value παίρνουμε την ηλικία του χρήστη και με ένα if (age>=18) βγάζουμε ένα μήνυμα σχετικό με την ηλικά του ενήλικα χρήστη.
If – Else if
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE> If - else if</TITLE>
<script type="text/javascript">
var visitor = "principal";
if(visitor == "teacher"){
document.write("My dog ate my homework...");
}else if(visitor == "principal"){
document.write("What stink bombs?");
} else {
document.write("How do you do?");
}
</script></HEAD><BODY></body></html>
Javascript getElementById
Για να λάβουμε το περιεχόμενο ενός input δεδομένων σε σελίδα HTML χρησιμοποιούμε την μέθοδο getElementById η οποία διαβάζει το περιεχόμενο του ενός id (άρα προφανώς χρειάζεται να δηλώσουμε id στο input για να τη χρησιμοποιήσουμε).
<html>
<script type="text/javascript">
function notEmpty(){
var myTextField = document.getElementById('myText');
if(myTextField.value != "")
alert("You entered: " + myTextField.value)
else
alert("Would you please enter some text?")
}
</script>
<input type='text' id='myText' />
<input type='button' onclick='notEmpty()' value='Form Checker' />
</html>
Αλλαγή της value ενός button
Αν έχουμε:
<input type="button" id="run" value="Run Animation">
Μπορούμε να το αλλάξουμε με το:
document.getElementById("run").value="Step 1";
Javascript innerHTML
Η μέθοδος innerHTML χρησιμοποιείται στην περίπτωση που θέλουμε να τροποποιήσουμε ένα μέρος της web σελίδας μας. Όπως και στην getElementById χρειάζεται να δηλώσουμε id στο input για να τη χρησιμοποιήσουμε.
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
function changeText(){
document.getElementById('boldStuff').innerHTML = 'Γιώργο';
}
</script>
<p>Welcome to the site <b id='boldStuff'>φίλε</b> </p>
<input type='button' onclick='changeText()' value='Change Text'/>
</html>
document.createElement
<!DOCTYPE html>
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE>document.createElement</TITLE></head>
<body>
<p>Κάντε Click στο κουμπί για να εμφανιστεί ένα δεύτερο με κείμενο.</p>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction()
{
var btn=document.createElement("BUTTON");
var t=document.createTextNode("ΕΔΩ ΕΙΜΑΙ");
btn.appendChild(t);
document.body.appendChild(btn);
};
</script></body></html>
Η createTextNode προσθέτει κείμενο στο κουμπί μέσω της btn.appendChild(t);
.
Form Validation
Η Javascript είναι ιδανική για τον έλεγχο των στοιχείων που μας δίνει όποιος χρήστης συμπληρώνει τη φόρμα μας. Το πλεονέκτημα του ελέγχου του form input με javascript είναι πως δεν χρειάζεται να πειράξουμε το action script που κατά πάσα πιθανότητα δεν έχει φτιαχτεί από εμάς και συνεπώς είναι δυσκολότερο να τροποποιηθεί.
Έλεγχος πως είναι πεδίο συμπληρώθηκε:
Ο κώδικας για μια αυτόνομη σελίδα είναι:
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE>Δοκιμές </TITLE>
<script type='text/javascript'>
function isEmpty(elem, helperMsg){
if(elem.value.length == 0){
alert(helperMsg);
elem.focus();
return true;
}
return false;
}
</script></head>
<body><form>
Required Field: <input type='text' id='req1'/>
<input type='button'
onclick="isEmpty(document.getElementById('req1'), 'Please Enter a Value')"
value='Check Field' />
</form></BODY></HTML>
Διαβάζοντας από το τέλος βλέπουμε πως όταν κάνουμε κλικ (onclick) καλείται η function isEmpty και τις δίδονται δύο μεταβλητές. Η document.getElementById('req1'), δηλαδή το περιεχόμενο του input box που έχει name req1 και το μήνυμα «Please Enter a Value».
Βλέποντας τώρα ψηλότερα στην function isEmpty ελέγχεται το μέγεθος του κειμένου που υπήρχε στο req1 (είναι η variable elem και η εργασία απεικονίζεται ως: elem.value.length). Αν πράγματι δεν έχει μήκος τότε εμφανίζεται το alert μήνυμα (που φυλάσσεται στη μεταβλητή helperMsg).
Το elem.focus() μεταφέρει τον δρομέα μέσα στο input πεδίο ώστε ο χρήστης να μη χρειάζεται να μετακινηθεί στο πεδίο για να πληκτρολογήσει το input του.
Το return true; δηλώνει πως μετά το κλικ στο ΟΚ του χρήστη θα εκτελεστεί ο υπόλοιπος κώδικας (ο δρομέας θα πάει στο input πεδίο που δεν έχει συμπληρωθεί).
Έλεγχος πως ένα πεδίο περιέχει μόνο αριθμούς
Χρήσιμο σε περίπτωση που θέλουμε να εξασφαλίσουμε πως ο χρήστης έδωσε με τον σωστό τρόπο έναν ταχυδρομικό κώδικα, έναν αριθμό πιστωτικής κάρτας ή ένα τηλέφωνο.
Ο κώδικας είναι:
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE>Δοκιμές</TITLE>
<script type='text/javascript'>
function isNumeric(elem, helperMsg){
var numericExpression = /^[0-9]+$/;
if(elem.value.match(numericExpression)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
</script></HEAD><BODY>
<form>
Numbers Only: <input type='text' id='numbers'/>
<input type='button'
onclick="isNumeric(document.getElementById('numbers'), 'Numbers Only Please')"
value='Check Field' />
</form></BODY></HTML>
Η φόρμα είναι δομημένη ακριβώς όπως και στο προηγούμενο παράδειγμα. Αλλάζει μόνο το name που τώρα είναι numbers (φυσικά θα μπορούσε να είναι οτιδήποτε) και φυσικά το μήνυμα προς τον χρήστη.
Η function παίρνει το input του χρήστη και το μήνυμα λάθους. Δημιουργεί τη νέα μεταβλητή numericExpression που θα χρησιμοποιηθεί για σύγκριση με την τιμή που έδωσε στο input ο χρήστης. Το var δηλώνει τη δημιουργία της (είναι σαν να λέμε στη javascript δημιούργησε την numericExpression). Η νέα μεταβλητή από την αρχή (^) μέχρι το τέλος ($) της πρέπει να περιέχει μόνο αριθμούς ([0-9]) ανεξάρτητα από το πόσοι είναι αυτοί (+). Αυτός ο τρόπος σύγκρισης strings (ακολουθίες χαρακτήρων) ονομάζεται Regular Expression.
var numericExpression = /^[0-9]+$/;
Αν τώρα οι 2 μεταβλητές ταιριάζουν: if(elem.value.match(numericExpression)) τότε είμαστε οκ. Διαφορετικά εμφανίζεται το μήνυμα λάθους.
Έλεγχος πως ένα πεδίο περιέχει μόνο γράμματα
Λειτουργεί με ακριβώς τον ίδιο τρόπο με τον έλεγχο για αριθμούς. Η μόνη διαφορά βρίσκεται στη Regular Expression που τώρα είναι /^[a-zA-Z]+$/ δηλαδή αντί για τους αριθμούς [0-9] τώρα έχουμε όλα τα πεζά (μικρά) και κεφαλαία γράμματα από το πρώτο έως το τελευταίο δηλαδή: [a-zA-Z] Δυστυχώς αυτή η Regular Expression αναφέρεται μόνο σε λατινικούς χαρακτήρες.
Για έλεγχο ελληνικών δείτε το ακόλουθο παράδειγμα:
<HTML><HEAD><meta http-equiv=Content-Type content="text/html; charset=utf-8"><TITLE>Δοκιμές</TITLE>
<script type='text/javascript'>
function isNumeric(elem, helperMsg){
var numericExpression = /^[a-zA-Zα-ωΑ-ΩάέόώήίύϋϊΆΈΌΏΉΊΎΫ]+$/ ;
if(elem.value.match(numericExpression)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
</script></HEAD><BODY>
<form>
Μόνο γράμματα: <input type='text' id='numbers'/>
<input type='button'
onclick="isNumeric(document.getElementById('numbers'), 'Numbers Only Please')"
value='Check Field' />
</form></BODY></HTML>
Περιορισμός του μήκους ενός πεδίου
Αν δεν θέλουμε το μήκος του πεδίου να ξεπερνά ένα συγκεκριμένο μέγεθος (π.χ. για να μη μας δώσουν ταχυδρομικό κώδικα με περισσότερα από 5 νούμερα) χρησιμοποιούμε τον ακόλουθο κώδικα:
<HTML><HEAD><TITLE>Δοκιμές</TITLE>><meta http-equiv=Content-Type content="text/html; charset=utf-8"></HEAD></BODY>
<script type='text/javascript'>
function lengthRestriction(elem, min, max){
var uInput = elem.value;
if(uInput.length >= min && uInput.length <= max){
return true;
}else{
alert("Please enter between " +min+ " and " +max+ " characters");
elem.focus();
return false;
}
}
</script>
<form>
Username(6-8 characters): <input type='text' id='restrict'/>
<input type='button'
onclick="lengthRestriction(document.getElementById('restrict'), 6, 8)"
value='Check Field' />
</form></BODY></HTML>
Εδώ η function ονομάζεται lengthRestriction και της δίνουμε 3 μεταβλητές (variables). Το input της φόρμας, τον μέγιστο και τον ελάχιστο αριθμό χαρακτήρων.
Εδώ η if έχει δύο μέρη. Ελέγχει αν η μεταβλητή uInput που περιέχει ό,τι πληκτρολόγησε ο χρήστης έχει μέγεθος >= και ταυτόχρονα (&&) =< από τη μέγιστη και την ελάχιστη τιμή.
Προσέξτε ότι:
1. Η if θα μπορούσε να διατυπωθεί και ως: if(elem.value.length >= min && elem.value.length <= max). Δημιουργήσαμε την uInput για να βλέπουμε πιο καθαρά τι κάνουμε.
2. Για να εμφανίσουμε σε ένα text box τα δεδομένα (περιεχόμενο) μιας μεταβλητής τα περικλείουμε με +.
Υποχρεωτική επιλογή από select
Για να υποχρεώσουμε έναν χρήστη να επιλέξει οπωσδήποτε μια τιμή από ένα πεδίο select θα χρησιμοποιήσουμε κάτι αντίστοιχο με το ακόλουθο παράδειγμα:
<HTML><HEAD><TITLE>Δοκιμές</TITLE>><meta http-equiv=Content-Type content="text/html; charset=utf-8"></HEAD><BODY>
<script type='text/javascript'>
function madeSelection(elem, helperMsg){
if(elem.value == "Please Choose"){
alert(helperMsg);
elem.focus();
return false;
}else{
return true;
}
}
</script>
<form>
Selection: <select id='selection'>
<option>Please Choose</option>
<option>Αθήνα</option>
<option>Θεσσαλονίκη</option>
<option>Πάτρα</option>
</select>
<input type='button'
onclick="madeSelection(document.getElementById('selection'), 'Please Choose Something')"
value='Check Field' />
</form></BODY></HTML>
Εδώ η λειτουργία είναι πολύ απλή. Αν το input έχει το περιεχόμενο Please Choose τότε ο χρήστης δεν επέλεξε κάτι και τον καλούμε να το πράξει.
Έλεγχος ορθότητας μιας email διεύθυνσης
Για να σιγουρευτούμε ότι οι χρήστες μας έχουν δώσει μια σωστή email διεύθυνση θα χρησιμοποιήσουμε τον ακόλουθο κώδικα μέσω του οποίου ελέγχουμε ότι μας πληκτρολόγησαν κάτι που περιέχει το @, κάτι αριστερά του, κάτι δεξιά του, μια τελεία, ένα top level domain μετά την τελεία.
Προσοχή: Με τον κώδικα αυτό επιβεβαιώνουμε πως ο χρήσης πληκτρολόγησε κάτι που μοιάζει με email διεύθυνση. Δεν ελέγχουμε αν η συγκεκριμένη διεύθυνση όντως υπάρχει.
Ο κώδικας είναι:
<HTML><HEAD><TITLE>Δοκιμές</TITLE></HEAD>><meta http-equiv=Content-Type content="text/html; charset=utf-8"><BODY>
<script TYPE="text/javascript">
function emailValidator1(elem, helperMsg){
var emailExp = /^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-Z0-9]{2,4}$/;
if(elem.value.match(emailExp)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
</script>
<form>
Email: <INPUT TYPE="text" ID="emailer"/>
<INPUT TYPE="button" ONCLICK="emailValidator1(document.getElementById('emailer'), 'Not a Valid Email')" VALUE="Check Field"/>
</form></BODY></HTML>
Έλεγχος περισσότερων από ένα πεδίων ταυτόχρονα
Μέχρι τώρα είδαμε πώς μπορούμε να ελέγξουμε ένα πεδίο σε κάθε φόρμα. Ωστόσο, συνήθως επιθυμούμε να ελέγχουμε περισσότερα από ένα πεδία στην ίδια φόρμα.
Θα χρησιμοποιήσουμε τη function formValidator μέσω της οποία θα γίνουν όλοι οι έλεγχοι.
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type='text/javascript'>
function formValidator(){
// Make quick references to our fields
var firstname = document.getElementById('firstname');
var addr = document.getElementById('addr');
var zip = document.getElementById('zip');
var state = document.getElementById('state');
var username = document.getElementById('username');
var email = document.getElementById('email');
// Check each input in the order that it appears in the form!
if(isAlphabet(firstname, "Please enter only letters for your name")){
if(isAlphanumeric(addr, "Numbers and Letters Only for Address")){
if(isNumeric(zip, "Please enter a valid zip code")){
if(madeSelection(state, "Please Choose a State")){
if(lengthRestriction(username, 6, 8)){
if(emailValidator(email, "Please enter a valid email address")){
return true;
}
}
}
}
}
}
return false;
}
function isEmpty(elem, helperMsg){
if(elem.value.length == 0){
alert(helperMsg);
elem.focus(); // set the focus to this input
return true;
}
return false;
}
function isNumeric(elem, helperMsg){
var numericExpression = /^[0-9]+$/;
if(elem.value.match(numericExpression)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
function isAlphabet(elem, helperMsg){
var alphaExp = /^[a-zA-Z]+$/;
if(elem.value.match(alphaExp)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
function isAlphanumeric(elem, helperMsg){
var alphaExp = /^[0-9a-zA-Z]+$/;
if(elem.value.match(alphaExp)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
function lengthRestriction(elem, min, max){
var uInput = elem.value;
if(uInput.length >= min && uInput.length <= max){
return true;
}else{
alert("Please enter between " +min+ " and " +max+ " characters");
elem.focus();
return false;
}
}
function madeSelection(elem, helperMsg){
if(elem.value == "Please Choose"){
alert(helperMsg);
elem.focus();
return false;
}else{
return true;
}
}
function emailValidator(elem, helperMsg){
var emailExp = /^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/;
if(elem.value.match(emailExp)){
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
</script></head><body>
<form onsubmit='return formValidator()' >
First Name: <input type='text' id='firstname' /><br />
Address: <input type='text' id='addr' /><br />
Zip Code: <input type='text' id='zip' /><br />
State: <select id='state'>
<option>Please Choose</option>
<option>AL</option>
<option>CA</option>
<option>TX</option>
<option>WI</option>
</select><br />
Username(6-8 characters): <input type='text' id='username' /><br />
Email: <input type='text' id='email' /><br />
<input type='submit' value='Check Form' />
</form></body></html>
Javascript Arrays
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<script>
var i;
var mycars = new Array();
mycars[0] = "Saab";
mycars[1] = "Volvo";
mycars[2] = "BMW";
for (i=0;i<mycars.length;i++)
{
document.write(mycars[i] + "<br>");
}
</script></body></html>
Array Concatenation
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button για να ενωθούν τρία arrays.</p>
<button onclick="myFunction()">Ένωση</button>
<script>
function myFunction()
{
var hege = ["Γιώργος", "Μαρία"];
var stale = ["Βαγγέλης", "Τασία"];
var kai = ["Στέφανος","Θανάσης"];
var children = hege.concat(stale,kai);
var x=document.getElementById("demo");
x.innerHTML=children;
}
</script></body></html>
Join
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button για να ενωθούν τα arrays.</p>
<button onclick="myFunction()">Ένωση</button>
<script>
function myFunction()
{
var hege = ["Γιώργος", "Μαρία"];
var x=document.getElementById("demo");
x.innerHTML=hege.join();
}
</script></body></html>
Σύνταξη: array.join(separator)
Αν δεν οριστεί separator θα χρησιμοποιηθεί το κόμμα.
x.innerHTML=hege.join('#'); θα έχει ως separator το #
Push, προσθήκη στο τέλος
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα"];
family.push("Μάριος")
var x=document.getElementById("demo");
x.innerHTML=family.join();
}
</script></body></html>
unshift, προσθήκη στην αρχή
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα"];
family.unshift("Μάριος")
var x=document.getElementById("demo");
x.innerHTML=family.join();
}
</script></body></html>
Δεν λειτουργεί στον Internet Explorer 8
Pop, Αφαίρεση του τελευταίου element
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα"];
family.pop()
var x=document.getElementById("demo");
x.innerHTML=family.join();
}
</script></body></html>
shift, αφαίρεση του πρώτου element
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα"];
family.shift()
var x=document.getElementById("demo");
x.innerHTML=family.join();
}
</script></body></html>
reverse, αντιστροφή της σειράς των elements
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα"];
family.reverse()
var x=document.getElementById("demo");
x.innerHTML=family.join();
}
</script></body></html>
slice, λήψη τμημάτων της array
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα", "Μάριος", "Αθηνά"];
var paidia = family.slice(1,3);
var x=document.getElementById("demo");
x.innerHTML=paidia.join();
}
</script></body></html>
var paidia = family.slice(1,3);
φέρνει το 1 και το 2 αλλά όχι το 3.
Σύνταξη: array.slice(start, end)
Start = από αυτό το element και μετά (0 = 1). End = μέχρι ποιο element θα είναι η φέτα της array (προεραιτικό)
var paidia = family.slice(1); θα φέρει: Ματίνα,Μάριος,Αθηνά
var paidia = family.slice(-3,-1); θα μας φέρει τα elements από το τέλος, δηλαδή τα Ματίνα,Μάριος (όταν μετράμε ανάποδα από το τέλος ξεκινάμε από το 1 όχι από το 0).
Αλφαβητική αύξουσα ταξινόμηση
var family = ["Γιώργος", "Ματίνα", "Μάριος", "Αθηνά"];
family.sort();
var x=document.getElementById("demo");
x.innerHTML=family;
Splice, προσθήκη ή αφαίρεση elements σε συγκεκριμένο σημείο.
var family = ["Γιώργος", "Ματίνα", "Μάριος", "Αθηνά"];
family.splice(2,0,"Στέφανος","Θοδωρής");
var x=document.getElementById("demo");
x.innerHTML=family;
Το πρώτο νούμερο είναι ακέραιος και αναφέρει τη θέση όπου θα μπουν ή θα αφαιρεθούν elements. Το δεύτερο είναι ακέραιος και αναφέρει πόσα θα αφαιρεθούν. Ακολουθούν τα elements προς πρόσθεση.
family.splice(2,2,"Στέφανος","Θοδωρής");
Αφαιρεί τα δύο τελευταία elements και τα αντικαθιστά με καινούρια.
family.splice(2,1,"Στέφανος","Θοδωρής");
Αφαιρεί το Μάριος και προσθέτει δύο νέα στη θέση του.
Αριθμητική ταξινόμηση (αύξουσα)
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});
var x=document.getElementById("demo");
x.innerHTML=points;
Αριθμητική ταξινόμηση (φθίνουσα)
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return b-a});
var x=document.getElementById("demo");
x.innerHTML=points;
Μετατροπή μιας array σε string
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<p id="demo">Click στο button</p>
<button onclick="myFunction()">Προσθήκη</button>
<script>
function myFunction()
{
var family = ["Γιώργος", "Ματίνα", "Μάριος", "Αθηνά"];
family.toString();
var x=document.getElementById("demo");
x.innerHTML=family ;
var x1=document.getElementById("demo1");
x1.innerHTML=family[0]; // Η Array παραμένει ως έχει, απλώς την κάναμε να συμπεριφερθεί ως string.
}
</script>
<p id="demo1"></p>
</body></html>
Οι τιμές υποχρεωτικά χωρίζονται με κόμμα.
Array of Arrays
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><title>JavaScript Array of Arrays</title></head><body>
<h1>JavaScript Array of Arrays</h1>
<script language="Javascript">
var array = new Array("Γιώργος","Ματίνα",564,375,new Array(5,6,7),".net")
document.write("array[0] = "+array[0]+"<br>")
document.write("array[1] = "+array[1]+"<br>")
document.write("array[2] = "+array[2]+"<br>")
document.write("array[3] = "+array[3]+"<br>")
document.write("array[4][0] = "+array[4][0]+"<br>")
document.write("array[4][1] = "+array[4][1]+"<br>")
document.write("array[4][2]= "+array[4][2]+"<br>")
document.write("array[5]= "+array[5]+"<br>")
</script></body></html>
Για να βρουμε το μήκος μιας array που βρίσκεται μέσα σε άλλη το property είναι multidimentionalarray[simplearraypositioninmultidimentional].length
Associative Arrays
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head><body>
<SCRIPT language="JavaScript">
<!--
function which_car()
{
var my_cars= new Array()
my_cars["cool"]="Mustang";
my_cars["οικογενειακό"]="Station Wagon";
my_cars["μεγάλο"]="SUV";
var car_type=prompt("Γράψτε το αυτοκίνητο που προτιμάτε?","");
if ((car_type=="cool") || (car_type=="οικογενειακό") || (car_type=="μεγάλο"))
alert("Νομίζω πως πρέπει να αγοράσετε ένα "+my_cars[car_type]+" αμάξι.");
else
alert("Σύγνώμη δεν ξέρω τι χρειάζεστε");
}
//-->
</SCRIPT>
<FORM>
<INPUT TYPE="button" onClick="which_car()" value="Βρες τι αμάξι θέλεις!">
</FORM></body></html>
Δοκιμάστε τι θα γίνει αν ψάξετε για οικογενειακό χωρίς τόνο.
Javascript αναζήτηση κειμένου
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var myRegExp = /Μαρία/;
var string1 = "Today John went to the store and talked with Μαρία";
var matchPos1 = string1.search(myRegExp);
if(matchPos1 != -1)
document.write("There was a match at position " + matchPos1);
else
document.write("There was no match in the first string");
</script>
</html>
Προσέξτε πως εδώ έχουμε μόνο αναγνώριση του «Μαρία» το «μαρία» (με πεζό μ) δεν θα αναγνωριστεί. Για να γίνει αυτό θα πρέπει να ορίσουμε: var myRegExp = /μαρία/i;
Στρογγυλοποιήσεις
<!DOCTYPE HTML>
<html>
<head><meta http-equiv=Content-Type content="text/html; charset=utf-8"> <title>Rounding</title>
</head>
<body>
<script type="text/javascript">
var num = 5.56789;
var n=num.toFixed(2);
/* 2 Αν θέλω 2 δεκαδικά ψηφία*/
alert(n);
</script></body></html>
ΠΡΟΣΟΧΉ: Η στογγυλοποίηση γίνεται στην εμφάνιση των δεδομένων. Η num δεν έχει αλλάξει περιεχόμενο.
Σύνταξη: number.toFixed(x)
Χρήση: Μετατρέπει έναν αριθμό σε string με x αριθμό δεκαδικών (η δήλωσή του είναι προεραιτική, χωρίς x θα μας δώσει το νούμερο χωρίς υποδιαστολή).
Μετατροπή string σε αριθμό: ParseInt και ParseFloat
<!DOCTYPE HTML>
<html>
<head><meta http-equiv=Content-Type content="text/html; charset=utf-8"> <title>Rounding</title>
</head>
<body>
<script type="text/javascript">
var num = 5.56789;
var n=num.toFixed(2);
/* 2 Αν θέλω 2 δεκαδικά ψηφία*/
var new_n = parseFloat(n);
new_n += 1;
alert(new_n);
</script></body></html>
parseFloat('1.45kg') // 1.45
parseFloat('77.3') // 77.3
parseFloat('077.3') // 77.3
parseFloat('0x77.3') // 0
parseFloat('.3') // 0.3
parseFloat('0.1e6') // 100000
parseInt('123.45') // 123
parseInt('77') // 77
parseInt('077',10) // 77
parseInt('77',8) // 63 (= 7 + 7*8)
parseInt('077') // 63 (= 7 + 7*8)
parseInt('77',16) // 119 (= 7 + 7*16)
parseInt('0x77') // 119 (= 7 + 7*16)
parseInt('099') // 0 (9 is not an octal digit)
parseInt('99',8) // NaN (0 in very old browsers e.g. IE3)
parseInt('0.1e6') // 0
parseInt('ZZ',36) // 1295 (= 35 + 35*36)
Javascript αντικατάσταση κειμένου
<html><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var visitorName = "Ματίνα";
var myOldString = "Hello username! I hope you enjoy your stay username.";
var myNewString = myOldString.replace("username", visitorName);
document.write("Old string = " + myOldString);
document.write("<br />New string = " + myNewString);
</script></html>
Αντί για string μπορούμε να χρησιμοποιήσουμε regular expression
<html><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var visitorName = "Σοφία";
var myOldString = "Hello username! I hope you enjoy your stay username.";
var myNewString = myOldString.replace(/username/, visitorName);
document.write("Old string = " + myOldString);
document.write("<br />New string = " + myNewString);
</script></html>
Για να κάνουμε την αναζήτηση case insensitive:
var myNewString = myOldString.replace(/username/i, visitorName);
Για πολλαπλή αντικατάσταση έχουμε:
<html><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var visitorName = "Κώστα";
var myOldString = "Hello username! I hope you enjoy your stay username.";
var myNewString = myOldString.replace(/username/g, visitorName);
document.write("Old string = " + myOldString);
document.write("<br />New string = " + myNewString);
</script></html>
Javascript Εύρεση τρέχουσας ημερομηνίας
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<h4>Τώρα έχουμε
<script type="text/javascript">
<!--
var currentTime = new Date()
var month = currentTime.getMonth() + 1
var day = currentTime.getDate()
var year = currentTime.getFullYear()
document.write(month + "/" + day + "/" + year)
//-->
</script></h4></html>
Javascript Εύρεση τρέχουσας ώρας
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<h4>Η ώρα είναι
<script type="text/javascript">
var currentTime = new Date()
var hours = currentTime.getHours()
var minutes = currentTime.getMinutes()
if (minutes < 10){
minutes = "0" + minutes
}
document.write(hours + ":" + minutes + " ")
if(hours > 11){
document.write("μ.μ.")
} else {
document.write("π.μ.")
}
</script></h4></html>
Javascript Εύρεση μήκους χαρακτήρων
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var myString = "αβγδεζ";
var length = myString.length;
document.write("The string is this long: " + length);
/* Η πάνω και η κάτω γραμμή δίνουν το ίδιο αποτέλεσμα.
Στη 2η χρησιμοποιούμε την write function απευθείας χωρίς ενδιάμεση μεταβλητή */
document.write("<br />Το string έχει μήκος: " + myString.length);
</script></html>
Javascript IndexOf
Εύρεση της θέσης ενός string:
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var aURL = "http://www.tizag.com/";
document.write(aURL);
var aPosition = aURL.indexOf("www");
document.write("<br>Η θέση του www είναι: " + aPosition);
</script></html>
Χρήση offset στην έναρξη αναζήτησης:
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var aURL = "http://www.tizag.com/www.html";
var aPosition = aURL.indexOf("www");
var secondPos = aURL.indexOf("www", aPosition + 1);
document.write("η θέση του www είναι: " + aPosition);
document.write("<br />Η θέση του δεύτερου www = " + secondPos);
</script></html>
Σύγκριση strings
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var username = "Agent006";
if(username == "Agent007")
document.write("Welcome special agent 007");
else
document.write("Access Denied!");
document.write("<br /><br />Would you like to try again?<br /><br />");
// Ξαναπροσπαθούμε με άλλο username
username = "Agent007";
if(username == "Agent007")
document.write("Welcome special agent 007");
else
document.write("Access Denied!");
</script></html>
Αν θέλουμε η σύγκριση να είναι case insensitive έχουμε:
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
var username = "someAgent";
if(username == "SomeAgent")
document.write("Welcome special agent");
else
document.write("Access Denied!");
// Now as case insensitive
document.write("<br /><br />Ξαναδοκιμάζουμε με έχοντας κάνει LowerCase όλα:<br /><br />");
if(username.toLowerCase() == "SomeAgent".toLowerCase())
document.write("Welcome special agent");
else
document.write("Access Denied!");
</script></html>
parseInt
Διαβάζει ένα string και δίνει έναν ακέραιο.
Σύνταξη: parseInt(string, radix)
Το radix είναι προαιρετικό. Αν δεν υπάρχει κάτι βρίσκει αριθμό στο δεκαδικό σύστημα. Αν είναι 16 βρίσκει στο δεκαεξαδικό. Αν το string που θα βρει αρχίζει από 0x θα το θεωρήσει δεκαεξαδικό, ενώ αν αρχίζει από μηδέν οκταδικό (octal).
Τα οκταδικά συστήματα χρησιμοποιούν τα ψηφία από 0 έως 7. Για παράδειγμα σε binary το 74 του δεκαδικού συστήματος είναι 1001010, αυτό ομαδοποιείται σε: (00)1 001 010 οπότε το οκταδικό του είναι: 112.
<!DOCTYPE html>
<html><head><meta charset=utf-8></head>
<body><script>
document.write(parseInt("10") + "<br>") ;
document.write(parseInt("10.33") + "<br>");
document.write(parseInt("34 45 66") + "<br>");
document.write(parseInt(" 60 ") + "<br>");
document.write(parseInt("40 χρονών") + "<br>");
document.write(parseInt("Ήταν 40") + "<br>");
document.write("<br>");
document.write(parseInt("10",10)+ "<br>");
document.write(parseInt("010")+ "<br>");
document.write(parseInt("10",8)+ "<br>");
document.write(parseInt("0x10")+ "<br>");
document.write(parseInt("10",16)+ "<br>");
</script></body></html>
Χρήση της void
Με void 0 η παραπομπή δεν εκτελείται:
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<a href="javascript: void(0)">Άχρηστο link</a></html>
Με οποιοδήποτε άλλο νούμερο μπορούμε να το χρησιμοποιήσουμε για περαιτέρω εργασίες.
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<a href="javascript: void(myNum=10);alert('Νούμερο = '+myNum)">Δώσε νούμερο:</a></html>
Και για ένα τυχαίο νούμερο από το 0 έως το 10:
H Math.floor(x) μας δίνει τον κοντινότερο προς τα κάτω ακέραιο για ένα δεκαδικό. Π.χ:
Math.floor(1.6);
Μας δίνει 1.
<html>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>var myNum=Math.floor(Math.random()*11);</script>
<a href="javascript: void(myNum);alert('Νούμερο = '+myNum)">
Δώσε νούμερο:</a></html>
Για να αλλάξει το νούμερο πρέπει να ξαναγίνει load η σελίδα.
Τυχαίο νούμερο από 1 έως 100:
Math.floor((Math.random()*100)+1);
Confirmation Box
<html><head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script type="text/javascript">
function confirmation() {
var answer = confirm("Leave tizag.com?")
if (answer){
alert("Bye bye!")
window.location = "http://www.google.com/";
}
else{
alert("Ευχαριστούμε που παραμείνατε!")
}
}
</script></head>
<body>
<form>
<input type="button" onclick="confirmation()" value="Πήγαινε σε άλλο site">
</form></body></html></html>
Try … Catch
Εκτελούμε μια εργασία και παρακολουθούμε πιθανά λάθη.
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
var txt="";
function message()
{
try
{
adddlert("Καλώς όρισες!");
}
catch(err)
{
txt="Η σελίδα έχει λάθος.\n\n";
txt+="Περιγραφή λάθους: " + err.message + "\n\n";
txt+="Click στο OK για τη συνέχεια.\n\n";
alert(txt);
}
}
</script></head><body>
<input type="button" value="Δες το μήνυμα" onclick="message()">
</body></html>
Το πρόβλημα εδώ είναι πως γράψαμε adddlert αντί για alert. Αν το αλλάξουμε δεν θα εμφανίζεται πια το μήνυμα λάθους.
Ternary Operator
Αντί για if … else ένας άλλος τρόπος να ενεργήσουμε ελέγχους μιας συνθήκης είναι ο ternary operator.
Αντί για
var b=5;
If (b ==5) {
document.write(" ---------------------------σωστό");
}
else {
document.write(" ---------------------------λάθος");
}
έχουμε:
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head>
<body>
<script language=javascript>
var b=5;
(b == 5) ? a="σωστό" : a="λάθος";
document.write(" --------------------------- "+a);
</script>
</body>
</html>
Αλλάξτε το var b=5 για να δείτε το άλλο condition.
Object Oriented Programming με Javascript
Για την JavaScript τα πάντα είναι objects, πχ. Strings, Dates, Arrays, Functions. κ.λπ. Εκεί όμως που τα πράγματα γίνονται πιο περίπλοκα και ενδιαφέρντα είναι όταν δημιουργούμε δικά μας objects.
Στο παρακάτω κώδικα κατασκευάζουμε το object με όνομα: human
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
var human=new Object();
human.firstname="Γιώργος";
human.lastname="Επιτήδειος";
human.age=46;
human.eyecolor="καστανά";
document.write("Ο " + human.firstname + " είναι " + human.age + " ετών. Έχει " + human.eyecolor + " μάτια");
</script></body></html>
objectName.propertyName είναι η σύνταξη για να αποκτήσουμε πρόσβαση σε ένα χαρακτηριστικό (property) του object.
Χρήση υπάρχοντος object
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
var message="Είμαι και εγώ ένα αντικείμενο!";
var x=message.length;
document.write("Το μήνυμα έχει μήκος " + x + " χαρακτήρες");
</script></body></html>
Χρήση μεθόδων για ένα αντικείμενο:
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<script>
var message="Είμαι και εγώ ένα αντικείμενο!";
var x=message.toUpperCase();
document.write("Το μήνυμα είναι: " + x);
</script></body></html>
Εδώ χρησιμοποιούμε τη μέθοδο toUpperCase για να μετατρέψουμε το περιεχόμενο σε κεφαλαία.
Boolean Object
<!DOCTYPE html><html><body><script>
var b1=new Boolean(0);
var b2=new Boolean(1);
var b3=new Boolean("");
var b4=new Boolean(null);
var b5=new Boolean(NaN);
var b6=new Boolean("false");
document.write("0 is boolean "+ b1 +"<br>");
document.write("1 is boolean "+ b2 +"<br>");
document.write("An empty string is boolean "+ b3 + "<br>");
document.write("null is boolean "+ b4+ "<br>");
document.write("NaN is boolean "+ b5 +"<br>");
document.write("The string 'false' is boolean "+ b6 +"<br>");
</script></body></html>
Math Object
Round (μόνο για ακέραιους)
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
<p id="demo">Click για στρογγυλοποίηση του 2,5 στον κοντινότερο ακέραιο.</p>
<button onclick="myFunction()">Δοκιμή</button>
<script>
function myFunction()
{
document.getElementById("demo").innerHTML=Math.round(2.5);
}
</script></body></html>
Random (δίνει τιμή από 0 έως 1)
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
<p id="demo">Click για έναν τυχαίο αριθμό.</p>
<button onclick="myFunction()">Δοκιμή</button>
<script>
function myFunction()
{
document.getElementById("demo").innerHTML=Math.random();
}
</script></body></html>
Max (ο μεγαλύτερος από δύο ή περισσότερους αριθμούς)
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
<p id="demo">Click για τον μεγαλύτερο από δύο αριθμούς.</p>
<button onclick="myFunction()">Δοκιμή</button>
<script>
function myFunction()
{
document.getElementById("demo").innerHTML=Math.max(5,10);
}
</script></body></html>
Min (ο μικρότερος από δύο ή περισσότερους αριθμούς)
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
<p id="demo">Click για τον μικρότερο από δύο αριθμούς.</p>
<button onclick="myFunction()">Δοκιμή</button>
<script>
function myFunction()
{
document.getElementById("demo").innerHTML=Math.min(5,10);
}
</script></body></html>
Ajax
AJAX = Asynchronous JavaScript and XML.
Μια απλή εφαρμογή:
<!DOCTYPE html>
<html><head><meta charset="utf-8"><script>
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","ajaxtext.txt",true);
xmlhttp.send();
}
</script></head><body>
<div id="myDiv"><h2>Αλλαγή του κειμένου με AJAX</h2></div>
<button type="button" onclick="loadXMLDoc()">Άλλαξέ το</button>
</body></html>
Εδώ όταν ο χρήστης κάνει click στο κουμπί φορτώνεται το περιεχόμενο ενός αρχείου το οποίο στην προκειμένη περίπτωση ονομάζεται ajaxtext.txt και βρίσκεται στον ίδιο φάκελο με τη σελίδα. Το περιεχόμενο του αρχείου είναι:
<p>Dokimastiko 1 </p>
<p>Δοκιμαστικό 2 </p>
Τι σημαίνει αυτός ο κώδικας:
onclick="loadXMLDoc()
Όταν ο χρήστης κάνει click στο κουμπί θα κληθεί η συνάρτηση: loadXMLDoc χωρίς κάποια παράμετρο.
Για νακληθεί η σελίδα (αρχείο στην περίπτωσή μας) με το περιεχόμενο θα δημιουργηθεί το object xmlhttp με χρήση της XMLHttpRequest(), που είναι και αυτή ένα object, εκτός αν αυτή δεν είναι αναγνωρίσιμη από τον browser (IE5 και IE6,) οπότε θα κληθεί το ActiveXObject("Microsoft.XMLHTTP").
xmlhttp.open("GET","ajaxtext.txt",true);
xmlhttp.send();
Ακολούθως στέλνουμε το request για το αρχείο στον server. Η σύνταξη είναι:
open(method,url,async) για να δηλώσουμε τι είδους σύνδεση θα γίνει. Στο παράδειγμα το method είναι GET, url το URL και true σημαίνει πως η σύνδεση είναι ασύγχρονη. false σημαίνει σύχρονη.
Σπανίως θα κάνουμε σύγχρονη σύνδεση. Το πλεονέκτημα της ασύγχρονης είναι πως ο browser μπορεί να ασχοληθεί με άλλα πράγματα (π.χ. να τρέξει άλλα scripts) μέχρι να ολοκληρωθεί η κλήση οπότε η σελίδα φορτώνει πιο γρήγορα.
send(string) Έτσι ανοίγουμε τη σύνδεση για τη λήψη της σελίδα/αρχείου. Το string συμπληρώνεται μόνο στην περίπτωση που το method είναι POST.
POST θα χρησιμοποιήσουμε αν θέλουμε να στείλουμε πολλά δεδομένα στον server (μέσω του URL) επειδή η POST δεν έχει περιορισμούς μεγέθους. Επίσης αν θέλουμε να περάσουμε παραμέτρους μέσω του URL προτιμάται η POST γιατί είναι πιο σταθερή.
Μια POST request θα είχε τη μορφή:
xmlhttp.open("POST","ajaxtest.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Γιώργος&lname=Επιτήδειος");
xmlhttp.onreadystatechange=function()
Όταν είναι έτοιμη η απάντηση από τον server (ερώτηση κάναμε με το URL που ζητήσαμε).
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
Αν η λήψη των δεδομένων ήταν επιτυχής.
Property Περιγραφή
onreadystatechange Αποθηκεύει μια function (ή ένα όνομα function) που θα κληθεί αυτόματα μόλις αλλάξει το readyState propertys
readyState Περιέχει το status του XMLHttpRequest. Παίρνει τιμές από 0 έως 4:
0: request not initialized
1: server connection established
2: request received
3: processing request
4: request finished and response is ready
status 200: "OK"
404: Page not found
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
Αλλάζουμε το περιεχόμενο της σελίδας.
Αν ο server δώσει xml πρέπει να το διαβάσουμε (να το κάνουμε parse).
Ας υποθέσουμε πως έχουμε το xml αρχείο με περιεχόμενο:
<?xml version="1.0" encoding="UTF-8"?><doc class="simple"><title>Data Doc</title><section><title no="1" type="intro">Introduction</title><record><clientcode>ADV3</clientcode><clientname>Γιώργος</clientname></record><record><clientcode>ADV5</clientcode><clientname>Ματίνα</clientname></record></section></doc>
Ο κώδικας είναι:
<!DOCTYPE html><html><head><meta charset="utf-8"><script>
function loadXMLDoc()
{
var xmlhttp;
var txt,x,i;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
xmlDoc=xmlhttp.responseXML;
txt="";
x=xmlDoc.getElementsByTagName("clientname");
for (i=0;i<x.length;i++)
{
txt=txt + x[i].childNodes[0].nodeValue + "<br>";
}
document.getElementById("myDiv").innerHTML=txt;
}
}
xmlhttp.open("GET","ajaxtext.xml",true);
xmlhttp.send();
}
</script></head><body>
<h2>Δεδομένα από XML:</h2>
<div id="myDiv"></div>
<button type="button" onclick="loadXMLDoc()">Διάβασε το XML</button>
</body></html>
Προσοχή το clientname είναι case sensitive.
Υπενθύμιση: Τα XML αρχεία είναι υποχρεωτικά UTF-8
Εδώ η διαφορά στον κώδικα είναι το:
xmlDoc=xmlhttp.responseXML;
txt="";
x=xmlDoc.getElementsByTagName("clientname");
for (i=0;i<x.length;i++)
{
txt=txt + x[i].childNodes[0].nodeValue + "<br>";
}
Perl & AJAX
<!DOCTYPE html>
<html><head><meta charset="utf-8">
</head><body>
<div id="buttons">
<input type="button" id="save" value="Save Data">
</div>
Saved data: <span id="savedData">Saved Data</span></p>
<script type="text/javascript">
document.getElementById('save').addEventListener('click', function() {
saveData();
}, false);
var str = "test,test1,test2";
function saveData() {
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","http://www.eeei.gr/cgi-bin/save_battle_positions.pl?positions="+str,true);
xmlhttp.send();
document.getElementById("savedData").innerHTML=str;
}
</script>
</body></html>
Εδώ έχουμε ήδη μια πληροφορία (στην str) και τη στέλνουμε σε ένα perl script που κάτι την κάνει (την αποθηκεύει σε ένα αρχείο αλλά αυτό δεν έχει σημασία). Στη συνέχεια τυπώνουμε τι στείλαμε.
Προσοχή: για να λειτουργήσει το script πρέπει ο κώδικάς του να τοποθετηθεί κάτω από το κουμπί και το span. Σε διαφορετική περίπτωση τρέχει πρώτος και δεν τα αναγνωρίζει αφού δεν τα έχει βρει ακόμη ο browser.
PHP & AJAX
<!DOCTYPE html>
<html><head><meta charset="utf-8"><script>
function showHint(str)
{
var xmlhttp;
if (str.length==0)
{
document.getElementById("txtHint").innerHTML="";
return;
}
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","ajaxphp.php?q="+str,true);
xmlhttp.send();
}
</script></head><body>
<h3>Start typing a name in the input field below:</h3>
<form action="">
First name: <input type="text" id="txt1" onkeyup="showHint(this.value)" />
</form>
<p>Suggestions: <span id="txtHint"></span></p>
</body></html>
Ο παραπάνω κώδικας καλεί την εφαρμογή: ajaxphp.php και με βάση όσα πληκτρολογεί ο χρήστης του προτείνει ονόματα.
Ο PHP κώδικας είναι:
<?php
// Fill up array with names
$a[]="Anna";
$a[]="Brittany";
$a[]="Cinderella";
$a[]="Diana";
$a[]="Eva";
$a[]="Fiona";
$a[]="Giorgos";
$a[]="Gunda";
$a[]="Hege";
$a[]="Inga";
$a[]="Johanna";
$a[]="Kitty";
$a[]="Linda";
$a[]="Nina";
$a[]="Ophelia";
$a[]="Petunia";
$a[]="Amanda";
$a[]="Raquel";
$a[]="Cindy";
$a[]="Doris";
$a[]="Eve";
$a[]="Evita";
$a[]="Sunniva";
$a[]="Tove";
$a[]="Unni";
$a[]="Violet";
$a[]="Liza";
$a[]="Elizabeth";
$a[]="Ellen";
$a[]="Wenche";
$a[]="Vicky";
//get the q parameter from URL
$q=$_GET["q"];
//lookup all hints from array if length of q>0
if (strlen($q) > 0)
{
$hint="";
for($i=0; $i<count($a); $i++)
{
if (strtolower($q)==strtolower(substr($a[$i],0,strlen($q))))
{
if ($hint=="")
{
$hint=$a[$i];
}
else
{
$hint=$hint." , ".$a[$i];
}
}
}
}
// Set output to "no suggestion" if no hint were found
// or to the correct values
if ($hint == "")
{
$response="no suggestion";
}
else
{
$response=$hint;
}
//output the response
echo $response;
?>
Επεξήγηση:
onkeyup="showHint(this.value)
Όταν ελευθερώνεται κάποιο πλήκτρο (πατήθηκε και ελευθερώθηκε) διαβάζουμε τι γράφτηκε στο πεδίο και τα δίνουμε στη function showHint.
if (str.length==0)
{
document.getElementById("txtHint").innerHTML="";
return;
}
Αν η showHint είναι κενή δεν γράφουμε τίποτε.
Διαφορετικά:
xmlhttp.open("GET","ajaxphp.php?q="+str,true);
xmlhttp.send();
καλούμε το url: http://www.gepiti.com/tests/ajaxphp.php?q=g
(στο παράδειγμα έχει πληκτρολογηθεί μόνο το γράμμα g)
document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
Πάρνουμε την απάντηση και στη txtHint γράφουμε ό,τι μας προτείνει η εφαρμογή.
AJAX και βάση δεδομένων XML
<!DOCTYPE html><html><head><meta charset="utf-8"><script>
function loadXMLDoc(selectedvalue)
{
var xmlhttp;
var txt,x,i;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
xmlDoc=xmlhttp.responseXML;
x=xmlhttp.responseXML.documentElement.getElementsByTagName("record");
for (i=0;i<x.length;i++) {
var current_client_code;
var current_client_name;
xx=x[i].getElementsByTagName("clientcode");
{
try
{
current_client_code = xx[0].firstChild.nodeValue;
}
catch (er)
{
current_client_code = 'not found';
}
}
xx=x[i].getElementsByTagName("clientname");
{
try
{
current_client_name = xx[0].firstChild.nodeValue;
}
catch (er)
{
current_client_name = 'not found';
}
}
if (selectedvalue == current_client_code) {
txt = "Κωδικός: " + current_client_code + " Όνομα: " + current_client_name;
}
}
if (txt == null) {
txt = 'Δεν βρέθηκε ο πελάτης';
}
document.getElementById("txtHint").innerHTML=txt;
}
}
xmlhttp.open("GET","ajaxtext.xml",true);
xmlhttp.send();
}
</script></head><body>
<h2>Δεδομένα από βάση XML:</h2>
<form action="">
<select name="customers" onchange="loadXMLDoc(this.value)">
<option value="">Επιλέξτε Πελάτη:</option>
<option value="ADV3">Γιώργος</option>
<option value="ADV5">Ματίνα</option>
<option value="ADV6 ">Μάριος</option>
</select>
</form>
<br>
<div id="txtHint">Εδώ θα εμφανιστούν τα στοιχεία του πελάτη...</div>
</body></html>
setInterval
Ορίζει επαναλαμβανόμενη δραστηριότητα (θα τρέχει συνέχεια μέχρι να τη διακόψουμε).
H setInterval ορίζει μετά από πόσο χρόνο θα ξανατρέξει μια function. Αν λοιπόν η function μας έτρεξε στις 18:00:00 και τρέχει κάθε ένα δευτερόλεπτο (1000 microseconds), θα ξανατρέξει στις 18:00:01.
Προσέξτε πως η setInterval δεν λαμβάνει υπόψη της για πόσο χρόνο θα τρέξει η function. Είτε η function διαρκέσει μισό δευτερόλεπτο είτε 100 microseconds θα τρέχει στις και 1 δευτερόλεπτο και 2 δευτερόλεπτα κ.ο.κ.
Αν η function διαρκέσει 1,5 δεύτερα τότε η επόμενη θα τρέξει μόλις τελειώσει η προηγούμενη. Ουρά μεγαλύτερη του ενός δεν υπάρχει. Αν πρέπει να τρέξω κάθε 1 δευτερόλεπτο για 5 φορές τη function και αυτή έχει διάρκεια 3 δευτερόλεπτα θα τρέξει τρεις φορές.
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style>
#hour { color: red }
#min { color: green }
#sec { color: blue }
</style></head>
<body>
<div id="clock">
<span id="hour">ωω</span>:<span id="min">λλ</span>:<span id="sec">δδ</span>
</div>
<script type="text/javascript">
var timerId
function update() {
var date = new Date()
var hours = date.getHours()
if (hours < 10) hours = '0'+hours
document.getElementById('hour').innerHTML = hours
var minutes = date.getMinutes()
if (minutes < 10) minutes = '0'+minutes
document.getElementById('min').innerHTML = minutes
var seconds = date.getSeconds()
if (seconds < 10) seconds = '0'+seconds
document.getElementById('sec').innerHTML = seconds
}
function clockStart() {
if (timerId) return // Αν υπάρχει ήδη ο timer συνεχίζει στα ίδια
timerId = setInterval(update, 1000)
update() // <-- Αν δεν τρέξει άμεσα το setInterval θα αρχίσει με ένα δευτερόλεπτο καθυστέρηση (δοκιμάστε να το τρέξετε χωρίς αυτό).
}
function clockStop() {
clearInterval(timerId) // Έτσι σταματάει
timerId = null
}
</script>
<input type="button" onclick="clockStart()" value="Start">
<input type="button" onclick="clockStop()" value="Stop">
</body></html>
setTimeout
Ορίζει επαναλαμβανόμενη δραστηριότητα (θα τρέχει συνέχεια μέχρι να τη διακόψουμε)
Εδώ στο τέλος κάθε function υπάρχει μια καθυστέρηση Χ microseconds και ξαναρχίζει. Οπότε αν η function διαρκεί 500 microseconds τότε η πρώτη θα τρέξει 18:00:00 η δεύτερη 18:00:015 η Τρίτη 18:00:03 κ.ο.κ.
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style>
#hour { color: red }
#min { color: green }
#sec { color: blue }
</style></head><body>
<div id="clock">
<span id="hour">ωω</span>:<span id="min">λλ</span>:<span id="sec">δδ</span>
</div>
<script type="text/javascript">
var timerId
function update() {
var date = new Date()
var hours = date.getHours()
if (hours < 10) hours = '0'+hours
document.getElementById('hour').innerHTML = hours
var minutes = date.getMinutes()
if (minutes < 10) minutes = '0'+minutes
document.getElementById('min').innerHTML = minutes
var seconds = date.getSeconds()
if (seconds < 10) seconds = '0'+seconds
document.getElementById('sec').innerHTML = seconds
timerId = setTimeout(update, 1000)
}
function clockStart() {
if (timerId) return
update()
}
function clockStop() {
clearTimeout(timerId) // Έτσι σταματάει
timerId = null
}
</script>
<input type="button" onclick="clockStart()" value="Start">
<input type="button" onclick="clockStop()" value="Stop">
</body></html>
clientHeight,offsetHeight και Width
Χρησιμοποιούνται για να βρούμε το ύψος και το πλάτος ενός element.
<head>
<style>
#container {
width: 350px;
height: 150px;
margin: 10px;
border: 2px solid red;
padding: 15px;
}
</style>
<script type="text/javascript">
function GetContainerSize () {
var container = document.getElementById ("container");
var message = "The height with padding: " + container.clientHeight + "px.\n";
message += "The height with padding and border: " + container.offsetHeight + "px.\n";
message += "The width width padding: " + container.clientWidth + "px.\n";
message += "The width with padding and border: " + container.offsetWidth + "px.\n";
alert (message);
}
</script>
</head>
<body>
<div id="container">
The width of this element is 350px<br />
The height of this element is 150px<br />
Furthermore, the element has the following style definitions:<br />
margin: 10px; border: 2px solid red; padding: 15px;
</div>
<button onclick="GetContainerSize ();">Get the size of the container!</button>
</body>
Χρήση του jQuery
Το jQuery είναι η δημοφιλέστερη βιβλιοθήκη της Javascript με πολλά βοηθήματα για ευκολότερο προγραμματισμό.
Κρύψε τις παραγράφους όταν πατηθεί μια
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("p").click(function(){
$(this).hide();
});
});
</script></head>
<body>
<p>Κάνε μου click για να εξαφανιστώ.</p>
</body></html>
Η εφαρμογή αυτό χρησιμοποιεί τη μέθοδο hide() του jQuery για να εξαφανίσει όλα τα <p>
To $("p") επιλέγει όλα τα <p> elements της σελίδας.
Το jQuery βασίζεται πάνω σε ήδη υπάρχοντες CSS Selectors (π.χ. .class #id :hover div p κ.λπ)οι οποίοι καλούνται με το $().
Στην προκειμένη περίπτωση λοιπόν καλούμε το document και όταν έχει φορτώσει. Τρέχουμε μια function όπου επιλέγουμε τα <p> και στο click τρέχει άλλη function και κρύβονται.
Κρύψε τις παραγράφους όταν πατηθεί ένα κουμπί
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("p").hide();
});
});
</script>
</head><body>
<h2>Ένα heading</h2>
<p>Μία παράγραφος.</p>
<p>Μία άλλη παράγραφος.</p>
<button>Click me</button>
</body></html>
Κρύψε τις παραγράφους με συγκεκριμένο id όταν πατηθεί ένα κουμπί
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("#test").hide();
});
});
</script>
</head><body>
<h2>Ένα heading</h2>
<p>Μία παράγραφος.</p>
<p id="test">Μία άλλη παράγραφος.</p>
<button>Click me</button>
</body></html>
Κρύψε τις παραγράφους με συγκεκριμένη class όταν πατηθεί ένα κουμπί
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$(".test").hide();
});
});
</script>
</head><body>
<h2>Ένα heading</h2>
<p>Μία παράγραφος.</p>
<p class="test">Μία άλλη παράγραφος.</p>
<button>Click me</button>
</body></html>
Κρύψε όλα τα elements $("*").hide();
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("*").hide();
});
});
</script>
</head><body>
<h2>Ένα heading</h2>
<p>Μία παράγραφος.</p>
<p class="test">Μία άλλη παράγραφος.</p>
<button>Click me</button>
</body></html>
Κρύψε το τρέχον element $(this)
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$(this).hide(); // Εδώ κρύβεται το κουμπί
});
});
</script>
</head><body>
<h2>Ένα heading</h2>
<p>Μία παράγραφος.</p>
<p class="test">Μία άλλη παράγραφος.</p>
<button>Click me</button>
</body></html>
Άλλοι Selectors
$("p.intro") Selects all <p> elements with class="intro"
$("p:first") Selects the first <p> element
$("ul li:first") Selects the first <li> element of the first <ul>
$("ul li:first-child") Selects the first <li> element of every <ul>
$("[href]") Selects all elements with an href attribute
$("a[target='_blank']") Selects all <a> elements with a target attribute value equal to "_blank"
$("a[target!='_blank']") Selects all <a> elements with a target attribute value NOT equal to "_blank"
$(":button") Selects all <button> elements and <input> elements of type="button"
$("tr:even") Selects all even <tr> elements
$("tr:odd") Selects all odd <tr> elements
jQuery Κρύψε και Εμφάνισε
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#hide").click(function(){
$("p").hide();
});
$("#show").click(function(){
$("p").show();
});
});
</script></head><body>
<p>Αν κάνεις κλικ στο κρύψε θα εξαφανιστώ</p>
<button id="hide">Κρύψε</button>
<button id="show">Εμφάνισε</button>
</body></html>
Η σύνταξη είναι:
$(selector).hide(speed,callback);
$(selector).show(speed,callback);
Στο jQuery θα δούμε συχνά Callback functions όπως το $(selector).hide(speed,callback);. Ο λόγος είναι πως κανονικά ο κώδικας javascript εκτελείται σε σειρά οπότε έχουμε εκτέλεση της μιας γραμμής μετά την άλλη. Αυτό μπορεί να προκαλέσει προβλήματα σε ορισμένες περιπτώσεις οπότε προτιμούμε η γραμμή να καλεί άμεσα τη function που πρέπει να ακολουθήσει.
Προεραιτικά δηλώνουμε speed (ταχύτητα εμφάνισης ή κρυψίματος) με τιμές "slow", "fast", ή milliseconds.
Προεραιτικά δηλώνουμε optional callback δηλαδή το όνομα της function που θα τρέξει όταν ολοκληρωθεί το hide ή το show. (Στο παράδειγμα που ακολουθεί πάντως η function τρέχει πριν το show).
Αλλάξτε το: $("p").hide(); σε $("p").hide(2000); για να δείτε τη διαφορά.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#hide").click(function(){
$("p").hide(2000);
});
$("#show").click(function(){
$("p").show(1000,mytest('ddddd'));
});
});
function mytest (msg) {
alert(msg);
}
</script>
</head><body>
<p>Αν κάνεις κλικ στο κρύψε θα εξαφανιστώ</p>
<button id="hide">Κρύψε</button>
<button id="show">Εμφάνισε</button>
</body></html>
Toggle (εναλλαγή)
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("p").toggle();
});
});
</script></head><body>
<button>Toggle</button>
<p>Κάποιο κείμενο.</p>
<p>Και άλλο κείμενο σε ξεχωριστή παράγραφο.</p>
</body>
</html>
Η σύνταξη είναι: $(selector).toggle(speed,callback);
Εδώ χάνονται και εμφανίζονται πάλι όλες οι παράγραφοι.
Fade in – Fade out
Fade in (εμφάνιση)
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("#div1").fadeIn();
$("#div2").fadeIn("slow");
$("#div3").fadeIn(5000);
});
});
</script>
</head><body>
<p>fadeIn() με διαφορετικές παραμέτρους.</p>
<button>Click για fade in</button>
<br><br>
<div id="div1" style="width:80px;height:80px;display:none;background-color:red;"></div><br>
<div id="div2" style="width:80px;height:80px;display:none;background-color:green;"></div><br>
<div id="div3" style="width:80px;height:80px;display:none;background-color:blue;"></div>
</body>
</html>
Fade out (απόκρυψη)
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("#div1").fadeOut();
$("#div2").fadeOut("slow");
$("#div3").fadeOut(6000);
});
});
</script></head><body>
<p>fadeOut() με διαφορετικές παραμέτρους.</p>
<button>Κάντε Click για fade out</button>
<br><br>
<div id="div1" style="width:80px;height:80px;background-color:red;"></div><br>
<div id="div2" style="width:80px;height:80px;background-color:green;"></div><br>
<div id="div3" style="width:80px;height:80px;background-color:blue;"></div>
</body></html>
Με τον ίδιο τρόπο γίνεται και η εναλλαγή:
$(selector).fadeToggle(speed,callback);
fadeTo
Εδώ έχουμε μια επιπλέον παράμετρο, το opacity ώστε να ορίσουμε πόσο αχνό ή έντονο θέλουμε το περιεχόμενο. Παίρνει τιμές από 0 έως και 1.
$(selector).fadeTo(speed,opacity,callback);
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("#div1").fadeTo("slow",0.15);
$("#div2").fadeTo("slow",0.4);
$("#div3").fadeTo("slow",0.7);
$("#eeei1").fadeTo("slow",0.2);
});
});
</script></head><body>
<p>fadeTo() με διάφορες παραμέτρους.</p>
<button>Click για fade</button>
<br><br>
<div id="div1" style="width:80px;height:80px;background-color:red;"></div><br>
<div id="div2" style="width:80px;height:80px;background-color:green;"></div><br>
<div id="div3" style="width:80px;height:80px;background-color:blue;"></div>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Slide
Slide Down
Σύνταξη: $(selector).slideDown(speed,callback);
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").click(function(){
$("#panel").slideDown("slow");
});
});
</script>
<style type="text/css">
#panel,#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
display:none;
}
</style></head><body>
<div id="flip">Click για να γίνει slide προς τα κάτω το panel</div>
<div id="panel">Καλημέρα κόσμε!</div>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Λειτουργεί και ως expanded banner με τον ίδιο τρόπο.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").click(function(){
$("#panel").slideDown("slow");
});
});
</script>
<style type="text/css">
#panel,#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
display:none;
background-image: url(http://www.eeei.gr/images/eeeil1.jpg);
}
</style></head><body>
<div id="flip">Click για να γίνει slide προς τα κάτω το panel</div>
<div id="panel">Καλημέρα κόσμε!</div>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Το ίδιο μπορεί να γίνει και με mouseover
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").mouseover(function(){
$("#panel").slideDown("slow");
});
});
</script>
<style type="text/css">
#panel,#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
display:none;
background-image: url(http://www.eeei.gr/images/eeeil1.jpg);
}
</style></head><body>
<div id="flip">Click για να γίνει slide προς τα κάτω το panel</div>
<div id="panel">Καλημέρα κόσμε!</div>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Slide Up
Είναι η αντίθετη της slideDown και κρύβει αντί να εμφανίζει.
Σύνταξη: $(selector).slideUp(speed,callback);
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").click(function(){
$("#panel").slideUp("slow");
});
});
</script>
<style type="text/css">
#panel,#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
}
</style></head><body>
<div id="flip">Click για να γίνει slide προς τα πάνω το panel</div>
<div id="panel">Καλημέρα κόσμε!</div>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Το ίδιο με img αντί για div
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").click(function(){
$("#panel").slideUp("slow");
});
});
</script>
<style type="text/css">
#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
}
</style></head><body>
<div id="flip">Click για να γίνει slide προς τα πάνω το panel</div>
<img id="panel" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Toggle
Σύνταξη: $(selector).slideToggle(speed,callback);
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").click(function(){
$("#panel").slideToggle("slow");
});
});
</script>
<style type="text/css">
#panel,#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
display:none;
}
</style></head><body>
<div id="flip">Click για να κινηθεί το panel πάνω κάτω</div>
<div id="panel">Καλημέρα κόσμε!</div>
</body></html>
Chaining
Μπορούμε αν θέλουμε να βάλουμε πολλές ενέργειες στην ίδια κλήση. Αυτό κάνει και πιο γρήγορη την εκτέλεση αφού ο browser δεν χρειάζεται να ξαναψάχνει για το ίδιο element.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function()
{
$("button").click(function(){
$("#p1").css("color","red").slideUp(2000).slideDown(2000);
});
});
</script></head><body>
<p id="p1">Πολύ Ωραίο</p>
<button>Click εδώ</button>
</body></html>
Εδώ παίρνουμε την <p id=”p1”> και κάνουμε κόκκινο το κείμενο, την κάνουμε slide προς τα πάνω και μετά προς τα κάτω.
jQuery Animation
Σύνταξη: $(selector).animate({params},speed,callback);
animate()
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("div").animate({left:'250px'});
});
});
</script> </head>
<body><button>Έναρξη</button>
<div style="background:#98bf21;height:100px;width:100px;position:absolute;">
</div></body></html>
Με τον παραπάνω κώδικα μετακινούμερ το div αριστερά κατά 250 pixels.
ΠΡΟΣΟΧΗ! Για να λειτουργήσει το animation το κινούμενο element θα πρέπει να έχει δηλωμένο position (relative, fixed, ή absolute).
Animation πολλών properties ταυτόχρονα.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("div").animate({
left:'250px',
opacity:'0.1',
height:'150px',
width:'150px'
});
});
});
</script> </head>
<body><button>Έναρξη</button>
<div style="background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;">
</div></body></html>
Αν δεν είχαμε δηλώσει opacity στο style τότε θα ξεκινούσε από 1.
Στα properties μπορώ να ορίσω σχετικές τιμές αντί για απόλυτες.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$("div").animate({
left:'250px',
opacity:'+=0.1',
height:'+=150px',
width:'+=150px'
});
});
});
</script> </head>
<body><button>Έναρξη</button>
<div style="background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;">
</div></body></html>
Animations σε σειρά
Αλλαγή στο μορφή ενός div
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
var div=$("div");
div.animate({height:'300px',opacity:'0.4'},"slow");
div.animate({width:'300px',opacity:'0.8'},"slow");
div.animate({height:'100px',opacity:'0.4'},"slow");
div.animate({width:'100px',opacity:'0.8'},"slow");
});
});
</script> </head>
<body><button>Έναρξη</button>
<div style="background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;">
</div></body></html>
Μετακίνηση div και αλλαγή της μορφής του περιεχομένου
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
var div=$("div");
div.animate({left:'100px'},"slow");
div.animate({fontSize:'2em'},"slow");
});
});
</script> </head>
<body><button>Έναρξη</button>
<div style="background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;">Καλό;
</div></body></html>
Διακοπή ενός animation
$(selector).stop();
Χωρίς κάποια μεταβλητή θα σταματήσει απλώς το τρέχον animation.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#flip").click(function(){
$("#panel").slideDown(5000);
});
$("#stop").click(function(){
$("#panel").stop();
});
});
</script>
<style type="text/css">
#panel,#flip
{
padding:5px;
text-align:center;
background-color:#e5eecc;
border:solid 1px #c3c3c3;
}
#panel
{
padding:50px;
display:none;
}
</style></head><body>
<button id="stop">Σταμάτημα του sliding</button>
<div id="flip">Click για να γίνει slide προς τα κάτω το panel</div>
<div id="panel">Καλημέρα κόσμε!</div>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98">
</body></html>
Διακοπή σε αλληλουχία ενεργειών (σταματάει μόνο η τελευταία).
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#start").click(function(){
var div=$("div");
div.animate({height:'300px',opacity:'0.4'},"slow");
div.animate({width:'300px',opacity:'0.8'},"slow");
div.animate({height:'100px',opacity:'0.4'},"slow");
div.animate({width:'100px',opacity:'0.8'},"slow");
});
$("#stop").click(function(){
$("div").stop();
});
});
</script> </head>
<body><button id=start>Έναρξη</button> <button id="stop">Σταμάτημα</button>
<div style="background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;">
</div></body></html>
Ο λόγος που σταματάει μόνο η τελευταία είναι διότι ο κώδικας διαβάζεται σειριακά οπότε το κουμπί με το στοπ διαβάζεται αφού έχουν διαβαστεί οι άλλες γραμμές κώδικα.
Αν βάλουμε πρώτα τον κώδικα με το κουμπί σταματάει όπου γίνει το κλικ.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#start").click(function(){
$("#stop").click(function(){
$("div").stop();
});
var div=$("div");
div.animate({height:'300px',opacity:'0.4'},"slow");
div.animate({width:'300px',opacity:'0.8'},"slow");
div.animate({height:'100px',opacity:'0.4'},"slow");
div.animate({width:'100px',opacity:'0.8'},"slow");
});
});
</script> </head>
<body><button id=start>Έναρξη</button> <button id="stop">Σταμάτημα</button>
<div style="background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;">
</div></body></html>
Εδώ έχουμε δηλώσει και ποιο animation θέλουμε να σταματήσει (το div).
Το ίδιο παράδειγμα με συγκεκριμένο id για το div
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<style>
#div1 {background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;}
</style>
<script>
$(document).ready(function(){
$("#start").click(function(){
$("#stop").click(function(){
$("#div1").stop();
});
var andiv=$("#div1");
andiv.animate({height:'300px',opacity:'0.4'},"slow");
andiv.animate({width:'300px',opacity:'0.8'},"slow");
andiv.animate({height:'100px',opacity:'0.4'},"slow");
andiv.animate({width:'100px',opacity:'0.8'},"slow");
});
});
</script> </head>
<body><button id=start>Έναρξη</button> <button id="stop">Σταμάτημα</button>
<div id="div1"></div>
</body></html>
Έναρξη και ταυτόχρονη διακοπή δύο animations:
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<style>
#div1 {background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;}
#div2 {background:blue;height:100px;width:100px;opacity:0.5;position:absolute;}
</style>
<script>
$(document).ready(function(){
$("#start").click(function(){
$("#stop").click(function(){
$("div").stop();
});
var andiv=$("#div1");
andiv.animate({height:'300px',opacity:'0.4'},"slow");
andiv.animate({width:'300px',opacity:'0.8'},"slow");
andiv.animate({height:'100px',opacity:'0.4'},"slow");
andiv.animate({width:'100px',opacity:'0.8'},"slow");
andiv=$("#div2");
andiv.animate({height:'300px',opacity:'0.4'},"slow");
andiv.animate({width:'300px',opacity:'0.8'},"slow");
andiv.animate({height:'100px',opacity:'0.4'},"slow");
andiv.animate({width:'100px',opacity:'0.8'},"slow");
});
});
</script> </head>
<body><button id=start>Έναρξη</button> <button id="stop">Σταμάτημα</button>
<div id="div1"></div>
<p> </p><p> </p><p> </p><p> </p><p> </p><p> </p>
<div id="div2"></div>
</body></html>
Ξεκίνημα σε σειρά, διακοπή του ενός
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<style>
#div1 {background:#98bf21;height:100px;width:100px;opacity:0.5;position:absolute;}
#div2 {background:blue;height:100px;width:100px;opacity:0.5;position:absolute;}
</style>
<script>
$(document).ready(function(){
$("#start").click(function(){
$("#stop").click(function(){
$("#div1").stop();
});
var andiv=$("#div1");
andiv.animate({height:'300px',opacity:'0.4'},"slow");
andiv.animate({width:'300px',opacity:'0.8'},"slow");
andiv.animate({height:'100px',opacity:'0.4'},"slow");
andiv.animate({width:'100px',opacity:'0.8'},"slow");
andiv=$("#div2");
andiv.animate({height:'300px',opacity:'0.4'},"slow");
andiv.animate({width:'300px',opacity:'0.8'},"slow");
andiv.animate({height:'100px',opacity:'0.4'},"slow");
andiv.animate({width:'100px',opacity:'0.8'},"slow");
});
});
</script> </head>
<body><button id=start>Έναρξη</button> <button id="stop">Σταμάτημα 1</button>
<div id="div1"></div>
<p> </p><p> </p><p> </p><p> </p><p> </p><p> </p>
<div id="div2"></div>
</body></html>
http://www.w3schools.com/jquery/jquery_stop.asp
CANVAS
Ορίζουμε ένα χώρο και μέσα σε αυτόν ζωγραφίζουμε ή εμφανίζουμε κάτι.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>περιγραφή</title>
</head>
<body>
περιεχόμενο......
<p><canvas id="myCanvas" width="200" height="100"
style="border:1px solid #000000;">
</canvas>
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="#FF0000";
ctx.fillRect(0,0,150,75);
</script>
</body>
</html>
Κάθε canvas πρέπει να έχει ένα id attribute. Με τον τρόπο αυτό ο browser γνωρίζει ποια άλλα στοιχεία της σελίδα (στο παράδειγμα το javascript) σχετίζονται με αυτό το canvas element. Απαραίτητα είναι επίσης τα width και height.
Η ζωγραφική μέσα σε ένα canvas element γίνεται με javascript. Στο παράδειγμα έχουμε:
var c=document.getElementById("myCanvas");
Βρίσκει που είναι το canvas με το οποίο έχει συσχετιστεί.
var ctx=c.getContext("2d");
Δίνουμε στη μέθοδο getContext το string 2d.
Το αντικείμενο (object) getContext("2d") ανήκει (περιέχεται) στην HTML 5 και διαθέτει τις δικές του μεθόδους και ιδιότητες (properties) για να ζωγραφίσει κανείς γραμμές, κουτιά, κύκλους, κείμενο, να εμφανίσει εικόνες κ.λπ.
ctx.fillStyle="#FF0000";
ctx.fillRect(0,0,150,75);
Τα παραπάνω ζωγραφίζουν ένα τετράγωνο. Η πρώτη δίνει το χρώμα και η δεύτερη ζωγραφίζει το τετράγωνο. Η fillStyle property μπορεί να είναι CSS color, gradient, ή pattern. Η μέθοδος fillRect (x,y,width,height) ζωγραφίζει το τεράγωνο, x= οριζόντιος άξονας y = κάθετος άξονας.
Γραμμές
ctx.moveTo(0,0);
ctx.lineTo(300,150);
ctx.stroke();
Τα fillStyle και fillRect του πρώτου παραδείγματος αντικαθιστούνται από τα παραπάνω.
Δηλώνουμε την αρχή της γραμμής (0,0), το τέλος (300,150) και χρησιμοποιούμε τη μέθοδο stroke για να τη ζωγραφίσουμε.
Το πάχος της γραμμής ορίζεται με: context.lineWidth = x; Όπου x είναι τα pixels.
Οι άκρες των γραμμών
Όταν βάζετε άκρη σε μια γραμμή το μήκος της θα αυξηθεί ανάλογα με το πάχος της. Έτσι μια γραμμή δηλωμένου μήκους 200 pixels και πάχους 10 pixels θα έχει μήκος 210 pixels.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// butt line cap (top line)
context.beginPath();
context.moveTo(200, canvas.height / 2 - 50);
context.lineTo(canvas.width - 200, canvas.height / 2 - 50);
context.lineWidth = 20;
context.strokeStyle = '#0000ff';
context.lineCap = 'butt';
context.stroke();
// round line cap (middle line)
context.beginPath();
context.moveTo(200, canvas.height / 2);
context.lineTo(canvas.width - 200, canvas.height / 2);
context.lineWidth = 20;
context.strokeStyle = '#0000ff';
context.lineCap = 'round';
context.stroke();
// square line cap (bottom line)
context.beginPath();
context.moveTo(200, canvas.height / 2 + 50);
context.lineTo(canvas.width - 200, canvas.height / 2 + 50);
context.lineWidth = 20;
context.strokeStyle = '#0000ff';
context.lineCap = 'square';
context.stroke();
</script>
</body>
</html>
Ένα πλήρες παράδειγμα με τετράγωνο
<!DOCTYPE HTML>
<html>
<head>
<style>
#myCanvas {
border: 1px solid #9C9898;
}
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.rect(188, 50, 200, 100);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
</script>
</body>
</html>
Κύκλοι - Αψίδες
Απλή Αψίδα
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="250"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.1 * Math.PI;
var endAngle = 1.9 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 15;
// line color
context.strokeStyle = 'black';
context.stroke();
</script>
</body>
</html>
Επεξήγηση
Εδώ έχει σημασία το false. Αν γίνει true το ημικύκλιο θα ζωγραφιστεί στην άλλη πλευρά του κύκλο.
ctx.beginPath();
ctx.arc(95,50,40,0,2*Math.PI);
ctx.stroke();
Η μέθοδος arc φτιάχνει τον κύκλο και η εμφάνισή του καθορίζεται από τις ink methods, όπως η stroke() ή η fill().
Η σύνταξη της arc είναι x,y (για το σημείο που θα βρίσκεται το κέντρο του κύκλου), r (radius) για την ακτίνα του κύκλου, sAngle το σημείο από όπου αρχίζει να ζωγραφίζεται ο κύκλος και eAngle το σημείο που τελειώνει ο κύκλος. Η αρχική (start Angle) και η τελική (end Angle) γωνία υπολογίζονται σε radians.
Radian είναι η αναλογία μεταξύ του μήκους ενός τόξου και της ακτίνας του κύκλου.
Μια πλήρης περιστροφή είναι 2π radians, οπότε για έναν πλήρη κύκλο η sAngle είναι 0 και η eAngle 2π που το γράφουμε 2*Math.PI.
Ο κύκλος αρχίζει να ζωγραφίζεται από το σημείο 0 και φυσικά μπορεί να μην θέλουμε να ζωγραφιστεί ολόκληρος.
ctx.beginPath();
ctx.arc(95,50,40,0,1.5*Math.PI);
ctx.stroke();
Εγώ έχουμε ? του κύκλου.
Ένας κύκλος
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
</script>
</body>
</html>
false και true στον κύκλο δεν έχει σημασία.
Ημικύκλιο
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.arc(288, 75, 70, 0, Math.PI, false);
context.closePath();
context.lineWidth = 5;
context.fillStyle = 'red';
context.fill();
context.strokeStyle = '#550000';
context.stroke();
</script>
</body>
</html>
Ενώσεις γραμμών
Αν οι γραμμές σας είναι πολύ λεπτές είναι πιθανόν να μη δείτε διαφορά στις ενώσεις οπότε στο παράδειγμα θα χρησιμοποιήσουμε χοντρές γραμμές.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// set line width for all lines
context.lineWidth = 25;
// miter line join (left)
context.beginPath();
context.moveTo(99, 150);
context.lineTo(149, 50);
context.lineTo(199, 150);
context.lineJoin = 'miter';
context.stroke();
// round line join (middle)
context.beginPath();
context.moveTo(239, 150);
context.lineTo(289, 50);
context.lineTo(339, 150);
context.lineJoin = 'round';
context.stroke();
// bevel line join (right)
context.beginPath();
context.moveTo(379, 150);
context.lineTo(429, 50);
context.lineTo(479, 150);
context.lineJoin = 'bevel';
context.stroke();
</script>
</body>
</html>
Στρογγυλεμένες γωνίες
Η βάση για τη δημιουργία της στρογγυλεμένης γωνίας είναι το:
context.arcTo(controlX,controlY,endX,endY,radius);
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 200;
var rectHeight = 100;
var rectX = 189;
var rectY = 50;
var cornerRadius = 50;
context.beginPath();
context.moveTo(rectX, rectY);
context.lineTo(rectX + rectWidth - cornerRadius, rectY);
context.arcTo(rectX + rectWidth, rectY, rectX + rectWidth, rectY + cornerRadius, cornerRadius);
context.lineTo(rectX + rectWidth, rectY + rectHeight);
context.lineWidth = 5;
context.stroke();
</script>
</body>
</html>
Όλη η δουλειά γίνεται από το:
context.arcTo(rectX + rectWidth, rectY, rectX + rectWidth, rectY + cornerRadius, cornerRadius);
Ουσιαστικά βλέπουμε μια κάθετη και μια οριζόντια γραμμή που τις ενώνει ένα τμήμα περιμέτρου κύκλου.
Rounded corners box
<!DOCTYPE html>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>περιγραφή</title>
</head>
<body>
περιεχόμενο......
<p><canvas id="myCanvas" width="400" height="400"
style="border:1px solid #000000;">
</canvas>
<script type="text/javascript">
var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");
var x = 50;
var y = 50
var width = 200;
var height = 80;
roundRect(context, x, y, width, height,25,'true','true','#8ED6FF','blue');
function roundRect(context, x, y, width, height, radius, fill, stroke,fillColor,strokeColor) {
if (typeof stroke == "undefined" ) {
stroke = true;
}
if (typeof radius === "undefined") {
radius = 5;
}
context.beginPath();
context.moveTo(x + radius, y);
context.lineTo(x + width - radius, y);
context.quadraticCurveTo(x + width, y, x + width, y + radius);
context.lineTo(x + width, y + height - radius);
context.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
context.lineTo(x + radius, y + height);
context.quadraticCurveTo(x, y + height, x, y + height - radius);
context.lineTo(x, y + radius);
context.quadraticCurveTo(x, y, x + radius, y);
context.closePath();
if (stroke) {
context.strokeStyle = strokeColor;
context.stroke();
}
if (fill) {
context.fillStyle = fillColor;
context.fill();
}
}
</script></body></html>
clearRect
Αυτή η μέθοδος χρησιμοποιείται για να καθαρίσουμε (αδειάσουμε) τα pixels από ένα προϋπάρχον σχήμα που βρίσκεται ήδη εκεί.
<!DOCTYPE html><html><body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(0,0,300,150);
ctx.clearRect(20,20,100,50);
</script></body></html>
Σε κύκλο θα γίνει:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
context.clearRect(centerX,centerY ,centerX,centerY );
</script>
</body>
</html>
Κείμενο
ctx.font="30px Arial";
ctx.fillText("Καλό Απόγευμα",10,50);
(Δεν χωράει όλο οπότε εμφανίζεται κομμένο).
Η font property ορίζει τη γραμματοσειρά και η fillText method γράφει τα γράμματα. Για να γίνει αυτό δίνουμε το κείμενο και τα x,y του σημείου που βρίσκεται κάτω αριστερά του πρώτου γράμματος (αν το πρώτο γράμμα είναι π.χ. το Υ θα είναι το κάτω αριστερά σημείο που θα γράφαμε αν ήταν Α δηλαδή πιο αριστερά από τη βάση του)..
ctx.strokeText("Καλό Βράδυ",10,50);
Αντί για fillText μπορώ να βάλω strokeText οπότε έχουμε ορατό μόνο το περίγραμμα
Στοίχιση κειμένου
Η στοίχιση γίνεται με λίγο περίεργο τρόπο. Ως βάση έχουμε μια ιδεατή κάθετη γραμμή ση θέση x που δηλώσαμε στη fillText() ή στην strokeText().. Στο παράδειγμα που ακολουθεί έχει γίνει ορατή η γραμμή.
<!DOCTYPE html><head><meta charset=utf-8>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath(); /* Έχω πολλαπλές γραμμές. Αν δεν βάλω context.beginPath() τότε το σύστημα θα νομίζω πως έχω μια γραμμή και θα δίνει το ίδιο χρώμα (το τελευταίο που δήλωσα) παντού.*/
var x = canvas.width / 2;
var y = canvas.height / 2;
context.font = '20pt Calibri';
context.textAlign = 'center';
context.fillStyle = 'blue';
context.fillText('CENTER', x, y);
context.strokeStyle = 'blue';
context.moveTo(x,0);
context.lineTo(x,canvas.height);
context.stroke();
context.beginPath();
context.fillStyle = 'red';
x = canvas.width / 4;
y = canvas.height / 4;
context.textAlign = 'left';
context.fillText('left', x, y);
context.moveTo(x,0);
context.lineTo(x,canvas.height);
context.strokeStyle = 'red';
context.stroke();
context.beginPath();
context.fillStyle = 'yellow';
x = canvas.width / 3 + canvas.width / 3;
y = canvas.height / 3 + canvas.height / 3;
context.textAlign = 'right';
context.fillText('right', x, y);
context.strokeStyle = 'yellow';
context.moveTo(x,0);
context.lineTo(x,canvas.height);
context.stroke();
context.beginPath();
context.fillStyle = 'lime';
x = canvas.width / 6;
y = canvas.height / 6;
context.textAlign = 'start';
context.fillText('start', x, y);
context.strokeStyle = 'lime';
context.moveTo(x,0);
context.lineTo(x,canvas.height);
context.stroke();
context.beginPath();
context.fillStyle = 'aqua';
x = canvas.width / 5 + canvas.width / 5;
y = canvas.height / 5 + canvas.height / 5;
context.textAlign = 'end';
context.fillText('end', x, y);
context.strokeStyle = 'aqua';
context.moveTo(x,0);
context.lineTo(x,canvas.height);
context.stroke();
</script> </body>
Γενικό παράδειγμα κειμένου
<!DOCTYPE HTML>
<html>
<head><meta charset=utf-8>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 80;
var y = 110;
context.font = 'italic 60pt Calibri'; // Η γραμματοσειρά, το είδος και το μέγεθος των γραμμάτων.
context.textBaseline = 'middle';
/* Οι τιμές που παίρνει είναι top (κάτω!), hanging (δεν υποστηρίζεται ακόμη), middle, alphabetic, ideographic (δεν υποστηρίζεται ακόμη), και bottom (πάνω!). Αν δεν έχει δηλωθεί το textBaseline property είναι alphabetic */
context.fillStyle = 'blue'; // Το χρώμα των γραμμάτων
context.fillText('Γεια σας!', x, y); // Το κείμενο
/* O κώδικας για εμφάνιση περιγράμματος γραμμάτων
context.lineWidth = 3; // Το πάχος της γραμμής γύρω από τα γράμματα.
context.strokeStyle = 'blue';
context.strokeText('Γεια σας!', x, y);
Αν θέλετε μπορείτε να χρησιμοποιήσετε και fill και stroke αλλά τότε είναι προτιμότερο να καλέσετε πρώτα την fill ώστε να γίνει καλύτερο render του πάχους του κειμένου.
*/
</script>
</body>
</html>
Πλέγμα στιγμών
Ένας εύκολος τρόπος να βλέπουμε σε ποιο σημείο βρίσκονται τα σχήματά μας είναι να δημιουργήσουμε ένα προσωρινό πλέγμα με τελείες σε τακτά διαστήματα.
<!DOCTYPE HTML>
<html>
<head><meta http-equiv=Content-Type content="text/html; charset=utf-8"> <title>map</title>
</head>
<body>
<div align="left">
<canvas id="myCanvas" width="600" height="500">You need a browser with HTML 5 Canvas support to see this animated map</canvas>
</div>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
showGrid();
function showGrid () {
/* A grid to use for design purposes. */
for (var w=0; w<canvas.width; w++) {
for (var h=0; h<canvas.height; h++) {
if ( h % 20 == 0 && w % 20 == 0) {
context.beginPath();
context.rect(w, h, 2, 2);
context.fillStyle = "red";
context.fill();
}
}
}
}
</script></body></html>
Μέτρηση του πλάτους του κειμένου
<!DOCTYPE HTML>
<html>
<head> <head><meta charset=utf-8>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2 - 10;
var text = 'Σταθεροποιητικά κινούνται οι τιμές';
context.font = '30pt Calibri';
context.textAlign = 'center';
context.fillStyle = 'blue';
context.fillText(text, x, y);
// get text metrics
var metrics = context.measureText(text);
var width = metrics.width;
context.font = '20pt Calibri';
context.textAlign = 'center';
context.fillStyle = '#555';
context.fillText('(' + width + 'px wide)', x, y + 40);
</script>
</body>
</html>
Το ύψος δεν χρειάζεται να το μετρήσουμε γιατί είναι το size της font.
Word Wrap
Χάρη στη measureText μπορούμε πλέον να φτιάξουμε μια συνάρτηση για να κάνουμε word wrap.
<!DOCTYPE HTML>
<html>
<head> <head><meta charset=utf-8>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function wrapText(context, text, x, y, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '';
for(var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if(testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var maxWidth = 500;
var lineHeight = 25;
var x = (canvas.width - maxWidth) / 2;
var y = 60;
var text = 'All the world \'s a stage: Σταθεροποιητικές τάσεις επικρατούν στο Χρηματιστήριο τη Δευτέρα, με τους επενδυτές να αναμένουν πως οι υπουργοί Οικονομικών της Ευρωζώνης θα καταλήξουν σε συμφωνία για την Ελλάδα στο κρίσιμο σημερινό Eurogroup των Βρυξελλών. ';
context.font = '16pt Calibri';
context.fillStyle = '#333';
wrapText(context, text, x, y, maxWidth, lineHeight);
</script>
</body>
</html>
Gradients
Για χρώμα που φθίνει (ντεγκραντέ) έχουμε:
Δημιουργία του γραμμικού gradient
var grd=ctx.createLinearGradient(0,0,200,0);
grd.addColorStop(0,"red");
grd.addColorStop(1,"white");
Έχουμε 2 x,y. Το πρώτο μας δίνει το σημείο αρχής του linear gradient (το πάνω αριστερά) και το δεύτερο το τέλος (πάνω δεξιά).
Η μέθοδος addColorStop περιέχει ένα νούμερο από 0.0 έως 1.0 για το σημείο που θα ξεκινήσει (στην πρώτη αναφορά) και θα τελειώσει (στη δεύτερη) το gradient. Περιέχει επίσης το χρώμα αρχής και τέλους σε μορφή αποδεκτή από CSS (συνήθως δεκαεξαδικό κωδικό).
Τοποθέτηση του χρώματος
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80);
Το canvas μας θα πάει από το 10,10 έως το 150,80 δηλαδή θα είναι μικρότερο από το 200,100 που τελειώνει το canvas μας (μπορεί να έχει διαστάσεις μέχρι και όσες ολόκληρο το canvas).
Παράδειγμα με πολλαπλά addColorStop
var grd=ctx.createLinearGradient(0,0,200,0);
grd.addColorStop(0,"black");
grd.addColorStop("0.3","magenta");
grd.addColorStop("0.5","blue");
grd.addColorStop("0.6","green");
grd.addColorStop("0.8","yellow");
grd.addColorStop(1,"red");
// Fill with gradient
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80);
Προσέξτε πως αν το τέλος της fillRect είναι στο 150 το gradient τελειώνει σε κίτρινο. Στα 180 βλέπουμε και κόκκινο. Στα 100 βλέπουμε μέχρι μπλε. Το μπλε εμφανίζεται στο 0.5 δηλαδή 200/100 = στο μισό του gradient. Θα το δούμε και πιο πριν (π.χ. στα 90) αφού το magenta πρέπει να τελειώσει σε blue αλλά γενικά χρώματα που έχουν σημείο εμφάνισης στο gradient μετά από το τέλος του τετραγώνου δεν θα εμφανιστούν.
Πλήρες παράδειγμα με Linear Gradient
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.rect(0, 0, canvas.width, canvas.height);
// add linear gradient
var grd = context.createLinearGradient(0, 0, canvas.width, canvas.height);
// light blue
grd.addColorStop(0, '#8ED6FF');
// dark blue
grd.addColorStop(1, '#004CB3');
context.fillStyle = grd;
context.fill();
</script>
</body>
</html>
Ακτινωτό Gradient
var grd=ctx.createRadialGradient(75,50,5,90,60,100);
grd.addColorStop(0,"red");
grd.addColorStop(1,"white");
Εδώ στην πραγματικότητα έχουμε 2 κύκλους. Ο εσωτερικός έχει κέντρο στο 75,50 και ακτίνα 5, ενώ ο εξωτερικός έχει κέντρο στο 90,60 και ακτίνα 100, (Συνήθως βέβαια και οι δύο κύκλοι θα έχουν το ίδιο κέντρο).
Η προσθήκη του χρώματος γίνεται με τον ίδιο τρόπο όπως και στο γραμμικό.
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80);
Για να δείτε τους κύκλος προσθέστε:
ctx.arc(75,50,5,0,2*Math.PI);
ctx.stroke();
ctx.arc(90,60,100,0,2*Math.PI);
ctx.stroke();
Πλήρες παράδειγμα με Ακτινωτό Gradient
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.rect(0, 0, canvas.width, canvas.height);
// create radial gradient
var grd = context.createRadialGradient(238, 50, 10, 238, 50, 300);
// light blue
grd.addColorStop(0, '#8ED6FF');
// dark blue
grd.addColorStop(1, '#004CB3');
context.fillStyle = grd;
context.fill();
</script>
</body>
</html>
Εισαγωγή εικόνας
<!DOCTYPE html>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>περιγραφή</title>
</head>
<body>
περιεχόμενο......
<p>Εικόνα:</p>
<img id="eeei" src="http://www.eeei.gr/images/eeeil1.jpg" alt="eeei" width="241" height="98"><p>Canvas:</p>
<canvas id="myCanvas" width="250" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("eeei");
ctx.drawImage(img,10,10);
</script>
</body></html>
Όλη η δουλειά γίνεται από τη μέθοδο drawImage(img,x,y). Τα x και y αναφέρονται στο πάνω αριστερά σημείο της εικόνας και τη θέση που θα έχει μέσα στο canvas.
Image με συγκεκριμένες διαστάσεις
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 188;
var y = 30;
var width = 241;
var height = 98;
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, x, y, width, height);
};
imageObj.src = 'http://www.eeei.gr/images/eeeil1.jpg';
</script>
</body>
</html>
Crop Image
Σύνταξη:
context.drawImage(imageObj, sx, sy, sw, sh, dx, dy, dw, dh);
Παίρνει ένα τμήμα της εικόνας και εμφανίζει μόνο αυτό σε διαστάσεις που ορίζουμε. Το τμήμα θα βγεί από το ορατό μέρος της εικόνας μετά το dx dy
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw cropped image
var sourceX = 150; // Αλλάξτε το σε 0 και σε 50 για να δείτε διαφορά.
var sourceY = 0;
var sourceWidth = 241;
var sourceHeight = 98;
var destWidth = sourceWidth; // Δοκιμάστε και /2 και επί 2.
var destHeight = sourceHeight; // Δοκιμάστε και /2 και επί 2.
var destX = canvas.width / 2 - destWidth / 2;
var destY = canvas.height / 2 - destHeight / 2;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
};
imageObj.src = 'http://www.eeei.gr/images/eeeil1.jpg';
</script>
</body>
</html>
Image για φόντο στο Canvas
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
var pattern = context.createPattern(imageObj, 'repeat');
context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle = pattern;
context.fill();
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/wood-pattern.png';
</script>
</body>
</html>
Image Loader
Όταν έχουμε πολλές εικόνες είναι προτιμότερο να τις φορτώνουμε και μετά να τις τοποθετούμε στο Canvas.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var sources = {
eeei: 'http://www.eeei.gr/images/eeeil1.jpg',
pattern: 'http://www.gepiti.com/tests/wood-pattern.png',
};
loadImages(sources, function(images) {
context.drawImage(images.eeei, 100, 30, 241, 98);
context.drawImage(images.pattern, 342, 34, 380, 271);
/* Η wood pattern δεν χωράει όλη και εμφανίζεται όσο χωράει. Αλλάξτε το ύψος του canvas σε 400 και το πλάτος σε 678 για να δείτε περισσότερη. */
});
</script>
</body>
</html>
Αναλυτικός image loader
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="500">You need a browser with HTML 5 Canvas support to see this animated map</canvas>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var images = {};
/* Associative Array with all the images used. */
function loadImages(sources, callback) {
/* Loader for all images used. */
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
/* Count images to load. */
for(var src in sources) {
loadedImages++;
/* Counting every image added to the image objects array*/
images[src] = new Image();
/* When the current image finishes loading execute the function.*/
images[src].onload = function() {
if(loadedImages >= numImages) {
callback(images);
}
/* If loadedImages more or equal to numImages call and load all.*/
};
images[src].src = sources[src];
images[src].width = imageWidths[src];
images[src].height = imageHeights[src];
}
}
var sources = {
/* Associative Array with all the sources of images used. */
hopliteImage: 'http://www.gepiti.com/tests/images/hoplite_face_right.png',
persianImage: 'http://www.gepiti.com/tests/images/persian_spearer_face_left.png',
northImage: 'http://www.gepiti.com/tests/images/north.png',
};
var imageWidths = {
/* Associative Array with all the widths of images used. */
hopliteImage: 18,
persianImage: 17,
northImage: 20,
};
var imageHeights = {
/* Associative Array with all the heights of images used. */
hopliteImage: 39,
persianImage: 47,
northImage: 22,
};
loadImages(sources, function(images) {
context.drawImage(images.hopliteImage, 50, 100, images.hopliteImage.width, images.hopliteImage.height);
context.drawImage(images.persianImage, 80, 200, images.persianImage.width, images.persianImage.height);
context.drawImage(images.northImage, 100, 300, images.northImage.width, images.northImage.height);
});
</script>
</body>
</html>
Γραμμή αποτελούμενη από άλλες γραμμές
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(100, 20);
// line 1
context.lineTo(200, 160);
// quadratic curve
context.quadraticCurveTo(230, 200, 250, 120);
// bezier curve
context.bezierCurveTo(290, -40, 300, 200, 400, 150);
// line 2
context.lineTo(500, 90);
context.lineWidth = 5;
context.strokeStyle = 'blue';
context.stroke();
</script>
</body>
</html>
Για να φτιάξουμε τη γραμμή μας δημιουργούμε ένα path το οποίο αποτελείται από sub-paths.
context.beginPath();
Το πρώτο sub-path είναι μια ευθεία γραμμή
Ξεκινάει:
context.moveTo(100, 20);
Καταλήγει:
context.lineTo(200, 160);
Συνεχίζει ως quadraticCurve
context.quadraticCurveTo(230, 200, 250, 120);
Η σύνταξη είναι:
context.quadraticCurveTo(controlX, controlY, endX, endY);
Η καμπύλη αυτή ορίζεται από τις συντεταγμένες του control point και του end point.
Αλλάξτε το controlX σε 330 για να δείτε τη διαφορά.
Στο επόμενο sub-path η καμπύλη αλλάζει σε Bezier.
context.bezierCurveTo(290, -40, 300, 200, 400, 150);
Η σύνταξη είναι:
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
Εδώ έχουμε δύο control points.
Και τελειώνουμε πάλι με ευθεία γραμμή:
context.lineTo(500, 90);
Arc δεν έχουμε σε αυτή τη γραμμή και η σύνταξή της υπάρχει παραπάνω.
Graph με Canvas
Ας ξεκινήσουμε με δύο functions για να φτιάχνουμε τις μπάρες και τις γραμμές
<!DOCTYPE html><head><meta charset=utf-8>
<style>
#graphSpace { margin-left:80px; }
</style><script type="text/javascript">
function graph() {
var graphCanvas = document.getElementById('graphSpace');
/* Καλούμε το element για να βεβαιωθούμε πως είναι διαθέσιμο στο DOM (δηλαδή πως το υποστηρίζει ο browser) */
if (graphCanvas && graphCanvas.getContext) {
var context = graphCanvas.getContext('2d');
/* Ανοίγουμε ένα 2D context μέσα στο canvas, δηλαδή του λέμε πως θα δημιουργήσουμε ένα δυσδιάστατο γραφικό (στο μέλλον θα μπορούμε να δημιουργήσουμε και γραφικά σε 3 διαστάσεις. */
drawLine(context, 0, 0, 100, 100);
context.fillStyle = "#b90000"; // Αν δεν δηλωθεί αυτό θα είναι μαύρο.
drawRectangle(context, 100, 100, 100, 100, true);
}
}
function drawLine(contextO, startx, starty, endx, endy) {
contextO.beginPath();
contextO.moveTo(startx, starty);
contextO.lineTo(endx, endy);
contextO.closePath();
contextO.stroke();
}
function drawRectangle(contextO, x, y, w, h, fill) {
contextO.beginPath();
contextO.rect(x, y, w, h);
contextO.closePath();
contextO.stroke();
if (fill) contextO.fill();
}
</script></head><body onLoad="graph();">
<canvas id="graphSpace" width="800" height="400"></canvas>
</body></html>
Το πλήρες παράδειγμα:
<!DOCTYPE html><head><meta charset=utf-8>
<style>
#graphSpace { margin-left:80px; }
</style>
<script type="text/javascript">
function graph() {
var graphCanvas = document.getElementById('graphSpace');
if (graphCanvas && graphCanvas.getContext) {
var context = graphCanvas.getContext('2d');
// Τα δεδομένα για το Bar chart
var data = new Array(5);
data[0] = "Πάτρα,200";
data[1] = "Λάρισα,120";
data[2] = "Ηράκλειο,80";
data[3] = "Θεσσαλονίκη,230";
data[4] = "Αθήνα,345";
// Draw the bar chart
drawBarChart(context, data, 50, 100, (graphCanvas.height - 20), 50);
}
}
// drawBarChart - H function που φτιάχνει το bar chart με τα δεδομένα που έχουμε
function drawBarChart(context, data, startX, barWidth, chartHeight, markDataIncrementsIn) {
/* Λαμβάνει την context (με ό,τι περιέχει) την data array το σημείο που θα ξεκινήσει (οριζόντια θέση), το πλάτος κάθε μπάρας, το ύψος του chart (όσο το canvas - 20 pixels) και κάθα ποιο ποσό θα δηλώνουμε τιμές.*/
// Ξεκινάμε ζωγραφίζοντας τους άξονες x και y
/* Ορίζουμε το πλάτος της γραμμής. Στο πιο πάνω παράδειγμα δεν το κάναμε οπότε πήρε την default τιμή.*/
context.lineWidth = "1.0";
/* Από αυτό το σημείο θα ξεκινάει η οριζόντια γραμμή */
var startY = 380;
/* Ο κάθετος άξονας*/
drawLine(context, startX, startY, startX, 30);
/* Ο οριζόντιος άξονας */
drawLine(context, startX, startY, 570, startY);
/* Τώρα θα ζωγραφίσουμε τις μπάρες και γι' αυτές δεν θέλουμε γραμμή στο περιθώριο.*/
context.lineWidth = "0.0";
/* Στη maxValue θα φυλάω τη μεγαλύτερη τιμή που έχει η βάση μου ώστε να ξέρω πόσο ψηλό είναι το υψηλότερο bar.*/
var maxValue = 0;
for (var i=0; i<data.length; i++) {
/* Διαβάζουμε ένα ένα τα elements της array και λαμβάνουμε τα δεδομένα.*/
var values = data[i].split(",");
var name = values[0];
var height = parseInt(values[1]);
/* Αν βρήκα μεγαλύτερη τιμή από αυτή που είχα ήδη αλλάζω την maxValue */
if (parseInt(height) > parseInt(maxValue)) maxValue = height;
/* Τώρα δίνουμε δεδομένα στο chart. Ξεκινάμε με το χρώμα της μπάρας*/
context.fillStyle = "#b90000";
// Μπορώ να δηλώσω χρώμα και με το όνομά του: context.fillStyle = "yellow";
/*Ζωγραφίζουμε την μπάρα*/
drawRectangle(context, startX + (i * barWidth) + i, (chartHeight - height), barWidth, height, true);
/* Βάζουμε τίτλο στον άξονα x */
/* H στοίχιση του κειμένου που θα είναι δεξιά του δηλωμένου σημείου αφού έχουμε δηλώσει left (παίρνει χρόνο να συνηθίσει κανείς αυτόν τον περίεργο τρόπο στοίχισης).*/
context.textAlign = "left";
/*Το χρώμα που θα έχει το κείμενο (το όνομα της πόλης)*/
context.fillStyle = "#000";
/* Γράφουμε το όνομα της πόλης*/
context.fillText(name, startX + (i * barWidth) + i, chartHeight + 10, 200);
}
/* Bάζουμε τις τιμές στον άξονα y */
/* Η Math.ceil() στρογγυλοποιεί ένα νούμερο στον ανώτερο ακέραιο. π.χ. Math.ceil(1.4) = 2*/
var numMarkers = Math.ceil(maxValue / markDataIncrementsIn);
context.textAlign = "right";
context.fillStyle = "#000";
var markerValue = 0;
for (var i=0; i<numMarkers; i++) {
context.fillText(markerValue, (startX - 5), (chartHeight - markerValue), 50);
markerValue += markDataIncrementsIn;
}
}
// drawLine function
function drawLine(contextO, startx, starty, endx, endy) {
contextO.beginPath();
contextO.moveTo(startx, starty);
contextO.lineTo(endx, endy);
contextO.closePath();
contextO.stroke();
}
// drawRectanle function
function drawRectangle(contextO, x, y, w, h, fill) {
contextO.beginPath();
contextO.rect(x, y, w, h);
contextO.closePath();
contextO.stroke();
if (fill) contextO.fill();
}
</script>
</head>
<body onLoad="graph();">
<article>
<h1>Πόλεις</h1>
<canvas id="graphSpace" width="800" height="400"></canvas>
</article>
</body>
</html>
Ακανόνιστο σχήμα
Για να δημιουργήσουμε ένα ιδιαίτερο σχήμα θα το σχηματίσουμε από γραμμές που εμείςθα δημιουργήσουμε και θα το κλείσουμε χρησιμοποιώντας την closePath()
<!DOCTYPE HTML>
<html>
<head><meta charset=utf-8><style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style></head><body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// Έναρξη custom shape
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
// Ολοκλήρωση custom shape
context.closePath();
context.lineWidth = 5;
context.strokeStyle = 'blue';
context.stroke();
// Τετραγωνάκι
context.beginPath();
context.rect(170, 80, 2, 2);
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
</script></body></html>
Το τετραγωνάκι φυσικά δεν χρειάζεται και για να είναι σωστό το σχήμα πρέπει να βγει αλλά υπάρχει για να μας δείχνει το σημείο από το οποίο ξεκινάει το σχήμα.
SVG (Scalable Vector Graphics)
• Τα γραφικά αυτά δηλώνονται σε μορφή XML. Το SVG στην πραγματικότητα αποτελεί μια γλώσσα περιγραφής 2D graphics σε XML.
• Επειδή είναι διανυσματικά δεν χάνουν σε ποιότητα στα zoom-in και τα zoom-out.
• Μπορούν να είναι animated
Κύκλος SVG
<body>
<h2>HTML5 SVG Circle</h2>
<svg id="svgelem" height="200" xmlns="http://www.w3.org/2000/svg">
<circle id="redcircle" cx="50" cy="50" r="50" fill="red" />
</svg>
</body>
cx="x" cy="y" r="ακτίνα" fill="χρώμα γεμίσματος"
Ορθογώνιο SVG
<body>
<h2>HTML5 SVG Rectangle</h2>
<svg id="svgelem" height="200" xmlns="http://www.w3.org/2000/svg">
<rect id="redrect" width="300" height="100" fill="red" />
</svg>
</body>
Γραμμή SVG
<body>
<h2>HTML5 SVG Line</h2>
<svg id="svgelem" height="200" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="0" x2="200" y2="100"
style="stroke:red;stroke-width:2"/>
</svg>
</body>
Δίνουμε συντεταγμένες αρχής και τέλους, χρώμα και πλάτος γραμμής.
Έλλειψη SCG
<body>
<h2>HTML5 SVG Ellipse</h2>
<svg id="svgelem" height="200" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="100" cy="50" rx="100" ry="50" fill="red" />
</svg>
cx="x" y="50" (θέση του κέντρου της έλλειψης) ακτίνα x="100" (οριζόντια) ακτίνα y="50" (κάθετη).
Και ένα παράδειγμα με 3 ελλείψεις μερικώς επικαλυπτόμενες.
<h2>HTML5 SVG Ellipses</h2>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<ellipse cx="240" cy="100" rx="220" ry="30" style="fill:purple"/>
<ellipse cx="220" cy="70" rx="190" ry="20" style="fill:lime"/>
<ellipse cx="210" cy="45" rx="170" ry="15" style="fill:yellow"/>
</svg>
Δύο ελλείψεις η μία μέσα στην άλλη
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow"/>
<ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white"/>
</svg>
Πολύγωνό SVG
<h2>HTML5 SVG Polygon</h2>
<svg id="svgelem" height="200" xmlns="http://www.w3.org/2000/svg">
<polygon points="20,10 300,20, 170,50" fill="red" />
</svg>
Οι θέσεις ξεκινάνε από αριστερά και δηλώνονται με τη φορά των δεικτών του ρολογιού.
Polyline (ακολουθία ευθειών γραμμών)
<h2>HTML5 SVG Polyline</h2>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180"
style="fill:none;stroke:black;stroke-width:3" />
</svg>
Δηλώνουμε τις θέσεις κάθε σημείου της ακολουθίας
Στο επόμενο παράδειγμα δημιουργούμε σκαλοπάτια:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160"
style="fill:white;stroke:red;stroke-width:4"/>
</svg>
Gradient
Θα κατασκευάσουμε μια έλλειψη.
<h2>HTML5 SVG Gradient Ellipse</h2>
<svg id="svgelem" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="gradient" cx="50%" cy="50%" r="50%"
fx="50%" fy="50%">
<stop offset="0%" style="stop-color:rgb(200,200,200);
stop-opacity:0"/>
<stop offset="100%" style="stop-color:rgb(0,0,255);
stop-opacity:1"/>
</radialGradient>
</defs>
<ellipse cx="100" cy="50" rx="100" ry="50"
style="fill:url(#gradient)" />
</svg>
Πρώτα δηλώνουμε το gradient και μετά την έλλειψη η οποία στη δήλωσή της αναφέρει και πως θα γεμίσει με χρώμα. Και εδώ έχουμε stop όπως και στο javascript gradient αλλά δηλωμένα με ποσοστά.
Οι cx, cy and r attributes δηλώνουν τον εξωτερικό κύκλο και τα fx και fy τον εσωτερικό.
Να και ένα ωραίο εφέ με ασύμμετρο gradient.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<radialGradient id="grad1" cx="20%" cy="30%" r="30%" fx="50%" fy="50%">
<stop offset="0%" style="stop-color:rgb(255,255,255);
stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
</radialGradient>
</defs>
<ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" />
</svg>
Ο εξωτερικός κύκλος είναι πιο αριστερά από τον εσωτερικό οπότε χώρος για gradient υπάρχει μόνο προς την πάνω αριστερή πλευρά.
Να και ένα γραμμικό gradient σε έλλειψη.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<linearGradient id="grad2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="10%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
<stop offset="40%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="60%" style="stop-color:rgb(0,150,50);stop-opacity:1" />
<stop offset="90%" style="stop-color:rgb(0,255,255);stop-opacity:1" />
</linearGradient>
</defs>
<ellipse cx="200" cy="70" rx="100" ry="65" fill="url(#grad2)" />
</svg>
Summary – Details
H details χρησιμοποιείται για αυτόματα άνοιγμα περισσότερου περιεχομένου.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
</head><body>
<details open="open">
<p>Αν ο browser υποστηρίζει τα details (π.χ. Chrome) θα πρέπει να μπορείτε να ανοίξετε και να κλείσετε το κείμενο.</p></details>
</body></html>
Αν έχουμε σκέτο <details> τότε το κείμενο δεν θα φαίνεται αλλά θα ανοίξει μετά από click του χρήστη.
<!DOCTYPE html>
<html><head><meta charset="utf-8">
</head><body>
<details>
<p>Αν ο browser υποστηρίζει τα details (π.χ. Chrome) θα πρέπει να μπορείτε να ανοίξετε και να κλείσετε το κείμενο.</p><img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98"></details>
</body></html>
Για να ορίσουμε εμείς το κείμενο που θα φαίνεται χρησιμοποιούμε την summary που πρέπει να είναι το πρώτο element που δηλώνεται μέσα στην <details>
<!DOCTYPE html>
<html><head><meta charset="utf-8">
</head><body>
<details>
<summary>Πάτα εδώ για περισσότερα</summary
<p>Αν ο browser υποστηρίζει τα details (π.χ. Chrome) θα πρέπει να μπορείτε να ανοίξετε και να κλείσετε το κείμενο.</p><img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" width="241" height="98"></details>
</body></html>
MathML
Χρησιμοποιείται για μαθηματικές διατυπώσεις
mrow
ομαδοποιεί οριζόντια ομάδες διατυπώσεων
mi
ορίζει ένα αναγνωριστικό (identifier) για παράδειγμα το όνομα μιας μεταβλητής, σταθεράς, συνάρτησης κ.λπ. Αν το όνομα έχει μήκος ένα χαρακτήρα γίνεται αυτόματα italic.
mo
Χρησιμοποιείται για τελεστές (π.χ. το +) διαχωριστικά όπως οι αγκύλες.
mn
Χρησιμοποιείται για αριθμούς. Για παράδειγμα <mn>3.14</mn>. Αν θέλεις να δηλώσεις το π θα δηλωθεί ως <mi>PI</mi> και όχι με την mn
Ένα απλό άθροισμα
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Pythagorean theorem</title>
</head>
<body>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<mrow>
<mi>x</mi>
<mo>+</mo>
<mi>y</mi>
</mrow>
<mo>=</mo>
<mn>2</mn>
</mrow>
</math>
</body>
</html>
Κλάσμα
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mfrac>
<mrow>
<mi>x</mi>
<mo>-</mo>
<mn>1</mn>
</mrow>
<mn>100</mn>
</mfrac>
</math>
Τετραγωνική ρίζα
<msqrt>
<mi>x</mi>
<mo>+</mo>
<mi>y</mi>
</msqrt>
msub
Κατώτερο κείμενο (subscript):
<msub>
<mi>x</mi>
<mi>i</mi>
</msub>
msup
Εκθέτης (superscript):.
<msup>
<mi>x</mi>
<mi>j</mi>
</msup>
msubsup
Και εκθέτης και κατώτερο κείμενο:
<msubsup>
<mi>x</mi>
<mi>i</mi>
<mi>j</mi>
</msubsup>
munder
Κεντραρισμένος εκθέτης (underscript) :
<munder>
<mi>x</mi>
<mo>─</mo>
</munder>
mover
Κεντραρισμένο κάτω κείμενο (overscript)
<mover>
<mi>v</mi>
<mo>→</mo>
</mover>
munderover
Και τα δύο μαζί:
<munderover>
<mi>x</mi>
<mi>a</mi>
<mi>b</mi>
</munderover>
Πίνακες:
<mrow>
<mo>[</mo>
<mtable>
<mtr>
<mtd>
<mn>1</mn>
</mtd>
<mtd>
<mn>0</mn>
</mtd>
<mtd>
<mn>0</mn>
</mtd>
</mtr>
<mtr>
<mtd>
<mn>0</mn>
</mtd>
<mtd>
<mn>1</mn>
</mtd>
<mtd>
<mn>0</mn>
</mtd>
</mtr>
<mtr>
<mtd>
<mn>0</mn>
</mtd>
<mtd>
<mn>0</mn>
</mtd>
<mtd>
<mn>1</mn>
</mtd>
</mtr>
</mtable>
<mo>]</mo>
</mrow>
Άθροισμα τετραγώνων.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Πυθαγόρειο Θεώρημα</title>
</head>
<body>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<msup><mi>a</mi><mn>2</mn></msup>
<mo>+</mo>
<msup><mi>b</mi><mn>2</mn></msup>
<mo>=</mo>
<msup><mi>c</mi><mn>2</mn></msup>
</mrow>
</math>
</body>
</html>
Προσθήκη ελεύθερου κειμένου:
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<mtext>if</mtext>
<mspace depth="0.5ex" height="0.5ex" width="1ex"/>
<mrow>
<mi>x</mi>
<mo>=</mo>
<mi>y</mi>
</mrow>
<mspace depth="0.5ex" height="0.5ex" width="1ex"/>
<mtext>then</mtext>
<mspace depth="0.5ex" height="0.5ex" width="1ex"/>
<mrow>
<mrow>
<mi>a</mi>
<mi>x</mi>
</mrow>
<mo>=</mo>
<mrow>
<mi>a</mi>
<mi>y</mi>
</mrow>
</mrow>
</mrow>
</math>
mtext
Το ελεύθερο κείμενο
Τα κενά μετά την mtext ορίζονται με την mspace (μην αφήνετε κενά πατώντας space, θα αγνοηθούν).
width
Το πλάτος του mspace element.
height
Το ύψος πάνω από την baseline.
depth
Το ύψος (χώρος) κάτω από την baseline.
ex = x-height, δηλαδή το ύψος του πεζού x (οι τιμές που γίνονται δεκτές είναι : em, ex, px, in, cm, mm, pt, pc)
Local Storage
<!DOCTYPE HTML>
Αποθήκευση περιεχομένου στον Η/Υ του χρήστη. Με τον τρόπο αυτό μειώνουμε τον φόρτο στον server μας και εξασφαλίζουμε πως αν ο χρήστης έχει π.χ. 2 παράθυρα ανοικτά στο ηλεκτρονικό κατάστημά μας δεν θα βρεθεί με 2 αγορές για το ίδιο προϊόν.
<!DOCTYPE HTML>
<html>
<body>
<script type="text/javascript">
localStorage.setItem("name", "Hello World!"); //Αποθηκεύουμε το key που ονομάζεται name με την τιμή (value) Hello World!
document.write(localStorage.getItem("name")); //Εμφανίζουμε στην σελίδα το Hello World!
localStorage.removeItem("name"); // Διαγράφουμε το περιεχόμενου αυτού του κλειδιού.
document.write(localStorage.getItem("name"));
</script>
</body>
</html>
<html>
<body>
<script type="text/javascript">
if( sessionStorage.hits ){
sessionStorage.hits = Number(sessionStorage.hits) +1;
}else{
sessionStorage.hits = 1;
}
document.write("Total Hits :" + sessionStorage.hits );
</script>
<p>Refresh αυξάνει το number of hits.</p>
<p>Αν κλείσουμε και ξανανοίξουμε το παράθυρο μετράμε από την αρχή (το storage μηδενίζεται όταν αλλάζει το session).</p>
</body>
</html>
Το ίδιο παράδειγμα με διατήρηση του αριθμού των hits μεταξύ sessions.
<!DOCTYPE HTML>
<html>
<body>
<script type="text/javascript">
if( localStorage.hits ){
localStorage.hits = Number(localStorage.hits) +1;
}else{
localStorage.hits = 1;
}
document.write("Total Hits :" + localStorage.hits );
</script>
<p>Refresh αυξάνει το number of hits.</p>
<p>Αν κλείσουμε και ξανανοίξουμε το παράθυρο συνεχίζουμε να μετράμε από εκεί που είχαμε μείνει.</p>
</body>
</html>
Για να διαγράψουμε τα δεδομένα στον Η/Υ του χρήστη
<!DOCTYPE HTML>
<html>
<body>
<script type="text/javascript">
localStorage.clear();
// Reset number of hits.
if( localStorage.hits ){
localStorage.hits = Number(localStorage.hits) +1;
}else{
localStorage.hits = 1;
}
document.write("Total Hits :" + localStorage.hits );
</script>
<p>Τώρα ούτε το refresh δεν λειτουργεί.</p>
</body>
</html>
Η localStorage.clear(); διαγράφει όλες τις πληροφορίες από τον Η/Υ του χρήστη.
Ένα πιο πλήρες παράδειγμα χρήσης του localstorage
<!DOCTYPE HTML>
<html>
<body>
<script type="text/javascript">
if (typeof(localStorage) == 'undefined' ) {
alert('Your browser does not support HTML5 localStorage. Try upgrading.');
} else {
try {
localStorage.setItem("name", "Hello World!"); //αποθηκεύουμε, "key", "value"
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!'); //Τα data δεν αποθηκεύτηκαν λόγο quota exceed οπότε εμφανίζουμε ένα error
}
}
document.write(localStorage.getItem("name")); //Hello World!
localStorage.removeItem("name"); //Διαγράφουμε το item από την database που κρατάει για αυτές τις πληροφορίες ο browser.
}
</script>
</body>
</html>
Εφαρμογή Local Storage
Θα φτιάξουμε μια απλή εφαρμογή για να παρακολουθούμε τις ώρες εργασίας που έχουν καταναλωθεί σε μια σειρά από projects.
<!DOCTYPE HTML>
<html>
<body>
<script type="text/javascript">
var newDate = new Date();
var itemId = newDate.getTime(); /* Δημιουργούμε ένα unique id με τα milliseconds από την 1/1/1970 */
document.write('new itemId: ' + itemId + '<br>');
var values = new Array(); /*Νέα array*/
var name = "Some Project";
var hours = "12";
var date = "5/7/2010";
values.push(name); /* βάζουμε κάθε value στην array που έχει το όνομα values*/
values.push(hours);
values.push(date);
try {
localStorage.setItem(itemId, values.join(";")); /* Τοποθετούμε στην database ένα item που κατασκευάσαμε βάζοντας μαζί όλες τις values με delimiter το ; */
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert("Quota exceeded!");
}
}
var itemKey = localStorage.key(0); /* Δεν βλέπω τι τιμή έχει το ItemId που έδωσα οπότε τη διαβάζω από το localStorage ζητώντας το πρώτο διαθέσιμο key που στην περίπτωσή μας είναι και το μοναδικό*/
document.write('found itemKey: ' + itemKey + '<br>');
var values1 = localStorage.getItem(itemKey); /*Η values1 περιέχει το: 'Some Project;12;5/7/2010' */
document.write('values1 data: ' + values1 + '<br>');
var newvalues = new Array(); /* Μπορεί να παραληφθεί διότι κάνουμε split οπότε αυτόματα θα πάνε τα δεδομένα σε μια νέα array.*/
newvalues = values1.split(";"); /* Χωρίζουμε τις τιμές και τις τοποθετούμε σε διαφορετικά elements της νέας array newvalues */
var project = newvalues [0];
var hours = newvalues [1];
var date = newvalues [2];
document.write('Project Name: ' + project + '<br />');
document.write('Hours Logged: ' + hours + 'hours<br />');
document.write('Date Logged: ' + date);
localStorage.removeItem(itemKey); /* Διαγράφουμε μόνο ένα key της βάσης */
localStorage.clear(); /* Διαγράφουμε όλη τη βάση. */
</script>
</body>
</html>
Η ίδια εφαρμογή με χρήση JQuery, φόρμα, εγγραφές και διαγραφές
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>localStorage() - Part Three - PKR Code Samples</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<!-- Για να κάνουμε πιο απλή τη δουλειά μας θα χρησιμοποιήσουμε την βιβλιοθήκη jquery (jquery library) -->
<script>
$(document).ready(function() {
if (typeof(localStorage) == 'undefined' ) {
alert('Your browser does not support HTML5 localStorage. Try upgrading.');
}
else {
getAllItems(); /*φορτώνουμε και εμφανίζουμε όλα τα διαθέσιμα items τρέχοντας τη function (ρουτίνα) που έχουμε δημιουργήσει παρακάτω. */
$("#logForm").submit(function(){
/* Αν στη φόρμα με id logForm πατήθηκε το submit */
var newDate = new Date();
var itemId = newDate.getTime();
/* Φτιάχνουμε τον κωδικό (key) για τη βάση. */
var values = new Array();
var project = $("input[name='project']").val();
var hours = $("input[name='hours']").val();
var date = $("input[name='date']").val();
project = project.replace(/(<([^>]+)>)/ig, "");
/* Καταργούμε πιθανά html tags που ίσως δηλώσει ο χρήστης στο πεδίο project.
[>] = ταίριαξε οποιοδήποτε χαρακτήρα μέσα στις αγκύλες
[^>] = ταίριαξε οποιοδήποτε χαρακτήρα δεν είναι μέσα στις αγκύλες
+ = συνέχισε όσο ταιριάζεις
*/
values.push(project);
values.push(hours);
values.push(date);
/*Παίρνουμε από τη φόρμα τα δεδομένα που έδωσε ο χρήστης και τα αποθηκεύουμε στη values */
if (project != "" && hours != "" && date != "") {
/* Αν το project πεδίο δεν είναι κενό και το ίδιο και τα άλλα δύο ...*/
try {
localStorage.setItem(itemId, values.join(';'));
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!');
}
}
}
else {
alert("All fields are required.");
}
});
$(".delete").click(function() {
var answer = confirm("Are you sure you want to delete this time?");
if (answer) {
var itemKey = $(this).attr("name");
localStorage.removeItem(itemKey);
getAllItems(); //refresh the list of items
}
});
/*Ο κώδικας για να επιβεβαιώσω πως θέλει ο χρήστης να διαγραφεί μια εγγραφή στη βάση. */
$("#clearLog").click(function() {
var answer = confirm("Are you sure you want to clear the log?");
if (answer) {
localStorage.clear();
getAllItems(); //refresh the list of items
}
});
/*Ο κώδικας για να επιβεβαιώσω πως θέλει ο χρήστης να διαγραφεί όλη η βάση. */
}
});
function getAllItems() {
var timeLog = ""; /* Σε αυτή τη μεταβλητή θα έχουμε όλο τον html κώδικα */
var i = 0;
var logLength = localStorage.length-1; /* Βρίσκουμε τον αριθμό των χρησιμοποιημένων θέσεων της database (το μήκος της μείον 1 αφού οι θέσεις ξεκινάνε από 0 */
//now we are going to loop through each item in the database
for (i = 0; i <= logLength; i++) {
//lets setup some variables for the key and values
var itemKey = localStorage.key(i);
var values = localStorage.getItem(itemKey);
values = values.split(";"); /* Η array με τις διαθέσιμες τιμές */
var project = values[0];
var hours = values[1];
var date = values[2];
/* Αφού βρούμε το item το προσθέτουμε στη λίστα */
timeLog += '<li><strong>'+project+'</strong>: '+hours+' hours - '+date+' <span class="delete" name="'+itemKey+'">ΧΧΧ</span></li>';
/* Όταν ο χρήστης πατήσει το ΧΧΧ θα διαγραφεί η εγγραφή. */
}
/* Χρειαζόμαστε και έναν έλεγχο και αντίστοιχο μήνυμα αν η database είναι κενή. */
if (timeLog == "")
timeLog = '<li class="empty">Log Currently Empty</li>';
$("#theLog").html(timeLog); /* Αφού τελειώσουν όλες οι εργασίες εμφανίζω όλα τα list items στη λίστα με id theLog. Το μήνυμα Loading θα εμφανιστεί μόνο αν υπάρχει κάποιο πρόβλημα και δεν προστεθούν δεδομένα στην timeLog π.χ. επειδή δεν κλήθηκαν σωστά. */
}
</script>
</head>
<body>
<form id="logForm" method="post">
<input type="text" name="project" value="Project Name">
<input type="number" name="hours" value="Hours" class="shortField">
<input type="text" name="date" value="Date" class="shortField">
<input type="submit" value="Log Time">
</form>
<ul id="theLog">
<li>Loading…</li>
</ul>
<button type="button" id="clearLog">Clear Log</button>
</body>
</html>
Περισσότερα για αυτό το θέμα θα βρείτε στο: http://paperkilledrock.com/2010/05/html5-localstorage-part-four/
Φόρμες με HTML 5
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>web forms 2.0</title>
</head>
<body>
<form action="http://example.com/cgiscript.pl" method="post">
<p>
<label for="firstname">first name: </label>
<input type="text" id="firstname" placeholder="Γράψε το μικρό σου όνομα"><br />
<label for="lastname">last name: </label>
<input type="text" id="lastname"><br />
<label for="email">email: </label>
<input type="text" id="email" required><br>
<input type="radio" name="sex" value="male"> Male<br>
<input type="radio" name="sex" value="female"> Female<br>
<input type="submit" value="send"> <input type="reset">
</p>
</form></body>
</html>
Προσέξτε το placeholder και το required που πλέον δεν χρειάζεται ειδικό κώδικα javascript.
Embeded Audio - Video
Audio
<!DOCTYPE HTML>
<html><body>
<audio controls="controls">
<source src="http://www.gepiti.com/tests/Tromboon-sample.ogg" type="audio/ogg">
<source src="http://www.gepiti.com/tests/blind_willie.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio> </body></html>
Video
<!DOCTYPE HTML>
<html>
<body>
<video width="300" height="200" controls autoplay>
<source src="http://www.gepiti.com/tests/Baba.mp4" type="audio/mp4" />
<source src="http://www.gepiti.com/tests/Trompoon-sample.ogg" type="audio/ogg" />
Your browser does not support the <video> element.
</video>
</body>
</html>
Λειτουργεί σε Chrome
<!DOCTYPE HTML>
<html><body>
<video controls="controls" autoplay="autoplay">
<source src="http://www.gepiti.com/tests/gizmo.mp4" type="video/mp4" />
<source src="http://www.gepiti.com/tests/gizmo.webm" type="video/webm" />
<source src="http://www.gepiti.com/tests/gizmo.ogv" type="video/ogg" />
Video not playing? <a href="pics/video/gizmo.mp4">Download file</a> instead.
</video></body></html>
Λειτουργεί σε Chrome και Firefox
Drag and Drop
<!DOCTYPE HTML>
<html>
<head>
<style type="text/css">
#div1 {width:350px;height:100px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<p>Drag the image into the rectangle:</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" draggable="true" ondragstart="drag(event)" width="241" height="98">
</body>
</html>
Επεξήγηση:
Φτιάχνουμε το div (#div1) όπου θα αποθέσουμε την εικόνα την οποία θα κάνουμε drag and drop.
Στην οδηγία (tag) της εικόνας δηλώνουμε draggable="true" ώστε να επιτραπεί η ενέργεια συρσίματος και απόθεσης.
Δημιουργούμε τη function drag η οποία με τη μέθοδο dataTransfer.setData() ορίζει το data type (είναι Text) και λαμβάνει το id του στοιχείου που θα συρθεί (είναι το eeei1 και το λαμβάνει μέσω της ev).
Κανονικά τα τμήματα της σελίδας δεν είναι συρόμενα. Για να το επιτρέψουμε αυτό θα καλέσουμε την μέθοδο ev.preventDefault(); Μέσω της function allowDrop
Μέσα στο div που θα τοποθετηθεί το αντικείμενο δηλώνουμε ondrop="drop(event)" (καλεί τη function drop) ondragover="allowDrop(event)" (αυτό ενημερώνει πως εδώ θα τοποθετηθεί τα συρόμενο αντικείμενο και πως επιτρέπεται αυτή η ενέργεια)
Η function drop εκτελεί τελικά την εργασία. Η drop:
1. Καλεί πάλι την preventDefault() για να εμποδίσει τον browser να κάνει το default handling των δεδομένων (default είναι να προσπαθήσει να ανοίξει παραπομπή)
2. Ο browser παίρνει τα συρόμενα δεδομένα με την μέθοδο dataTransfer.getData("Text"). Αυτή η μέθοδος θα δώσει όποια δεδομένα δηλώθηκαν με τη μέθοδο setData() (αυτό έγινε με τη function drag)
3. Το id του συρόμενου είναι το eeei1
4. Τέλος κάνει append (επισυνάπτει) τα συρόμενα δεδομένα στο drop element
Αν θέλουμε δύο drag and drop έχουμε τον ίδιο κώδικα αλλά προσθέτουμε:
#div2 {width:550px;height:100px;padding:10px;border:1px solid #aaaaaa;}
Το div πρέπει να έχει διαστάσεις μεγαλύτερες από το περιεχόμενο που θα του βάλουμε.
Επίσης στο body προσθέτουμε:
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="eeei2" src="http://www.eeei.gr/seminars/htmldr_a/clip_image018.jpg" draggable="true" ondragstart="drag(event)" width="555" height="63">
Αν δοκιμάσετε θα δείτε πως μπορείτε να βάλετε το κάθε drag element σε όποιο div επιθυμείτε. Αν οι διαστάσεις της εικόνας είναι μεγαλύτερες από εκείνες του δοχείου (εδώ του div το υπόλοιπο θα εξέχει).
Για να κάνουμε drag κείμενο έχουμε:
<span id="eeei2" draggable="true" ondragstart="drag(event)">aaaaa bbbbbbbbbb cccccccccc</span>
Το κείμενο μπορεί να γίνει drag.περισσότερες από μια φορές όπως βλέπουμε και στον κώδικα που ακολουθεί όπου προσπαθούμε να το βάλουμε μέσα σε πεδία φόρμας.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style type="text/css">
#div1 {width:350px;height:100px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<p>Δοκιμή με κείμενο και φόρμα</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" draggable="true" ondragstart="drag(event)" width="241" height="98">
<br>
<span id="Εδώ τι βγαίνει;" draggable="true" ondragstart="drag(event)">aaaaa bbbbbbbbbb cccccccccc</span>
<form method=POST action="http://www.eeei.gr/cgi-bin/mailform.pl">
<input type=hidden name="subject" value="eeei form parapona output" ondrop="drop(event)" ondragover="allowDrop(event)">
<input type=hidden name="reply" value="θα σας απαντήσουμε το συντομότερο δυνατό.">
<P><b>Ονοματεπώνυμο:</b>
<br><input id="eeei2" type="text" name="name" size="100">
<input type="submit" value="Υποβολή">
</form></body></html>
Το ίδιο με περισσότερο drag and drop:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style type="text/css">
#div1 {width:350px;height:100px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<p>Δοκιμή με κείμενο και φόρμα</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="eeei1" src="http://www.eeei.gr/images/eeeil1.jpg" draggable="true" ondragstart="drag(event)" width="241" height="98">
<br>
<span id="Εδώ τι βγαίνει;" draggable="true" ondragstart="drag(event)">Εδώ τι βγαίνει;</span>
<span id="Δεύτερη Δοκιμή" draggable="true" ondragstart="drag(event)">Δεύτερη Δοκιμή</span>
<form method=POST action="http://www.eeei.gr/cgi-bin/genericutf8mailform.pl">
<input type=hidden name="subject" value="Test output" ondrop="drop(event)" ondragover="allowDrop(event)">
<input type=hidden name="redirect" value="http://www.eeei.gr">
<input type=hidden name="recipient" value="gepiti_papaki_gmail.com">
<P><b>Κείμενο 1:</b>
<br><input id="eeei2" type="text" name="name" size="100">
<P><b>Κείμενο 2:</b>
<br><input id="eeei2" type="text" name="text" size="100">
<input type="submit" value="Υποβολή">
</form></body></html>
Geolocation
Με την υπηρεσία αυτή βρίσκουμε τη θέση του χρήστη που βλέπει τη σελίδα μας:
Για την εύρεση γεωγραφικού μήκους και πλάτους:
<!DOCTYPE html>
<html>
<head><meta http-equiv=Content-Type content="text/html; charset=utf-8"> <title>Geolocation</title></head>
<body>
<p id="demo">Κάντε κλικ για να δείτε τις συντεταγμένες σας:</p>
<button onclick="getLocation()">Που βρίσκομαι;</button>
<script>
var x=document.getElementById("demo");
function getLocation()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(showPosition);
}
else{x.innerHTML="Geolocation is not supported by this browser.";}
}
function showPosition(position)
{
x.innerHTML="Γεωγραφικό Πλάτος: " + position.coords.latitude +
"<br>Γεωγραφικό Μήκος: " + position.coords.longitude;
}
</script>
</body>
</html>
Πως λειτουργεί:
1. Η var x=document.getElementById("demo"); βάζει τα περιεχόμενα της παραγράφου με το id “demo” στην μεταβλητή x
2. Ελέγχουμε αν υποστηρίζεται Geolocation από τον browser
3. Αν υποστηρίζεται τρέχουμε την μέθοδο getCurrentPosition(), διαφορετικά εμφανίζουμε ένα μήνυμα στον χρήστη.
4. Αν όλα πάνε καλά στην getCurrentPosition() λαμβάνουμε τις συντεταγμένες και τις δίνουμε στην function showPosition
5. Η showPosition() function εμφανίζει γεωγραφικό μήκος και πλάτος (η innerHTML αλλάζει το περιεχόμενο κάπου HTML κώδικα, εδώ της x που διαβάσαμε παραπάνω όταν υπάρχει κάποια ενέργεια του χρήστη).
Geolocation με error handling και switch
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head>
<body>
<p id="demo">Κάντε κλικ για να δείτε τις συντεταγμένες σας:</p>
<button onclick="getLocation()">Που βρίσκομαι;</button>
<script>
var x=document.getElementById("demo");
function getLocation()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(showPosition,showError);
}
else{x.innerHTML="Geolocation is not supported by this browser.";}
}
function showPosition(position)
{
x.innerHTML="Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
function showError(error)
{
switch(error.code)
{
case error.PERMISSION_DENIED:
x.innerHTML="User denied the request for Geolocation."
break;
case error.POSITION_UNAVAILABLE:
x.innerHTML="Location information is unavailable."
break;
case error.TIMEOUT:
x.innerHTML="The request to get user location timed out."
break;
case error.UNKNOWN_ERROR:
x.innerHTML="An unknown error occurred."
break;
}
}
</script>
</body>
</html>
Αν απενεργοποιήσατε την προβολή στοιχείων τοποθεσίας στον Firefox για να δοκιμάσετε το παράδειγμα και θέλετε να την επανενεργοποιήσετε επισκεφθείτε μια σελίδα του site που σας ενδιαφέρει και επιλέξετε – Εργαλεία – Πληροφορίες Σελίδας – Δικαιώματα.
Συνήθως στη switch βάχουμε και μια default τιμή αν δεν ισχύει κάποια από τις άλλες συνθήκες. Π.χ.
default:
x.innerHTML="Κλάφτα δεν καταλαβαίνω τίποτε"
Εμφάνιση τοποθεσίας στον χάρτη (στατικός χάρτης)
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"></head>
<body>
<p id="demo">Κάντε κλικ για να δείτε τις συντεταγμένες σας:</p>
<button onclick="getLocation()">Που βρίσκομαι;</button>
<div id="mapholder"></div>
<script>
var x=document.getElementById("demo");
function getLocation()a
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(showPosition,showError);
}
else{x.innerHTML="Geolocation is not supported by this browser.";}
}
function showPosition(position)
{
var latlon=position.coords.latitude+","+position.coords.longitude;
var img_url="http://maps.googleapis.com/maps/api/staticmap?center="
+latlon+"&zoom=14&size=400x300&sensor=false";
document.getElementById("mapholder").innerHTML="<img src='"+img_url+"'>";
}
function showError(error)
{
switch(error.code)
{
case error.PERMISSION_DENIED:
x.innerHTML="User denied the request for Geolocation."
break;
case error.POSITION_UNAVAILABLE:
x.innerHTML="Location information is unavailable."
break;
case error.TIMEOUT:
x.innerHTML="The request to get user location timed out."
break;
case error.UNKNOWN_ERROR:
x.innerHTML="An unknown error occurred."
break;
}
}
</script>
</body>
</html>
Εμφάνιση τοποθεσίας σε διαδραστικό χάρτη
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>Εμφάνιση τοποθεσίας σε διαδραστικό χάρτη</title>
</head>
<body>
<p id="demo">Κάντε κλικ για να δείτε τις συντεταγμένες σας:</p>
<button onclick="getLocation()">Που βρίσκομαι;</button>
<div id="mapholder"></div>
<script src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script>
var x=document.getElementById("demo");
function getLocation()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(showPosition,showError);
}
else{x.innerHTML="Geolocation is not supported by this browser.";}
}
function showPosition(position)
{
lat=position.coords.latitude;
lon=position.coords.longitude;
latlon=new google.maps.LatLng(lat, lon)
mapholder=document.getElementById('mapholder')
mapholder.style.height='250px';
mapholder.style.width='500px';
var myOptions={
center:latlon,zoom:14,
mapTypeId:google.maps.MapTypeId.ROADMAP,
mapTypeControl:false,
navigationControlOptions:{style:google.maps.NavigationControlStyle.SMALL}
};
var map=new google.maps.Map(document.getElementById("mapholder"),myOptions);
var marker=new google.maps.Marker({position:latlon,map:map,title:"You are here!"});
}
function showError(error)
{
switch(error.code)
{
case error.PERMISSION_DENIED:
x.innerHTML="User denied the request for Geolocation."
break;
case error.POSITION_UNAVAILABLE:
x.innerHTML="Location information is unavailable."
break;
case error.TIMEOUT:
x.innerHTML="The request to get user location timed out."
break;
case error.UNKNOWN_ERROR:
x.innerHTML="An unknown error occurred."
break;
}
}
</script>
</body>
</html>
instanceof
Ελέγχει ένα object και επιστρέφει true αν είναι του τύπου που έχει οριστεί.
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
var color1 = new String("green");
var condition1 = new Boolean(color1 instanceof String); // true επειδή είναι String.
var color2 = "coral"; //no type specified
var condition2 = new Boolean(color2 instanceof String);
document.write(condition1 + " " + condition2);
</script></body></html>
First Class Objects
Στην javascript μια function είναι και αυτή ένα object και μπορούμε να τη διαχειριστούμε ως τέτοιο.
Μπορούμε επίσης να τις διαχειριστούμε ως μεταβλητές που τις δίνουμε σε άλλες functions ή να τους επισυνάψουμε object properties.
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
function feedCat()
{
alert("Κάτι γίνεται εδώ.");
}
var condition = new Boolean(feedCat instanceof Object);
document.write(condition);
</script></body></html>
Η function μπορεί να πάρει ιδιότητες όπως κάθε object και ακόμη να καλέσει τον constructor της (function Function() { [native code] } δηλαδή πως το object δημιουργήθηκε από function).
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
function feedCat()
{
alert("Κάτι γίνεται εδώ.");
}
feedCat.food = "kibble";
document.write(feedCat.food + " " + feedCat.constructor);
</script></body></html>
Η function μπορεί να τοποθετηθεί σε μια μεταβλητή και να κληθεί από αυτήν.
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
function feedCat()
{
alert("Κάτι γίνεται εδώ.");
}
var eveningChore = feedCat;
eveningChore();
</script></body></html>
Η function μπορεί να δωθεί ως παράμετρος σε μια άλλα function.
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
function feedCat()
{
alert("Κάτι γίνεται εδώ.");
}
function doEveningChores(chores)
{
for(var x=0; x<chores.length; x++)
chores[x]();
// Η for είναι ισοδύναμη με το: chores[0]();
}
doEveningChores([feedCat]);
</script></body></html>
Αντί για array από functions μπορούμε να δώσουμε μια απλή μεταβλητή.
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
function feedCat()
{
alert("Κάτι γίνεται εδώ.");
}
function doEveningChores(chores)
{
chores();
}
doEveningChores(feedCat);
</script></body></html>
Μπορεί να κληθεί μια function που ως return (επιστροφή δεδομένων) θα έχει μια άλλη function.
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
function feedCat()
{
alert("Κάτι γίνεται εδώ.");
}
// return a function from another function
function tonightChores()
{
return feedCat;
}
var tonight = tonightChores();
tonight();
</script></body></html>
Χάρη σε αυτές τις τεχνικές είναι πολύ εύκολο να φτιάχνουμε objects στην Javascript χωρίς να χρειάζονται classes:
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
var sabby = {
name : "Sabby",
species: "cat",
hello : function() { alert("hissss"); }
};
document.write(sabby.name + " " + sabby.species);
sabby.hello();
</script></body></html>
Array of objects
<!DOCTYPE html><html><head><meta charset="utf-8">
</head><body><script>
var list = [
{ date: '12/1/2011', reading: 3, id: 20055 },
{ date: '13/1/2011', reading: 5, id: 20053 },
{ date: '14/1/2011', reading: 6, id: 45652 }
];
document.write(list[1].date + " " + list[0].id + " " + list[2].reading);
</script></body></html>
Javascript Animation
ΠΡΟΣΟΧΗ: Σχεδόν όλα τα animations απαιτούν να υπάρχει δηλωμένο στο style της σελίδας κάποιο property για τα id και classes που χρησιμοποιούνται.
Απλή κίνηση ενός αντικειμένου
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>Κινούμενο DIV</title>
<style type="text/css">
#fooObject {
/* Ένα απλό box */
position:absolute;
left:0px;
top:8em;
width:5em;
line-height:3em;
background:#99ccff;
border:1px solid #003366;
white-space:nowrap;
padding:0.5em;
}</style>
<script type="text/javascript">
var foo = null; // Δηλώνουμε το object
function doMove() {
foo.style.left = parseInt(foo.style.left)+1+'px';
setTimeout(doMove,20); // Η doMove εκτελείτε κάθε 20msec
}
function init() {
foo = document.getElementById('fooObject'); // Η init λαμβάνει το "foo" object
foo.style.left = '0px'; // Ορίζει την αρχική του θέση στα 0px
doMove(); // Καλεί τη function που κάνει το animating
}
window.onload = init; // Καλούμε την init για να ξεκινήσει η Javascript.
</script>
</head>
<body>
<div id="fooObject">
Είμαι ο foo.
</div>
</body></html>
Κίνηση με συγκεκριμένο αριθμό επαναλήψεων
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>Κινούμενο DIV</title>
<style type="text/css">
#fooObject {
/* Ένα απλό box */
position:absolute;
left:0px;
top:8em;
width:250px;
}</style>
<script type="text/javascript">
var foo = null; // Δηλώνουμε το object
var repetitions = '0';
var max_repetitions = '30';
function doMove() {
foo.style.left = parseInt(foo.style.left)+1+'px';
if (max_repetitions >= repetitions) {
setTimeout(doMove,20); // Η doMove εκτελείτε κάθε 20msec
repetitions++;
}
}
function init() {
foo = document.getElementById('fooObject'); // Η init λαμβάνει το "foo" object
foo.style.left = '0px'; // Ορίζει την αρχική του θέση στα 0px
doMove(); // Καλεί τη function που κάνει το animating
}
window.onload = init; // Καλούμε την init για να ξεκινήσει η Javascript.
</script>
</head>
<body>
<div id="fooObject">
Είμαι ο foo.<p>
<img src="http://www.eeei.gr/images/eeeil1.jpg" alt="eeei" width="241" height="98">
</div>
</body></html>
Διαγώνια κίνηση
<!DOCTYPE html>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>Κινούμενο DIV</title>
<style type="text/css">
#fooObject {
/* Ένα απλό box */
position:absolute;
left:0px;
top:80px;
width:250px;
}</style>
<script type="text/javascript">
var foo = null; // Δηλώνουμε το object
var repetitions = '0';
var max_repetitions = '80';
function doMove() {
foo.style.left = parseInt(foo.style.left)+1+'px';
foo.style.top = parseInt(foo.style.top)+1+'px';
if (max_repetitions >= repetitions) {
setTimeout(doMove,20); // Η doMove εκτελείτε κάθε 20msec
repetitions++;
}
}
function init() {
foo = document.getElementById('fooObject'); // Η init λαμβάνει το "foo" object
foo.style.left = '0px'; // Ορίζει την αρχική του θέση στα 0px
foo.style.top = '80px';
doMove(); // Καλεί τη function που κάνει το animating
}
window.onload = init; // Καλούμε την init για να ξεκινήσει η Javascript.
</script>
</head>
<body>
<div id="fooObject">
Είμαι ο foo.<p>
<img src="http://www.eeei.gr/images/eeeil1.jpg" alt="eeei" width="241" height="98">
</div>
</body></html>
Animation με την setInterval
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
</style>
<script>
function move(elem) {
var left = 0
function frame() {
left++ // Αυξάνουμε τη θέση κατά ένα.
elem.style.left = left + 'px' // Αλλάζουμε τη θέση του elem δηλαδή του example_block
if (left == 100) // Πότε τελειώνει η κίνηση (για να πάει πιο δεξιά θα πρέπει να το αυξήσουμε
clearInterval(id)
}
var id = setInterval(frame, 10) // Ζωγραφίζουμε κάθε 10ms
}
</script>
</head>
<body>
Κάνε κλικ πάνω στο μπλε τετραγωνάκι.
<div onclick="move(this.children[0])" class="example_path">
<div class="example_block"></div>
</div>
</body>
</html>
Η δουλειά εδώ γίνεται με ένα DOM style object. Το HTML DOM (Document Object Model) αποτελεί τον τρόπο για να έχουμε προγραμματιστικά (και όχι μόνο) πρόσβαση σε στοιχεία της σελίδας μας.
Το elem.style.left = left + 'px' αλλάζει το style του example_block και το πηγαίνει Χ θέσεις προς τα αριστερά (και φυσικά το Χ αλλάζει χάρη στο πρόγραμμα). Στην αρχή δεν υπάρχει left οπότε στην πραγματικότητα κάθε φορά ορίζεται από την αρχή.
Η σύνταξη είναι: Object.style.left= "auto|length|%|inherit"
Εδώ το Object είναι το example_block και δηλώνουμε length (μπορεί να πάρει και αρνητικές τιμές).
Η πλήρης σύνταξη είναι:: document.getElementById("id").style.property="value"
Προσοχή: αν βάλουμε move(example_block) θα λειτουργήσει μόνο αν το example_block είναι id. Αν το αφήσουμε κλάση δεν θα δουλέψει.
Επεξήγηση της Children
Η children είναι μια array που περιέχει όλα τα elements που βρίσκονται μέσα στο τρέχον element.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
.example_path .example_block1 {
position: absolute;
background-color: red;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
</style>
<script>
function move(elem) {
var left = 0
function frame() {
left++ // Αυξάνουμε τη θέση κατά ένα.
elem.style.left = left + 'px' // Αλλάζουμε τη θέση του elem δηλαδή του example_block
if (left == 100) // Πότε τελειώνει η κίνηση (για να πάει πιο δεξιά θα πρέπει να το αυξήσουμε
clearInterval(id)
}
var id = setInterval(frame, 10) // Ζωγραφίζουμε κάθε 10ms
}
</script>
</head>
<body>
Κάνε κλικ πάνω στο μπλε τετραγωνάκι.
<div onclick="move(this.children[0])" class="example_path">
<div class="example_block"></div>
<div class="example_block1"></div>
<!--Τώρα έχουμε 2 div το ένα πάνω στο άλλο. Όταν κινείται το πρώτο εμφανίζεται. Χωρίς κίνηση δεν φαίνεται γιατί το δεύτερο το καλύπτει-->
</div>
</body>
</html>
Αν κάνουμε το this.children[1] τότε θα κινηθεί το κόκκινο div.
setInterval με αριθμό βημάτων
Αντί να ορίσουμε τελικό προορισμό μπορούμε να κινηθούμε για συγκεκριμένο αριθμό βημάτων.
<!DOCTYPE HTML><html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><style>
#example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
#example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
</style><script>
var maxsteps = 20;
var steps = 0;
function move(elem) {
var left = 0;
function frame() {
left += 2; // Αυξάνουμε τη θέση κατά 2.
steps++;
elem.style.left = left + 'px' // Αλλάζουμε τη θέση του elem δηλαδή του example_block
if (steps > maxsteps) // Πότε τελειώνει η κίνηση (για να πάει πιο δεξιά θα πρέπει να το αυξήσουμε
clearInterval(id);
}
var id = setInterval(frame, 10); // Ζωγραφίζουμε κάθε 10ms
}
</script></head><body>
Κάνε κλικ πάνω στο μπλε τετραγωνάκι.
<div onclick="move(example_block)" id="example_path">
<div id="example_block"></div>
</div></body></html>
Μπορούμε επίσης να συσχετίσουμε την κίνηση με τον αριθμό των βημάτων:
Στην ακόλουθη τροποποιήση προσθέτουμε τη μεταβλητή pixels2move που λέει στο πρόγραμμα πόσα pixels θα κινηθεί συνολοκά το το κουτάκι. Έτσι η currentPixels2move περιέχει τον αριθμό των pixels που θα κινηθεί σε κάθε βήμα
var pixels2move = 100;
var currentPixels2move = Math.ceil(pixels2move/maxsteps);
left += currentPixels2move; // Αυξάνουμε τη θέση κατά όσα pixels υπολογίστηκε παραπάνω.
Αλλάξτε τα βήματα από 20 σε 100 για να δείτε το κουτί να καλύπτει την ίδια απόσταση αλλά με πιο αρχή ταχύτητα.
Μια πλήρης εφαρμογή animation
Θα χρειαστούμε τις ακόλουθες μεταβλητές
• delay = κάθε πότε τρέχει το κάθε βήμα του animation (είναι η δεύτερη παράμετρος στη setInterval)
• duration = η συνολική διάρκεια του animation.
• progress = το ποσοστό του χρόνου που έχει περάσει (θα του δίνουμε τιμές από 0 έως 1).
• delta = πόση από την συνολική δραστηριότητα του animation έχει ολοκληρωθεί. Αν το animation λειτουργεί γραμμικά το progress και το delta θα είναι ίδια αλλά υπάρχουν περιπτώσεις που θέλουμε κάτι πιο φυσιολογικό π.χ. η κίνηση να ξεκινάει αργά μετά να πηγαίνει πιο γρήγορα και στο τέλος να επιβραδύνει πριν σταματήσει. Σε τέτοιες περιπτώσεις θα διαφέρουν.
• step = Εκτελεί όση εργασία χρειάζεται να γίνει σε αυτό το βήμα (έχει νόημα να το παρακολουθούμε αν delta και process δεν εξελίσσονται με την ίδιο ρυθμό).
Παράδειγμα πλήρους εφαρμογής animation
<!DOCTYPE HTML>
<html>
<head>
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
if (progress > 1) progress = 1
var delta = opts.delta(progress)
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script>
<script>
function move(element, delta, duration) {
var to = 500
animate({
delay: 10,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
}
})
}</script>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
</style></head><body>
<div onclick="move(this.children[0], function(p) {return p})" class="example_path">
<div class="example_block"></div>
</div></body></html>
Τι παίρνει η function move:
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function move(element, delta, duration) {
var x=document.getElementById("data"); // Για να δούμε ποια είναι τα δεδομένα
x.innerHTML=duration + " " + delta + " " + element;
}
</script>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
}
#box {}
#data {}
</style>
</head>
<body>
<p id="data">data</p>
<div onclick="move(this.children[0], function(p) {return p},5000)" class="example_path">
<div class="example_block"><span id="box">0</span></div>
</div></body></html>
Η έναρξη γίνεται με κλήση από τη σελίδα.
<div onclick="move(this.children[0], function(p) {return p})" class="example_path">
<div class="example_block"></div>
</div></body></html>
Αν κάνουμε κλικ στο div όσο κινείται το box θα αποκτήσουμε και δεύτερο κινούμενο box.
Έτσι όπως είναι ρυθμισμένο το πρόγραμμα η move δεν δίνει duration και αυτή λαμβάνει. Την default τιμή.
<div onclick="move(this.children[0], function(p) {return p})" class="example_path">
<div class="example_block"></div>
</div>
<script></body></html>
Φυσικά θα μπορούσαμε να δώσουμε κάποια τιμή για να διαρκεί περισσότερο (οπότε θα κινείται πιο αργά):
<div onclick="move(this.children[0], function(p) {return p},25000)" class="example_path">
var to = 500 είναι το σημείο μέχρι το οποίο θα κινηθεί το μπλε τετράγωνο (το example_block). Αν το κάνουμε var to = 1500 τότε θα φύγει εκτός του div class="example_path" (και δεν θα φαίνεται).
Το delay είναι property του object animate (που είναι μια function) και μας δίνει κάθε πότε θα τρέχει η animate. Κάθε πότε δηλαδή θα εκτελείται νέο βήμα.
Αν βάλουμε delay: 100 θα έχουμε λιγότερα βήματα, συνεπώς πιο τραχιά κίνηση.
Για να δούμε την delta θα κάνουμε μερικές αλλαγές στον κώδικα:
#box {font-weight:bold;}
<div onclick="move(this.children[0], function(p) {return p},25000)" class="example_path">
<div class="example_block"><span id="box">0</span></div>
</div>
delay: 100,
step: function(delta) {
element.style.left = to*delta + "px"
var x=document.getElementById("box");
x.innerHTML=delta;
}
Η ίδια εφαρμογή με δείκτες για να βλέπουμε τι γίνεται είναι:
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
var y=document.getElementById("data"); // Για να δούμε ποιο είναι το progress
y.innerHTML=progress ;
if (progress > 1) progress = 1
var delta = opts.delta(progress)
var z=document.getElementById("data1"); // Για να δούμε ποιο είναι το delta
z.innerHTML=delta ;
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script><script>
function move(element, delta, duration) {
var to = 500
animate({
delay: 100,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
var x=document.getElementById("box"); // Για να δούμε ποια είναι η θέση του box
x.innerHTML=element.style.left;
}
})
}</script>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
#box {font-weight:bold;}
#data {font-weight:bold;}
#data1 {font-weight:bold;}
</style>
</head>
<body>
Progress:<p id="data">Αρχικό.</p>
Delta:<p id="data1">Αρχικό 1.</p>
<div onclick="move(this.children[0], function(p) {return p},25000)" class="example_path">
<div class="example_block"><span id="box">0</span></div>
</div></body></html>
Στο παραπάνω παράδειγμα η εξέλιξη της κίνησης είναι γραμμική, δηλαδή η ακόλουθη:
Θα μπορούσαμε όμως να έχουμε διαφορετικού τύπου κίνηση, για παράδειγμα ο κύβος να κινείται αργά στην αρχή και μετά να επιταχύνει.
Η συνάρτηση είναι:
function quad(progress) {
return Math.pow(progress, 2)
}
Η Math.pow ανεβάζει ένα νούμερο σε μια δύναμη. Π.χ. Math.pow(4,3); = 64 (4 εις την τρίτη). Οπότε όσο μεγαλύτερο είναι το n (εδώ είναι 2) τόσο μεγαλύτερη η επιτάχυνση.
Με n=5 θα είναι:
function quint(progress) {
return Math.pow(progress, 5)
Ο πλήρης κώδικας με συνάρτηση αλλαγής ταχύτητας κίνησης και χρονοκαθυστέρηση για να φαίνεται η αλλαγή είναι:
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function quad(progress) {
return Math.pow(progress, 2)
}
</script>
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
var y=document.getElementById("data"); // Για να δούμε ποιο είναι το progress
y.innerHTML=progress ;
if (progress > 1) progress = 1
var delta = opts.delta(progress)
var z=document.getElementById("data1"); // Για να δούμε ποιο είναι το delta
z.innerHTML=delta ;
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script><script>
function move(element, delta, duration) {
var to = 500
animate({
delay: 1000,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
var x=document.getElementById("box"); // Για να δούμε ποια είναι η θέση του box
x.innerHTML=element.style.left;
}
})
}</script>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
#box {font-weight:bold;}
#data {font-weight:bold;}
#data1 {font-weight:bold;}
</style>
</head>
<body>
Progress:<p id="data">Αρχικό.</p>
Delta:<p id="data1">Αρχικό 1.</p>
<div onclick="move(this.children[0], quad,60000)" class="example_path">
<div class="example_block"><span id="box">0</span></div>
</div></body></html>
Άλλες συναρτήσεις που μπορούμε να χρησιμοποιήσουμε:
Κυκλική:
Η κίνηση αποτελεί μέρος ενός κύκλου
function circ(progress) {
return 1 - Math.sin(Math.acos(progress))
}
Τόξου:
Πάμε λίγο προς τα πίσω και μετά προς τα εμπρός
function back(progress) {
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5)
}
Μπρος πίσω
Η κίνηση γίνεται προς τα εμπρός αλλά με μερικά τυχαία πισωγυρίσματα κατά καιρούς μέχρι φυσικά να φτάσουμε στο τέλος.
function bounce(progress) {
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
}
Φυσικά μπορούμε να υιοθετήσουμε όποια άλλη συνάρτηση θέλουμε αλλά αυτές καλύτπουν το 95% των περιπτώσεων που θα χρειαστούμε.
Ελαστική
Είναι παραλλαγή της bounce όπου όμως το αρχικό μπρος πίσω ακολουθείται από ένα τίναγμα προς το τέλος.
function elastic(progress) {
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress)
}
Το εύρος της ελαστικότητας ρυθμίζεται από τη συνάρτηση. Εδώ είναι 1.5
Παράδειγμα με ενσωμάτωση όλων των συνηθισμένων συναρτήσεων ρυθμού κίνησης:
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function elastic(progress) {
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress)
}
function linear(progress) {
return progress
}
function quad(progress) {
return Math.pow(progress, 2)
}
function quint(progress) {
return Math.pow(progress, 5)
}
function circ(progress) {
return 1 - Math.sin(Math.acos(progress))
}
function back(progress) {
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5)
}
function bounce(progress) {
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
}
</script>
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
var y=document.getElementById("data"); // Για να δούμε ποιο είναι το progress
y.innerHTML=progress ;
if (progress > 1) progress = 1
var delta = opts.delta(progress)
var z=document.getElementById("data1"); // Για να δούμε ποιο είναι το delta
z.innerHTML=delta ;
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script><script>
function move(element, delta, duration) {
var to = 500
animate({
delay: 1000,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
var x=document.getElementById("box"); // Για να δούμε ποια είναι η θέση του box
x.innerHTML=element.style.left;
}
})
}</script>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
#box {font-weight:bold;}
#data {font-weight:bold;}
#data1 {font-weight:bold;}
</style>
</head>
<body>
Progress:<p id="data">Αρχικό.</p>
Delta:<p id="data1">Αρχικό 1.</p>
<div onclick="move(this.children[0], linear,60000)" class="example_path">
<div class="example_block"><span id="box">0</span></div>
</div></body></html>
Ease Out - EaseInOut
Το easeout είναι μια αντιστροφή της συνάρτησης. Στην περίπτωση του bounce για παράδειγμα, αντί να έχουμε κίνηση όπως δείχνει ο κόκκινη γραμμή έχουμε όπως η πράσινη. Δηλαδή φτάνουμε σχεδόν μέχρι το τέλος και μετά πισωγυρίζουμε (όπως η μπάλα που αναπηδά).
function makeEaseOut(delta) {
return function(progress) {
return 1 - delta(1 - progress)
}
}
Στο easeinout παίζουμε με το χρόνο και μειώνουμε το delta effect τόσο στην αρχή όσο και στο τέλος του animation.
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2
else
return (2 - delta(2*(1-progress))) / 2
}
}
Τα EaseOut και EaseInOut μπορούν να εφαρμοστούν σε όλες τις συναρτήσεις. Ας δούμε τη συμπεριφορά στη circ:
Το πλήρες παράδειγμα με EaseOut και EaseInOut
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function elastic(progress) {
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress)
}
function linear(progress) {
return progress
}
function quad(progress) {
return Math.pow(progress, 2)
}
function quint(progress) {
return Math.pow(progress, 5)
}
function circ(progress) {
return 1 - Math.sin(Math.acos(progress))
}
function back(progress) {
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5)
}
function bounce(progress) {
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2
else
return (2 - delta(2*(1-progress))) / 2
}
}
function makeEaseOut(delta) {
return function(progress) {
return 1 - delta(1 - progress)
}
}
</script>
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
var y=document.getElementById("data"); // Για να δούμε ποιο είναι το progress
y.innerHTML=progress ;
if (progress > 1) progress = 1
var delta = opts.delta(progress)
var z=document.getElementById("data1"); // Για να δούμε ποιο είναι το delta
z.innerHTML=delta ;
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script><script>
function move(element, delta, duration) {
var to = 500
animate({
delay: 1000,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
var x=document.getElementById("box"); // Για να δούμε ποια είναι η θέση του box
x.innerHTML=element.style.left;
}
})
}</script>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
#box {font-weight:bold;}
#data {font-weight:bold;}
#data1 {font-weight:bold;}
</style>
</head>
<body>
Progress:<p id="data">Αρχικό.</p>
Delta:<p id="data1">Αρχικό 1.</p>
<div onclick="move(this.children[0], makeEaseInOut(bounce),60000)" class="example_path">
<div class="example_block"><span id="box">0</span></div>
</div></body></html>
Μπάλα που αναπηδά
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function elastic(progress) {
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress)
}
function linear(progress) {
return progress
}
function quad(progress) {
return Math.pow(progress, 2)
}
function quint(progress) {
return Math.pow(progress, 5)
}
function circ(progress) {
return 1 - Math.sin(Math.acos(progress))
}
function back(progress) {
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5)
}
function bounce(progress) {
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2
else
return (2 - delta(2*(1-progress))) / 2
}
}
function makeEaseOut(delta) {
return function(progress) {
return 1 - delta(1 - progress)
}
}
</script>
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
if (progress > 1) progress = 1
var delta = opts.delta(progress)
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script>
<style>
#field {
height: 200px;
border-bottom: 3px black groove;
position: relative;
}
#ball {
position: absolute;
}
</style>
</head>
<body>
<div id="field">
<img src="ball.gif" width="40" height="40" id="ball">
</div>
<script>
var img = document.getElementById('ball')
img.onclick = function() {
var to = document.getElementById('field').clientHeight - img.clientHeight
animate({
delay: 20,
duration: 1000,
delta: makeEaseOut(bounce),
step: function(delta) {
img.style.top = to*delta + 'px'
}
})
}
</script></body></html>
Ας χρησιμοποιήσουμε τώρα όσα γνωρίζουμε για να συνδιάσουμε 2 κινήσεις και να κάνουμε την μπάλα να κινείται προς τα εμπρός καθώς αναπηδά. Ο κώδικας στο <body> είναι:
<body>
<div id="field">
<img src="ball.gif" width="40" height="40" id="ball">
</div><script>
var img = document.getElementById('ball')
img.onclick = function() {
var height = document.getElementById('field').clientHeight - img.clientHeight
var width = 100
animate({
delay: 20,
duration: 1000,
delta: makeEaseOut(bounce),
step: function(delta) {
img.style.top = height*delta + 'px'
}
})
animate({
delay: 20,
duration: 1000,
delta: makeEaseOut(quad),
step: function(delta) {
img.style.left = width*delta + "px"
}
})
}
</script></body></html>
Animation χρώματος
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function elastic(progress) {
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress)
}
function linear(progress) {
return progress
}
function quad(progress) {
return Math.pow(progress, 2)
}
function quint(progress) {
return Math.pow(progress, 5)
}
function circ(progress) {
return 1 - Math.sin(Math.acos(progress))
}
function back(progress) {
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5)
}
function bounce(progress) {
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2
else
return (2 - delta(2*(1-progress))) / 2
}
}
function makeEaseOut(delta) {
return function(progress) {
return 1 - delta(1 - progress)
}
}
</script>
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
if (progress > 1) progress = 1
var delta = opts.delta(progress)
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
</script><script>
function highlight(elem, delta) {
var from = [255,0,0], to = [255,255,255]
animate({
delay: 10,
duration: 1000,
delta: delta,
step: function(delta) {
elem.style.backgroundColor = 'rgb(' +
Math.max(Math.min(parseInt((delta * (to[0] - from[0])) + from[0], 10), 255), 0) + ',' +
Math.max(Math.min(parseInt((delta * (to[1] - from[1])) + from[1], 10), 255), 0) + ',' +
Math.max(Math.min(parseInt((delta * (to[2] - from[2])) + from[2], 10), 255), 0) + ')'
}
})
}
</script><style></style></head><body>
<div onclick="highlight(this, linear)" style="font-size:150%">Click για κίνηση</div>
</body></html>
Δοκιμάστε και το ίδιο με: makeEaseOut(bounce) αντί για linear.
Παράδειγμα με animation input.
Αλλάξτε το body σε:
<body>
<p><input id="textExample" size=200 style="border: 1px solid #BBB; color:#444" value="Η Εκκλησία της Αγγλίας ψήφισε εναντίον της χειροτονίας γυναικών στον επισκοπικό θρόνο, δίνοντας τέλος σε έναν διάλογο που είχε διχάσει το ποίμνιο επί 12 χρόνια.">
<p><button onclick="animateText(document.getElementById('textExample'))">Γράψε!</button></p></body>
Αντικαταστήστε την function highlight με την:
<script>
function animateText(textArea) {
var text = textArea.value
var to = text.length, from = 0
animate({
delay: 20,
duration: 5000,
delta: bounce,
step: function(delta) {
var result = (to-from) * delta + from
textArea.value = text.substr(0, Math.ceil(result))
}
})
}
</script>
και δοκιμάστε το.
CSS Transitions
Με το CCS 3 μπορούμε να ομαλοποιήσουμε τις αλλαγές στα CSS. Στο παράδειγμα που ακολουθεί το χρώμα δεν θα αλλάξει αμέσω αλλά σε διάστημα 2 δευτερολέπτων. Δυστυχώς η κλήση πρέπει να γίνεται με διαφορετικό τρόπο ανάλογα τον browser του χρήστη. Αν λοιπόν για ένα γενικό:
.animated {
transition-property: background-color;
transition-duration: 2s;
}
πρέπει να δηλωθεί όπως φαίνεται στο παράδειγμα:
<!DOCTYPE HTML>
<html><head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style>
.animated {
transition: background-color 2s;
-webkit-transition: background-color 2s;
-o-transition: background-color 2s;
-moz-transition: 2s;
}
</style></head><body>
<div class="animated" onclick="this.style.backgroundColor='red'">
<span style="font-size:150%">Click για χρωματικό animation (δεν λειτουργεί σε IE<10, και FF<4)</span>
</div>
</body></html>
Λιγότερη δουλειά για τον Browser
Το προηγούμενο παράδειγμα σχεδιάζει τη σελίδα από την αρχή μετά από κάθε κίνηση του div. Αυτό όμως επιβαρύνει πολύ τον Browser και αν θέλουμε περίπλοκες κινήσεις ή πολλά αντικείμενα ο υπολογιστής του χρήστη δεν θα μπορέσει να ανταποκριθεί.
Ακόμη όμως και αν μπορέσει η κίνηση δεν θα είναι ομαλή. Κάντε τα 20msec 2 στο προηγούμενο παράδειγμα και θα δείτε πόσο πιο κοφτή γίνεται η κίνηση.
Επίσης αν υπάρχουν πολλοί διαφορετικοί timers αυτό κάνει πολύ περίπλοκη τη διεργασία. Καλύτερα όλα τα objects να συγχρονίζονται με τον ίδιο timer και να κινούνται ταυτόχρονα με ένα μόνο redraw από τον Browser.
Επίσης, όσο πιο εσωτερικό (nested) είναι το κινούμενο element τόσο περισσότερη δουλειά πρέπει να κάνει ο browser για να υπολογίσει τα γύρω του πριν φτάσει σε αυτό.
Προχωρημένο CANVAS
Transformations
Translate
Με την translate() μπορούμε να μεταφέρουμε μέρη του Canvas από ένα σημείο σε ένα άλλο (αλλάζει η θέση του 0,0 σε ό,τι του πούμε). Φυσικά κάτι τέτοιο μπορεί να γίνει και με το χέρι αλλά για ένα περίπλοκο γραφικό για παράδειγμα είναι ευκολότερο να του δώσουμε ένα όνομα και να το μεταφέρουμε όλο μαζί σε άλλο σημείο.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
// translate context to center of canvas
context.translate(canvas.width / 2, canvas.height / 2);
context.fillStyle = 'blue';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
</script>
</body>
</html>
Στον παραπάνω κώδικα φτιάξαμε απλώς ένα τετράγωνο. Χωρίς το translate θα εμφανιζόταν στο 0,0. (γιατί αρνητικές τιμές μεταφράζονται σε μηδέν) με αυτό στο canvas.width / 2, canvas.height / 2.
Εδώ μεταφράσαμε όλο το context οπότε μεταφέρθηκαν τα πάντα στη νέα θέση.
Στο επόμενο έχουμε μερικά τετράγωνα. Αλλάζει θέση μόνο όποιο βρίσκεται μετά την translate.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
context.fillStyle = 'blue';
context.fillRect(2, 2, rectWidth, rectHeight);
context.fillRect(100, 100, rectWidth, rectHeight);
context.translate(canvas.width / 2, canvas.height / 2);
context.fillRect(2, 2, rectWidth, rectHeight);
</script>
</body>
</html>
Μεταφέρετε το 2ο τετράγωνο μετά την translate και θα πάψει να φαίνεται διότι πιάνει την ίδια θέση με το τρίτο.
Κάθε νέο translate δίνει τιμές που προστίθενται στις ήδη υπάρχουσες.
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
context.fillStyle = 'blue';
context.fillRect(2, 2, rectWidth, rectHeight);
context.fillStyle = 'red';
context.translate(canvas.width / 2, canvas.height / 2);
context.fillRect(2, 2, rectWidth, rectHeight);
context.fillStyle = 'yellow';
context.translate(50, 50);
context.fillRect(2, 2, rectWidth, rectHeight);
</script>
</body>
</html>
Scale
Στο ίδιο παράδειγμα αμέσως μετά την translate προσθέστε τη γραμμή:
context.scale(1, 0.5);
Η σύνταξη είναι:
context.scale(scalewidth,scaleheight);
Στο παράδειγμά μας κρατάμε την ίδια κλίμακα στο πλάτος και το μισό ύψος.
Στο ακόλουθο παράδειγμα έχουμε το ίδιο ορθογώνιο με άλλο scale.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.strokeRect(5,5,25,15);
context.scale(2,2);
context.strokeRect(5,5,25,15);
</script>
</body>
</html>
Παρατηρούμε πως τα δύο ορθογώνια δεν πέφτου το ένα πάνω στο άλλο διότι γίνονται scale και οι θέσεις τους!
Ό,τι καινούριο κατασκευαστεί θα έχει πλέον το ίδιο scale. Μετά τα άλλα ορθογώνια για να επιστρέψετε στο σωστό scale προσθέστε το:
context.scale(0.5,0.5);
context.strokeRect(55,55,25,15);
Βάση πλέον είναι το νέο scale οπότε πρέπει να πάμε στο μισό του..
Rotate
Η σύνταξη είναι:
context.rotate(angle);
Όπου angle είναι τα radians της περιστροφής.
Τροποποιόντας το προηγούμενο παράδειγμα προσθέτουμε rotation (περιστροφή) με το:
context.rotate(Math.PI / 4);
Αυτό θα περιστρέψει κατά 45 μοίρες το κουτί μας.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
// translate context to center of canvas
context.translate(canvas.width / 2, canvas.height / 2);
// rotate 45 degrees clockwise
context.rotate(Math.PI / 4);
context.fillStyle = 'blue';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
</script>
</body>
</html>
Βάλτε το κουτί:
context.fillStyle = 'blue';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
πάνω και κάτω από το rotate για να δείτε τη μεταβολή.
context.rotate(20*Math.PI/180)΄= 20 μοίρες περιστροφή.
Χρησιμοποιήστε αρνητικές τιμές για περιστροφή αντίθετα από τους δείκτες του ρολογιού.
Transform -setTransform
Η σύνταξη είναι:
context.transform(a,b,c,d,e,f);
a Scales the drawing horizontally
b Skew (γύρε) the drawing horizontally
c Skew (γύρε) the drawing vertically
d Scales the drawing vertically
e Moves the drawing horizontally
f Moves the drawing vertically
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
context.fillStyle="yellow";
context.fillRect(0,0,250,100)
context.transform(1,0.5,-0.5,1,30,10);
context.fillStyle="red";
context.fillRect(0,0,250,100);
context.transform(1,0.5,-0.5,1,30,10);
context.fillStyle="blue";
context.fillRect(0,0,250,100);
</script>
</body>
</html>
Η transform method εκτελείται σε σχέση με άλλες transformations που έκαναν οι rotate(), scale(), translate(), ή transform().
Για να δείτε τη διαφοροποίηση διαγράψτε το κόκκινο ορθογώνιο και θα δείτε πως το μπλε μπαίνει στη θέση του.
Αν δεν θέλουμε να δουλέψουμε με αναλογική διαφοροποίηση χρησιμοποιούμε την setTransform().
Αλλάζοντας το παράδειγμα σε:
context.setTransform(1,0.5,-0.5,1,30,10);
context.fillStyle="red";
context.fillRect(0,0,250,100);
context.setTransform(1,0.5,-0.5,1,30,10);
context.fillStyle="blue";
context.fillRect(0,0,250,100);
Πλέον το κόκκινο ορθογώνιο δεν φαίνεται γιατί επάνω του έχει μπει το μπλε αφού πλέον έχουν την ίδια θέση.
Η setTransform χρησιμοποιείται επίσης για να κάνω reset μια Transform και να σταματήσουμε τα transformations που αυτή παράγει:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
// translate context to center of canvas
context.translate(canvas.width / 2, canvas.height / 2);
context.fillStyle = 'blue';
context.fillRect(-rectWidth / 2, rectHeight / -2, rectWidth, rectHeight);
// Reset Transform
// 1 0 0
// 0 1 0
// 0 0 1
// apply custom transform
context.setTransform(1, 0, 0, 1, 0, 0);
context.fillStyle = 'red';
context.fillRect(0, 0, rectWidth, rectHeight);
</script>
</body>
</html>
Εφέ παραμόρφωσης με transform:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
// shear matrix:
// 1 sx 0
// sy 1 0
// 0 0 1
var sx = 0.75;
// .75 horizontal shear
var sy = 0;
// no vertical shear
// translate context to center of canvas
context.translate(canvas.width / 2, canvas.height / 2);
// apply custom transform
context.transform(1, sy, sx, 1, 0, 0);
context.fillStyle = 'blue';
context.fillRect(-rectWidth / 2, rectHeight / -2, rectWidth, rectHeight);
</script>
</body>
</html>
Εδώ έχουμε οριζόντια κλήση με σταθερή την κλίμακα (οριζόντια και κάθετα) και χωρίς μετακίνηση.
Βάλτε και var sy = .75; για να δείτε κάθετη κλίση. Επίσης βάλτε 0 οριζόντια και 0.75 κάθετη.
Κατοπτρικό εφέ.
Με το context.scale(1, 1) επιτυγχάνουμε οριζόντιο εφέ αντιστροφής. Με το context.scale(1, -1) κάθετης αντιστροφής.
Το context.scale(1, 1) είναι το φυσιολογικό.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// translate context to center of canvas
context.translate(canvas.width / 2, canvas.height / 2);
// flip context horizontally
context.scale(-1, 1);
context.font = '30pt Calibri';
context.textAlign = 'center';
context.fillStyle = 'blue';
context.fillText('Hello World!', 0, 0);
</script>
</body>
</html>
Save και Restore States
Αν θέλω η εφαρμογή μου να θυμάμαι κάποιες ρυθμίσεις και να τις ανακτήσει μετά χρησιμοποιώ τα Save και Restore.
Απλό παράδειγμα με ένα save και ένα restore:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
context.save();
// Κάνω save την translate που ακολουθεί
context.translate(canvas.width / 2, canvas.height / 2);
// Ζωγραφίζω (ισχύει η παραπάνω translate).
context.fillStyle = 'blue';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
context.restore();
/* Κάνω restore την κατάσταση πριν το save (δηλαδή πριν την translate) και ζωγραφίζω κάτι άλλο.
Τώρα έχει εφαρμογή ό,τι ισχύε πριν το save. */
context.fillStyle = 'green';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
</script>
</body>
</html>
Αν έχω περισσότερα από ένα save το restore γίνεται αντίστροφα (πρώτα καλείται το τελευταίο, μετά το προτελευταίο κ.ο.κ. μέχρι να φτάσω στο πρώτο save που καλείται τελευταίο (αφού έχουν κληθεί όλα τα άλλα).
Παράδειγμα με πολλά save και restore:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
context.save();
// save state 1
context.translate(canvas.width / 2, canvas.height / 2);
context.save();
// save state 2
context.rotate(Math.PI / 4);
context.save();
// save state 3
context.scale(2, 2);
/* Το μπλε ορθογώνιο έχει όλες τις ιδιότητες (κέντρο, rotated και διπλάσιο) */
context.fillStyle = 'blue';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
context.restore();
// restore state 3
/* Το κόκκινο ορθογώνιο έχει τις 2 αρχικές ιδιότητες (κέντρο και rotated αλλά όχι διπλάσιο) */
context.fillStyle = 'red';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
context.restore();
// restore state 2
/* Το κίτρινο ορθογώνιο έχει την αρχική ιδιότητα (κέντρο αλλά δεν είναι rotated ούτε διπλάσιο) */
context.fillStyle = 'yellow';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
context.restore();
// restore state 1
/* Το πράσινο ορθογώνιο δεν έχει καμία από τις αρχικές ιδιότητες */
context.fillStyle = 'green';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
</script>
</body>
</html>
Πολλαπλές ρυθμίσεις στο ίδιο save:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rectWidth = 150;
var rectHeight = 75;
context.save();
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(Math.PI / 4);
context.scale(2, 2);
/* Το μπλε ορθογώνιο έχει όλες τις ιδιότητες (κέντρο, rotated και διπλάσιο) */
context.fillStyle = 'blue';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
/* Αποθηκεύτηκαν και οι 3 ρυθμίσεις στο ίδιο save οπότε με το restore φεύγουν και οι τρεις. */
context.restore();
/* Το κόκκινο ορθογώνιο έχει χάσει όλες τις ιδιότητες */
context.fillStyle = 'red';
context.fillRect(rectWidth / -2, rectHeight / -2, rectWidth, rectHeight);
</script>
</body>
</html>
Δημιουργία οβάλ σχήματος
Για να φτιάξω ένα οβάλ σχήμα χρησιμοποιώ την scale για να κάνω stretch οριζόντια έναν κύκλο. Στη συνέχεια κάνω restore τις αρχικές ρυθμίσεις για την εμφάνιση.
Το παράδειγμα έχει δύο canvas, ένα με restore και ένα χωρίς. Βλέπουμε πως η διαφορά είναι στο lineWidthόπου κρατάει και αυτό το scaling και δεν έχει το ίδιο πλάτος σε όλα τα σημεία γύρω από το οβάλ.
Κάντε commend το lineWidth και στα δύο canvas και θα δείτε πως τα σχήματα είναι πλέον ίδια.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas1 {
border: 1px solid #9C9898;
}
#myCanvas2 {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas1" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas1');
var context = canvas.getContext('2d');
var centerX = 0;
var centerY = 0;
var radius = 50;
context.save();
// translate context
context.translate(canvas.width / 2, canvas.height / 2);
// scale context horizontally
context.scale(2, 1);
// draw circle which will be stretched into an oval
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.restore();
// apply styling
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = 5;
context.strokeStyle = 'black';
context.stroke();
</script>
<br>
<canvas id="myCanvas2" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas2');
var context = canvas.getContext('2d');
var centerX = 0;
var centerY = 0;
var radius = 50;
// translate context
context.translate(canvas.width / 2, canvas.height / 2);
// scale context horizontally
context.scale(2, 1);
// draw circle which will be stretched into an oval
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// apply styling
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = 5;
context.strokeStyle = 'black';
context.stroke();
</script>
</body>
</html>
Δημιουργία Σκιών
Το χρώμα της σκιάς:
context.shadowColor = 'blue';
Μαζί με τη shadowColor χρησιμοποιούμε και τη shadowBlur όπου δίνουμε το βαθμό θολότητας (default το 0). Όσο πιο μεγάλο είναι το νούμερο τόσο μεγαλύτερο το gradient της σκιάς.
context.shadowBlur = 20;
Δοκιμάστε με context.shadowBlur = 200 για να δείτε τη διαφορά.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.rect(188, 40, 200, 100);
context.fillStyle = 'red';
context.shadowColor = '#999';
context.shadowBlur = 20;
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
context.fill();
</script>
</body>
</html>
Χωρίς τα:
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
Η σκιά θα περιτριγυρίζει το σχήμα.
Η shadowOffsetX θα μετατοπίσει τη σκιά Χ pixels προς τα δεξιά (αρνητικά νούμερα για αριστερά). Ομοίως προς τα κάτω θα κάνει ή shadowOffsetY (αρνητικό για επάνω).
Διαφάνεια (Global Alpha)
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw blue rectangle
context.beginPath();
context.rect(200, 20, 100, 100);
context.fillStyle = 'blue';
context.fill();
// draw transparent red circle
context.globalAlpha = 0.5;
context.beginPath();
context.arc(320, 120, 60, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
</script>
</body>
</html>
Η globalAlpha παίρνει τιμές από 0 (διάφανο) έως 1 (πλήρως αδιαφανές).
Δοκιμάστε να ζωγραφίσετε άλλο ένα τετράγωνο (στον κώδικα κάτω από τον κύκλο) με τα χαρακτηριστηκά:
context.beginPath();
context.rect(300, 20, 100, 100);
context.fillStyle = 'green';
context.fill();
Αν δεν δηλώσουμε νέο globalAlpha θα ισχύει η διαφάνεια που ορίστηκε παραπάνω.
Clip()
Με το clipping μπορούμε να απομονώσουμε μια περιοχή. Ό,τι ενέργειες εκτελεστούν μετά την clip() αφορούν μόνο τη δική της περιοχή. Το υπόλοιπο Canvas είναι απροσπέλαστο μέχρι να κάνουμε restore.
Απλό παράδειγμα:
<!DOCTYPE html>
<html>
<body>
<span>Without clip():</span>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// Draw a rectangle
ctx.rect(50,20,200,120);
ctx.stroke();
// Draw red rectangle
ctx.fillStyle="red";
ctx.fillRect(0,0,150,100);
</script>
<span>With clip():</span>
<canvas id="myCanvas2" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas2");
var ctx=c.getContext("2d");
// Clip a rectangular area
ctx.rect(50,20,200,120);
ctx.stroke();
ctx.clip();
// Draw red rectangle after clip()
ctx.fillStyle="red";
ctx.fillRect(0,0,150,100);
</script>
</body>
</html>
Πιο περίπλοκο παράδειγμα:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var offset = 50;
/* Πρώτα κάνουμε save() ώστε να μπορέσουμε μετά να επιστρέψουμε στην πρότερη κατάσταση (πριν το clip) */
context.save();
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false); // Αυτή είναι η περιοχή του clip
context.clip();
/* Ζωγραφίζουμε μπλε κύκλο στην clipping region. Το κέντρο βρίσκεται εκτός οπότε ο κύκλος δεν εμφανίζεται ολόκληρος. Μόνο το μέρος του που βρίσκεται μέσα στο clip. */
context.beginPath();
context.arc(x - offset, y - offset, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'blue';
context.fill();
/* Ζωγραφίζουμε κίτρινο κύκλο στην clipping region. Το κέντρο βρίσκεται εντός αλλά ο κύκλος δεν χωράει οπότε δεν εμφανίζεται ολόκληρος. Μόνο το μέρος του που βρίσκεται μέσα στο clip. */
context.beginPath();
context.arc(x + offset, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'yellow';
context.fill();
/* Ζωγραφίζουμε κόκκινο κύκλο στην clipping region. Ισχύει ό,τι και στα υπόλοιπα */
context.beginPath();
context.arc(x, y + offset, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
/*
Το restore() μας επιστρέφει στην πριν το clip κατάσταση
*/
context.restore();
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.lineWidth = 10;
context.strokeStyle = 'green';
context.stroke();
</script>
</body>
</html>
Για να καταλάβετε καλύτερα τι συμβαίνει κάντε commend τους δύο κύκλους κάθε φορά και δείτε τι φαίνεται από τον τρίτο.
globalCompositeOperation
Σύνταξη: globalCompositeOperation="source-in";
Με αυτή τη μέθοδο ορίζουμε πως θα εμφανιστεί κάτι σε σχέση με κάτι άλλο που υπάρχει ήδη στο σημείο προορισμού του:
Οι διαθέσιμες ιδιότητες είναι:
Value Description
source-over Default. Displays the source image over the destination image
source-atop Displays the source image on top of the destination image. The part of the source image that is outside the destination image is not shown
source-in Displays the source image in to the destination image. Only the part of the source image that is INSIDE the destination image is shown, and the destination image is transparent
source-out Displays the source image out of the destination image. Only the part of the source image that is OUTSIDE the destination image is shown, and the destination image is transparent
destination-over Displays the destination image over the source image
destination-atop Displays the destination image on top of the source image. The part of the destination image that is outside the source image is not shown
destination-in Displays the destination image in to the source image. Only the part of the destination image that is INSIDE the source image is shown, and the source image is transparent
destination-out Displays the destination image out of the source image. Only the part of the destination image that is OUTSIDE the source image is shown, and the source image is transparent
lighter Displays the source image + the destination image
copy Displays the source image. The destination image is ignored
xor The source image is combined by using an exclusive OR with the destination image
Απλό παράδειγμα με source-over και destination-over:
<!DOCTYPE html>
<html><body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(20,20,75,50);
ctx.fillStyle="blue";
ctx.globalCompositeOperation="source-over";
ctx.fillRect(50,50,75,50);
ctx.fillStyle="red";
ctx.fillRect(150,20,75,50);
ctx.fillStyle="blue";
ctx.globalCompositeOperation="destination-over";
ctx.fillRect(180,50,75,50);
</script></body></html>
destination-atop source-atop
Αλλάξτε το destination-over σε destination-atop για να δείτε πως τα δύο τετράγωνα συνδυάζονται σε ένα.
Στο ίδιο παράδειγμα αλλάξτε το source-over σε source atop και κρατήστε το δεύτερο μέρος ως destination-atop. Θα δείτε πως το παράδειγμα δεν λειτουργεί. Αν όμως διαγράψετε το δύο τελευταία κουτιά λειτουργεί:
<!DOCTYPE html>
<html><body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(20,20,75,50);
ctx.fillStyle="blue";
ctx.globalCompositeOperation="source-atop";
ctx.fillRect(50,50,75,50);
</script></body></html>
Ο λόγος είναι πως μπορούμε να έχουμε μόνο ένα globalCompositeOperation σε κάθε Canvas. Βάλαμε δύο στο αρχικό παράδειγμα επειδή το πρώτο ήταν source-over που είναι η default λειτουργία.
Source-in
<!DOCTYPE html>
<html><body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById('myCanvas');
var ctx=c.getContext('2d');
ctx.fillStyle='blue';
ctx.fillRect(10,10,50,50);
ctx.globalCompositeOperation='source-in';
ctx.beginPath();
ctx.fillStyle='red';
ctx.arc(50,50,30,0,2*Math.PI);
ctx.fill();
</script></body></html>
Source-out
Ίδιο με το παραπάνω αλλά:
ctx.globalCompositeOperation='source-out';
Destination-in
ctx.globalCompositeOperation='destination-in';
Destination-out
ctx.globalCompositeOperation='destination-out';
Lighter
ctx.globalCompositeOperation='lighter';
Copy
ctx.globalCompositeOperation='copy';
Xor
ctx.globalCompositeOperation='xor';
Hidden Canvas
Η globalCompositeOperation επιτρέπει τη χρήση της μόνο μια φορά σε κάθε Canvas. Για να το παρακάμψουμε αυτό θα χρησιμοποιήσουμε ένα κρυφό Canvas.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="430"></canvas>
<canvas id="tempCanvas" width="578" height="430" style="display:none;"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var tempCanvas = document.getElementById('tempCanvas');
var tempContext = tempCanvas.getContext('2d');
var squareWidth = 55;
var circleRadius = 35;
var shapeOffset = 50; // Η απόσταση του δεύτερου σχήματος (του κύκλου) από το πρώτο.
var operationOffset = 150;
// Φτιάχνουμε μια array με όλες τις ρυθμίσεις της globalCompositeOperation
var arr = [];
arr.push('source-atop');
arr.push('source-in');
arr.push('source-out');
arr.push('source-over');
arr.push('destination-atop');
arr.push('destination-in');
arr.push('destination-out');
arr.push('destination-over');
arr.push('lighter');
arr.push('darker');
arr.push('xor');
arr.push('copy');
// Βάζουμε 10px για padding
context.translate(10, 10);
// Ζωγραφίζουμε μια μια της διαφορετικές περιπτώσεις που έχουμε βάλει στην Array.
for(var n = 0; n < arr.length; n++) {
var thisOperation = arr[n];
tempContext.save();
// Αδειάζω το temp context από ό,τι περιείχε.
tempContext.clearRect(0, 0, canvas.width, canvas.height);
// Ζωγραφίζω το ορθογώνιο (destination)
tempContext.beginPath();
tempContext.rect(0, 0, squareWidth, squareWidth); // Ζωγραφίζω πάνω αριστερά.
tempContext.fillStyle = 'blue';
tempContext.fill();
// Ορίζω το global composite
tempContext.globalCompositeOperation = thisOperation;
// Ζωγραφίζω τον κύκλο (source)
tempContext.beginPath();
tempContext.arc(shapeOffset, shapeOffset, circleRadius, 0, 2 * Math.PI, false);
tempContext.fillStyle = 'red';
tempContext.fill();
tempContext.restore();
/* Αφού ζωγραφίσω επαναφέρω το παλιό context (πριν γίνει η ζωγραφική) ώστε να έχουμε την πρότερη κατάσταση. */
// Βάζω το κείμενο.
tempContext.font = '10pt Verdana';
tempContext.fillStyle = 'black';
tempContext.fillText(thisOperation, 0, squareWidth + 45);
// translate visible context so operation is drawn in the right place
/* Τώρα ασχολούμαι με το visible context. Κάθε κρυφό Canvas πρέπει να εμφανιστεί. Ουσιαστικά το εμφανίζω κάθε φορά ολόκληρο αλλά το επόμενο που θα έρθει πατάει πάνω στο προηγούμενο και κρύβει ένα μέρος του. Φυσικά φροντίζω κάθα φορά να το πάω πιο δεξιά ή και πιο κάτω ώστε να μην κρυφτούν τα προηγούμενα που θέλω. */
if(n > 0) {
if(n % 4 === 0) {
context.translate(operationOffset * -3, operationOffset);
/* Αφού βάζω 4 σχήματα (άρα 4 temp canvas) σε κάθε γραμμή αν το n διαιρείται ακριβώς με το 4 πηγαίνει 3 θέσεις αριστερά στο οριζόντιο και τα καθορισμένα pixels προς τα κάτω στο κάθετο. */
}
else {
context.translate(operationOffset, 0);
/* Αν δεν χρειάζεται να αλλάξω γραμμή απλώς βάζω με το translate λίγο πιο δεξιά το κρυφό canvas*/
}
}
/* Στην πρώτη τοποθέτηση δεν χρειάζεται να κινηθεί κάτι. Το κρυφό Canvas μπαίνει πάνω αριστερά στο ορατό. */
// Τοποθετώ το tempCanvas στο visible canvas
context.drawImage(tempCanvas, 0, 0);
}
</script>
</body>
</html>
Για να φανεί καλύτερα τι πραγματικά συμβαίνει με το κρυφό canvas μπορείτε μετάξυ του ορθογωνίου και του κύκλου να προσθέσετε:
tempContext.moveTo(10,10);
tempContext.lineTo(squareWidth * '3',10);
tempContext.stroke();
Έτσι είναι ορατό το υπόλοιπο Canvas όσο αυτό είναι εφικτό (σε κάποια το καλύπτει το globalCompositeOperation
Λήψη όλων των δεδομένων εμφάνισης ενός Canvas
Αρχικά ας φτιάξουμε ένα Canvas με μια εικόνα:
Θα πάρουμε και θα διαβάσουμε ένα από τα pixels της εικόνας με την getImageData.
Η σύνταξη είναι: context.getImageData(x,y,width,height);
Στο x,y έχουμε το πάνω αριστερό τμήμα και στο width,height το πλάτος και ύψος της περιοχής που θα διαβαστεί.
<!DOCTYPE html>
<html><body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
<script>
var c=document.getElementById("myCanvas");
var context=c.getContext("2d");
context.fillStyle="red";
context.fillRect(10,10,50,50);
var imgData=context.getImageData(30,30,50,50);
var red=imgData.data[0];
var green=imgData.data[1];
var blue=imgData.data[2];
var alpha=imgData.data[3];
var foundData = red + " " + green + " " + blue + " " + alpha;
context.font = '30pt Calibri';
context.fillStyle = 'blue';
context.fillText(foundData , 60, 60);
// alert(foundData);
</script></body></html>
Στη συνέχεια θα διαβάσουμε ένα ένα όλα τα δεδομένα:
<!DOCTYPE html>
<html><body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
<script>
var c=document.getElementById("myCanvas");
var context=c.getContext("2d");
context.fillStyle="red";
context.fillRect(10,10,50,50);
var imageData=context.getImageData(30,30,50,50);
var data = imageData.data;
var foundData = "";
// Τώρα διαβάζουμε ένα ένα τα δεδομένα για όλα τα pixels
for(var i = 0, n = data.length; i < n; i += 4) {
var red = data[i];
var green = data[i + 1];
var blue = data[i + 2];
var alpha = data[i + 3];
if (i <8) // Κρατάμε πληροφορίες μόνο τα δύο πρώτα pixels
foundData += red + " " + green + " " + blue + " " + alpha + "|";
}
context.font = '8pt Calibri';
context.fillStyle = 'blue';
context.fillText(foundData , 60, 60);
</script></body></html>
Μπορούμε επίσης να διαβάσουμε τα pixels με βάση τις συντεταγμένες τους:
Πρώτα κοιτάμε μια μια τις γραμμές
for(var y = 0; y < sourceHeight; y++) {
Στη συνέχεια κοιτάμε μια μια τις στήλες
for(var x = 0; x < sourceWidth; x++) {
var red = data[((sourceWidth * y) + x) * 4];
var green = data[((sourceWidth * y) + x) * 4 + 1];
var blue = data[((sourceWidth * y) + x) * 4 + 2];
var alpha = data[((sourceWidth * y) + x) * 4 + 3];
}
}
Ας φτιάξουμε τώρα ένα Canvas με μια εικόνα:
<!DOCTYPE HTML>
<html><head><style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style></head><body>
<canvas id="myCanvas" width="300" height="200"></canvas>
<script>
function drawImage(imageObj) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageX = 10;
var imageY = 10;
var imageWidth = imageObj.width;
var imageHeight = imageObj.height;
context.drawImage(imageObj, imageX, imageY);
}
var imageObj = new Image();
imageObj.onload = function() {
drawImage(this);
};
imageObj.src = 'http://www.eeei.gr/images/eeeil1.jpg';
</script></body></html>
Image Editing on the Fly
Θα πάρουμε τώρα και θα διαβάσουμε ένα ένα τα pixels της εικόνας με την getImageData. Τα δεδομένα για τα pixels θα μπουν μέσα στην Array data.
Στη συνέχεια θα αλλάξουμε όλα τα χρώματα με τα αντίθετά τους.
Η getImageData θα λειτουργήσει μόνο αν η σελίδα μας βρίσκεται στο ίδιο domain με αυτό που μας έδωσε την εικόνα.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
function drawImage(imageObj) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 69;
var y = 50;
context.drawImage(imageObj, x, y);
var imageData = context.getImageData(x, y, imageObj.width, imageObj.height);
var data = imageData.data;
/* Με την for κάνουμε αντιστροφή όλων των χρωμάτων */
for(var i = 0; i < data.length; i += 4) {
// red
data[i] = 255 - data[i];
// green
data[i + 1] = 255 - data[i + 1];
// blue
data[i + 2] = 255 - data[i + 2];
}
// Κάνουμε overwrite την αρχική εικόνα.
context.putImageData(imageData, x, y);
}
var imageObj = new Image();
imageObj.onload = function() {
drawImage(this);
};
imageObj.src = 'http://www.gepiti.com/tests/eeei1.jpg';
</script>
</body>
</html>
Αν στη for προσθέσουμε και data[i + 3] = 100 θα αλλάξουμε και το opacity (τη διαφάνεια)
Για να κοκκινίσουμε την εικόνα: data[i] = 255 - 100;
Για να κάνουμε Grayscale την εικόνα αλλάζουμε τη for ως ακολούθως:
for(var i = 0; i < data.length; i += 4) {
var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
// red
data[i] = brightness;
// green
data[i + 1] = brightness;
// blue
data[i + 2] = brightness;
}
Αποφασίζω κάθε χρώμα πόσο θα συμμετέχει στη συνολική φωτεινότητα και δίνω την ίδια τιμή σε όλα.
Δημιουργία image από Canvas
Για να επιτύχουμε αυτό το εφέ θα χρησιμοποιήσουμε την toDataURL. Εξ ορισμού κατασκευάζεται png αλλά μπορούμε να φτιάξουμε και jpg εικόνα και από 0 έως 1 ορίζουμε την ποιότητά της. 1 = η καλύτερη ποιότητα.
Η σύνταξη είναι:
<script>
// get png data url
var pngUrl = canvas.toDataURL();
// get jpeg data url
var jpegUrl = canvas.toDataURL('image/jpeg');
// get low quality jpeg data url
var lowQualityJpegUrl = canvas.toDataURL('image/jpeg', 0.2);
</script>
Δείτε ένα παράδειγμα χωρίς jQuery που ανοίγει κατευθείαν νέο παράθυρο με jpeg image.:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL('image/jpeg');
window.open(dataURL , "toDataURL() image", "width=600, height=200");
</script>
</body>
</html>
Σε αυτό το παράδειγμα χρησιμοποιούμε και jQuery για το άνοιγμα στα textarea (δεν είναι απαραίτητο στην HTML 5).
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
</script>
<script type="text/javascript">
$(document).ready(function() {
drawEx1();
$("#buttonTextArea").click(function() {
var canvas = document.getElementById("ex1");
var dataUrl = canvas.toDataURL();
document.getElementById("textArea").value = dataUrl;
});
$("#buttonWindow").click(function(){
var canvas = document.getElementById("ex1");
var dataUrl = canvas.toDataURL();
window.open(dataUrl, "toDataURL() image", "width=600, height=200");
});
});
</script>
</head>
<body>
<canvas id="ex1" width="500" height="100" style="border: 1px solid #cccccc;">
HTML5 Canvas not supported
</canvas>
<script>
function drawEx1() {
var canvas = document.getElementById("ex1");
var context = canvas.getContext("2d");
context.font = "36px Verdana";
context.fillStyle = "#000000";
context.fillText("HTML5 Canvas Text", 50, 50);
context.font = "normal 36px Arial";
context.strokeStyle = "#000000";
context.strokeText("HTML5 Canvas Text", 50, 90);
}
</script>
<br/><br/>
<input id="buttonTextArea" type="button" value="Show in textarea"/>
<input id="buttonWindow" type="button" value="Show in new window"/>
<textarea id="textArea" cols="60" rows="10"></body></html>
Χρήση ήδη κατασκευασμένου data2URL
Αν έχουμε ήδη δημιουργήσει το image μπορούμε να το φορτώσουμε με ένα AJAX call.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function loadCanvas(dataURL) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// load image from data url
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(this, 0, 0);
};
imageObj.src = dataURL;
}
// make ajax call to get image data url
var request = new XMLHttpRequest();
request.open('GET', 'http://www.gepiti.com/tests/dataURL.txt', true);
request.onreadystatechange = function() {
// Makes sure the document is ready to parse.
if(request.readyState == 4) {
// Makes sure it's found the file.
if(request.status == 200) {
loadCanvas(request.responseText);
}
}
};
request.send(null);
</script>
</body>
</html>
Canvas Background
Μπορείτε να βάλετε φόντο στο canvas σας μέσω CSS και HTML. Δεν θα εμφανιστεί όμως από την toDataURL
Η σύνταξη είναι γνωστή:
canvas { background:url(http://www.eeei.gr/images/eeeil1.jpg) }
Canvas Animation
Reset Canvas
Υπάρχουν διάφοροι τρόποι να καθαρίσουμε το Canvas ώστε να αρχίσουμε από την αρχή (π.χ. αλλαγή του width ή καταστροφή και επαναδημιουργία) αλλά έχουν προβλήματα με διάφορους browsers οπότε η καλύτερη λύση είναι το clearRect.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#buttons {
position: absolute;
top: 5px;
left: 10px;
}
#buttons > input {
padding: 10px;
display: block;
margin-top: 5px;
}
canvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<div id="buttons">
<input type="button" id="clear" value="Clear">
</div>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// begin custom shape
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
// complete custom shape
context.closePath();
context.lineWidth = 5;
context.strokeStyle = 'blue';
context.stroke();
// bind event handler to clear button
document.getElementById('clear').addEventListener('click', function() {
context.clearRect(0, 0, canvas.width, canvas.height);
}, false);
</script>
</body>
</html>
Animation Frames με την window.setTimeout
Για να λάβουμε ένα μήνυμα με καθυστέρηση μετά το click δείτε το παράδειγμα:
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head>
<body>
<p>Κάντε click στο button και θα περιμένετε 3 δευτερόλεπτα για το alert "Γεια Χαρά".</p>
<button onclick="myFunction()">Εδώ</button>
<script>
function myFunction()
{
setTimeout(function(){alert("Γεια Χαρά")},3000);
}
</script></body></html>
Η σύνταξη είναι:
setTimeout(code,millisec,lang)
Το code είναι function ή expression για evaluation. Millisec η καθυστέρηση σε χιλιοστά του δευτερολέπτου. Προαιρετικά δηλώνουμε και τη scripting language: (JScript | VBScript | JavaScript).
requestAnimFrame
Για να επιτύχουμε κίνηση χρησιμοποιούμε την requestAnimFrame που επιτρέπει στον browser να βρει το ιδανικό FPS (frame per second) για το animation. Για κάθε animation frame, μπορούμε να ενημερώσουμε (update) τα elements του canvas, να αδειάσουμε (clear) το canvas, να κάνουμε redraw το canvas και μετά να ζητήσουμε ένα άλλο animation frame.
Το ακόλουθο παράδειγμα περιέχει τα απολύτως απαραίτητα για την κίνηση (και δεν κάνει τίποτε).
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate() {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// Κοιτάμε σε ποια χρονική στιγμή βρίσκεται η κίνηση
// Διαγράφω το παλιό frame ώστε να φτιάξω καινούριο.
context.clearRect(0, 0, canvas.width, canvas.height);
// Σχεδιάζω κάτι
// Καλώ νέο frame
requestAnimFrame(function() {
animate();
});
}
animate();
</script>
</body>
</html>
Η requestAnimFrame είναι ένα shim (ονομάζεται και shiv), δηλαδή ένα κομμάτι κώδικα ή μια μικρή βιβλιοθήκη που εκτελεί μια ενέργεια καλύπτοντας ταυτόχρονα διαφορετικές πλατφόρμες. Για να το κάνει αυτό μεταφράζει την πληροφορία με τον τρόπο που χρειάζεται κάθε διαφορετικό API το οποίο θα κληθεί να υλοποιήσει τον κώδικά μας.
Στο παράδειγμά μας καλούμε το requestAnimationFrame API (το ξεκίνησε ο Mozilla και το υποστηρίζει και η Google) ή αν δεν είναι διαθέσιμο καλούμε το WebKit (είναι ένα layout engine software σχεδιασμένο ώστε να επιτρέπει σε web browsers να κάνουμε render web σελίδες και χρησιμοποιείται από Safari και Chrome). Αν δεν είναι ούτε αυτό διαθέσιμο καλεί άλλες πιθανές υλοποιήσεις.
Γραμμική Κίνηση
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
/* Το myRectangle object παίρνει τις αρχικές τιμές του. */
var myRectangle = {
x: 0,
y: 75,
width: 100,
height: 50,
borderWidth: 5
};
/* Ζωγραφίζουμε το ορθογώνιο.*/
drawRectangle(myRectangle, context);
/* Αναμονή ενός δευτερολέπτου πριν αρχίσει το animation */
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
/* startTime = τα milliseconds από την 1/1/1970. Δια 1000 θα μας δώσει τα seconds */
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
/* Εμείς καλούμε το παράθυρο κάθε 1 εξηκοστό του δευτερολέπτου. Αυτό όμως δεν έχει σημασία.
Ο browser θα πάει όσο πιο γρήγορα μπορεί. */
};
})();
/* Με μια function ζωγραφίζουμε το ορθογώνιό μας.*/
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
/* Το myRectangle είναι object και έχει properties. */
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
/* Βρίσκω πόσος χρόνος πέρασε από την αρχή της κίνησης. */
var time = (new Date()).getTime() - startTime;
/* Ορίζω την απόσταση κίνησης σε pixels*/
var linearSpeed = 100;
/* Η νέα θέση βρίσκεται από το pixels * χρόνος που πέρασε ανά δευτερόλεπτο */
var newX = linearSpeed * time / 1000;
/* Όσο το ορθογώνιο είναι εντός των ορίων του canvas θα κινείται. */
if(newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
myRectangle.x = newX;
}
/* Διαγράφω το παλιό ορθογώνιο (για την ακρίβεια διαγράφω όλο το canvas και μαζί του και το παλιό ορθογώνιο).*/
context.clearRect(0, 0, canvas.width, canvas.height);
/* Ζωγραφίζω το ορθογώνιο στη νέα θέση. */
drawRectangle(myRectangle, context);
/* Ζητάω νέο frame για να ξαναρχίσει από την αρχή η function */
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
</script>
</body>
</html>
Ένα bug στο πρόγραμμα.
Η κίνηση ξεκινάει από τη θέση 0.
Όταν ξεκινάμε
var time = (new Date()).getTime() – startTime = 0
var linearSpeed = 100;
var newX = linearSpeed * time / 1000;
δηλαδή:
newX ΄= 0 * 100 / 1000 = 0
Οπότε αν το αρχικό x μπει σε άλλο νούμερο (π.χ. 100) θα έχουμε το ορθογώνιο αρχικά σε άλλη θέση και μετά θα διακτινιστεί στο 0 για να αρχίσει η κίνηση.
Για να το κάνω να κινηθεί από όποια θέση θέλω θα χρειαστώ τα ακόλουθα:
var myRectangle = {
x: 100,
y: 75,
width: 100,
height: 50,
borderWidth: 5,
originalX : 100
};
var newX = linearSpeed * time / 1000 + myRectangle.originalX;
Για να κινήσω και τον άξονα y έχω:
var myRectangle = {
x: 100,
y: 75,
width: 100,
height: 50,
borderWidth: 5,
originalX : 100,
originalY : 75,
};
if(newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
myRectangle.x = newX;
myRectangle.y = newX / (linearSpeed * 2) + myRectangle.originalY;
myRectangle.originalY = myRectangle.y;
}
Παράδειγμα με παρακολούθηση της τιμής του x του κουτιού
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
var linearSpeed = 100;
// pixels / second
var newX = linearSpeed * time / 1000;
if(newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
myRectangle.x = newX;
if (time % 40 == 0) {
context.font = 'italic 10pt Calibri';
context.fillStyle = 'black';
context.fillText(newX, textX, 20);
textX = textX + 30;
}
}
// Άλλαξε το clear για να μην σβήνει την πάνω σειρά όπου έχω τη θέση του x του κουτιού.
context.clearRect(0, 30, canvas.width, canvas.height);
drawRectangle(myRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = {
x: 0,
y: 75,
width: 100,
height: 50,
borderWidth: 5
};
var textX = 0; // Η θέση του αριθμού που μας δίνει το x του κουτιού
drawRectangle(myRectangle, context);
// wait one second before starting animation
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
</script>
</body>
</html>
Οριζόντια κίνηση rotated κουτιού
Επειδή με το rotation το canvas γέρνει χρειαζόμαστε μια διόρθωση στο y ώστε να κινηθεί ευθύγραμμα το ορθογώνιο. Δοκιμάστε χωρίς αυτήν για να δείτε τη διαφορά.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas { background:url(http://www.eeei.gr/images/eeeil1.jpg) }
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
var linearSpeed = 100;
// pixels / second
var newX = linearSpeed * time / 1000;
if(newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
myRectangle.x = newX;
myRectangle.y -= 0.6;
/* Επειδή το Canvas έχει κλίση */
if (time % 40 == 0) {
context.font = 'italic 10pt Calibri';
context.fillStyle = 'black';
context.fillText(newX, textX, 20);
textX = textX + 40;
}
}
// Άλλαξε το clear για να μην σβήνει την πάνω σειρά όπου έχω τη θέση του x του κουτιού.
context.clearRect(0, 30, canvas.width, canvas.height);
context.save();
context.rotate(Math.PI / 10);
drawRectangle(myRectangle, context);
context.restore();
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = {
x: 0,
y: 75,
width: 100,
height: 50,
borderWidth: 5
};
var textX = 0; // Η θέση του αριθμού που μας δίνει το x του κουτιού
context.save();
context.rotate(Math.PI / 10);
drawRectangle(myRectangle, context);
context.restore();
// wait one second before starting animation
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
</script>
</body>
</html>
Κίνηση rotated και μη rotaged rectangle ταυτόχρονα
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas { background:url(http://www.eeei.gr/images/eeeil1.jpg) }
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
var linearSpeed = 100;
// pixels / second
var newX = linearSpeed * time / 1000;
if(newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
myRectangle.x = newX;
myOtherRectangle.x = newX;
myRectangle.y -= 0.6;
/* Επειδή το Canvas έχει κλίση */
if (time % 40 == 0) {
context.font = 'italic 10pt Calibri';
context.fillStyle = 'black';
context.fillText(newX, textX, 20);
textX = textX + 40;
}
}
// Άλλαξε το clear για να μην σβήνει την πάνω σειρά όπου έχω τη θέση του x του κουτιού.
context.clearRect(0, 30, canvas.width, canvas.height);
context.save();
context.rotate(Math.PI / 10);
drawRectangle(myRectangle, context);
context.restore();
drawRectangle(myOtherRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = {
x: 0,
y: 75,
width: 100,
height: 50,
borderWidth: 5
};
var myOtherRectangle = {
x: 10,
y: 40,
width: 10,
height: 10,
borderWidth: 1
};
var textX = 0; // Η θέση του αριθμού που μας δίνει το x του κουτιού
context.save();
context.rotate(Math.PI / 10);
drawRectangle(myRectangle, context);
context.restore();
// wait one second before starting animation
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
</script>
</body>
</html>
Κάθετη κίνηση με επιτάχυνση
Για την επιτάχυνση θα χρησιμοποιήσουμε quadratic curve όπως κάναμε σε παλαιότερο μάθημε με τη function quad σε καθαρή javascript.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
// pixels / second^2
var gravity = 200;
myRectangle.y = 0.5 * gravity * Math.pow(time / 1000, 2);
if(myRectangle.y > canvas.height - myRectangle.height - myRectangle.borderWidth / 2) {
myRectangle.y = canvas.height - myRectangle.height - myRectangle.borderWidth / 2;
}
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// draw
drawRectangle(myRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = {
x: 239,
y: 0,
width: 100,
height: 50,
borderWidth: 5
};
drawRectangle(myRectangle, context);
// wait one second before dropping rectangle
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 2000);
</script>
</body>
</html>
Αρμονική ταλάντωση (Oscillation)
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
var amplitude = 150;
// in ms
var period = 2000;
var centerX = canvas.width / 2 - myRectangle.width / 2;
var nextX = amplitude * Math.sin(time * 2 * Math.PI / period) + centerX;
myRectangle.x = nextX;
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// draw
drawRectangle(myRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = {
x: 250,
y: 70,
width: 100,
height: 50,
borderWidth: 5
};
drawRectangle(myRectangle, context);
// wait one second before starting animation
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
</script>
</body>
</html>
Έναρξη – Διακοπή animation
Για να έχουμε animation ζητούμε διαρκώς νέο frame. Για να τη διακόψουμε, απλώς σταματάμε να ζητάμε νέο frame.
Στο παράδειγμα που ακολουθεί ακούμε το ποντίκι (όταν κάνει click μέσα στο χώρο του canvas) και κάνουμε το αντίθετο απ’ ό,τι προηγουμένως:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRect(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(lastTime, myRectangle, runAnimation, canvas, context) {
if(runAnimation.value) {
// update
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
// pixels / second
var linearSpeed = 100;
var linearDistEachFrame = linearSpeed * timeDiff / 1000;
var currentX = myRectangle.x;
if(currentX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myRectangle.x = newX;
}
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// draw
drawRect(myRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(time, myRectangle, runAnimation, canvas, context);
});
}
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = {
x: 0,
y: 75,
width: 100,
height: 50,
borderWidth: 5
};
/*
Δημιουργούμε ένα runAnimation boolean obect και με βάση αυτό θα αλλάζει η συμπεριφορά της animate
*/
var runAnimation = {
value: false
};
/* Προσθέτουμε ένα click listener στο canvas */
document.getElementById('myCanvas').addEventListener('click', function() {
/* Αλλάζουεμ την κατάσταση (flip flag) */
runAnimation.value = !runAnimation.value;
if(runAnimation.value) {
var date = new Date();
var time = date.getTime();
animate(time, myRectangle, runAnimation, canvas, context);
}
});
drawRect(myRectangle, context);
</script>
</body>
</html>
Εύρεση των συντεταγμένων του δρομέα (από το ποντίκι)
Για να βρούμε τη θέση του ποντικού θα χρησιμοποιήσουμε την getMousePos(), Για να βρούμε τη θέση του Canvas μέσα στη σελίδα θα χρησιμοποιήσουμε την getBoundingClientRect() method του window object.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function writeMessage(canvas, message) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.fillText(message, 10, 25);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
/* Διορθώνω τη θέση με τα πάνω και αριστερά offsets (αποστάσεις από το παράθυρο) του canvas.*/
};
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
/* Η function δημιουργεί το object evt και το δίνει για περαιρέρω επεξεργασία. */
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message);
}, false);
</script>
</body>
</html>
Όπως είναι αυτή τη στιγμή το canvas αρχίζει αμέσως στη σελίδα οπότε το 0,0 του canvas είναι πρακτικά και το 0,0 της σελίδας (στην πραγματικότητα υπάρχουν margins αλλά είναι πολύ μικρά.
Προσθέστε ένα <p> με κάποιο κείμενο πριν το canvas για να το κατεβάσετε πιο κάτω και να δείτε πως η θέση 0,0 υπάρχει ακόμη στο πάνω αριστερά σημείο του canvas παρότι κατέβηκε πιο χαμηλά.
Δημιουργία ακανόνιστης γραμμής
<!DOCTYPE HTML>
<html>
<head><meta http-equiv=Content-Type content="text/html; charset=utf-8"> <title>Ακανόνιστη Γραμμή</title></head></body>
<canvas id="myCanvas" width="600" height="500">You need a browser with HTML 5 Canvas support to see this animated map</canvas>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
genericFrontLine (100,0,150,canvas.height,5,"blue",5,5);
function genericFrontLine (lineStartX,lineStartY,lineEndX,lineEndY,lineParts,frontLineColor,frontLineWidth,curveIntensity) {
/* Creates a ragged front line with bezier sorter lines. Params:
Start - End line positions and in how many smaller bezier lines the script will
divide the front line. The more the lines the larger number of curves we will get
curveIntensity = How stiff the curves will be (higher number, smoother curves.
WORKS ON THE Y AXIS. DRAWS FROM TOP TO BOTTOM.
*/
var perPartY = Math.ceil((lineEndY - lineStartY) / lineParts);
var perPartX = Math.ceil((lineEndX - lineStartX) / lineParts);
/* Move per line to some direction. */
var stepsY = Math.ceil(perPartY / curveIntensity);
var stepsX = stepsY;
/* Steps for bezier control points. */
var allPosX = new Array();
var allPosY = new Array();
var currentEndX;
var currentEndY;
/* The end positions of every part of the front line are kept outside to loop to be used again in the next iteration. */
for (var i=0; i<lineParts; i++) {
/* This for is used to find the positions of all X and Ys of all the lines*/
if (i == 0) {
/* First Line */
var currentStartX = lineStartX;
var currentStartY = lineStartY;
currentEndX = lineStartX + perPartX;
currentEndY = lineStartY + perPartY;
allPosX.push(currentEndX);
allPosY.push(currentEndY);
}
else if (i == (lineParts -1)) {
/* Last Line */
var currentStartX = currentEndX;
var currentStartY = currentEndY;
currentEndX = lineEndX;
currentEndY = lineEndY;
allPosX.push(currentEndX);
allPosY.push(currentEndY);
}
else {
/* Lines in between. */
var currentStartX = currentEndX;
var currentStartY = currentEndY;
currentEndX = currentEndX + perPartX;
currentEndY = currentEndY + perPartY;
allPosX.push(currentEndX);
allPosY.push(currentEndY);
}
}
/*-------------------------------------------------------*/
context.beginPath();
context.moveTo(lineStartX, lineStartY);
for (var i=0; i<lineParts; i++) {
/* This for is used change the positions of all X and Ys of all the lines according to troop movements.
It also draws the front line. */
if (i == 0) {
/* First Line */
var currentStartX = lineStartX;
var currentStartY = lineStartY;
var currentEndX = allPosX[i];
var currentEndY = allPosY[i];
var controlX1 = currentStartX + stepsX;
var controlY1 = currentStartY + stepsY;
var controlX2 = currentEndX - stepsX;
var controlY2 = currentEndY - stepsY;
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, currentEndX, currentEndY);
var line = currentEndX + "-" + currentEndY;
context.font="10px Geneva,Arial";
context.fillStyle = 'black';
context.fillText(line, currentEndX, currentEndY);
}
else if (i == (lineParts -1)) {
/* Last Line */
var currentStartX = allPosX[i-1];
var currentStartY = allPosY[i-1];
var currentEndX = allPosX[i];
var currentEndY = allPosY[i];
var controlX1 = currentStartX + stepsX;
var controlY1 = currentStartY + stepsY;
var controlX2 = currentEndX - stepsX;
var controlY2 = currentEndY - stepsY;
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, currentEndX, currentEndY);
var line = currentEndX + "-" + currentEndY;
context.font="10px Geneva,Arial";
context.fillStyle = 'black';
context.fillText(line, currentEndX, currentEndY);
}
else {
/* Lines in between. */
var currentStartX = allPosX[i-1];
var currentStartY = allPosY[i-1];
var currentEndX = allPosX[i];
var currentEndY = allPosY[i];
var controlX1 = currentStartX + stepsX;
var controlY1 = currentStartY + stepsY;
var controlX2 = currentEndX - stepsX;
var controlY2 = currentEndY - stepsY;
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, currentEndX, currentEndY);
var line = currentEndX + "-" + currentEndY;
context.font="10px Geneva,Arial";
context.fillStyle = 'black';
context.fillText(line, currentEndX, currentEndY);
}
}
// complete custom shape
context.lineWidth = frontLineWidth;
context.strokeStyle = frontLineColor;
context.stroke();
}
</script></body></html>
Καταγραφή συντεταγμένων σε click μέσα στο canvas (Δοκιμασμένο σε Firefox και Chrome)
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8">
<style>
body {
margin: 0px;
padding: 0px;
}
</style></head><body>
<canvas id="myCanvas" width="600" height="500"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
canvas.addEventListener("mousedown", getPosition, false);
function getPosition(event)
{
var x = new Number();
var y = new Number();
if (event.x != undefined && event.y != undefined)
{
x = event.x;
y = event.y;
}
else // Firefox method to get the position
{
x = event.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
x -= canvas.offsetLeft;
y -= canvas.offsetTop;
var message = "x:" + x + " y:" + y;
writeMessage(canvas, message);
}
function writeMessage(canvas, message) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.fillText(message, 10, 25);
}
</script></body></html>
Drag and Drop σε Canvas
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Canvas Drag and Drop Test</title>
</head>
<body>
<section>
<div>
<canvas id="canvas" width="400" height="300">
Your browser does not support HTML5 Canvas.
</canvas>
</div>
<script type="text/javascript">
var canvas;
var ctx;
var x = 75;
var y = 50;
var WIDTH = 400;
var HEIGHT = 300;
var dragok = false;
/* Όταν είναι true κινείται το ορθογώνιο. */
/* Η function που ζωγραφίζει το ορθογώνιο. */
function rect(x,y,w,h) {
ctx.beginPath();
ctx.rect(x,y,w,h);
ctx.closePath();
ctx.fill();
}
/* Καθαρίζουμε την προηγούμενη προβολή για να ζωγραφιστεί η καινούρια. */
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
/* Δημιουργούμε το canvas. */
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(draw, 10);
/* Κάθε 10 milliseconds ξανασχεδιάζεται το canvas. Δεν έχουμε βάλει clearInterval οπότε δεν σταματάει ποτέ.*/
}
function draw() {
clear();
/* Η πρώτου δουλειά της draw είναι να καθαρίζει το ήδη υπάρχον canvas για να το αντικαταστήσει με καινούριο. */
ctx.fillStyle = "#FAF7F8";
rect(0,0,WIDTH,HEIGHT);
/* Καλείτε η function rect που ζωγραφίζει το ορθογώνιο.*/
ctx.fillStyle = "#444444";
rect(x - 15, y - 15, 30, 30);
/* Βάζουμε αυτές τα x - 15, y - 15 ως συντεταγμένες ώστε τα x,y να μας δίνουν το κέντρο του ορθογωνίου. (Αυτό δεν είναι απαραίτητο αλλά βοηθάει στο παράδειγμα)*/
}
/* Η function που εκτελεί την κίνηση. */
function myMove(e){
if (dragok){
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
}
}
/* Η πρώτη δουλειά της function myDown είναι να ελέγξει αν το κλικ έγινε μέσα στο χώρο που καταλαμβάνει το ορθογώνιο. Αν αυτό έχει γίνει αλλάζουμε τα x y του ορθογωνίου και πλέον το είναι ελεύθερο να κινηθεί.
canvas.offsetLeft = απόσταση του canvas από το αριστερό κάθετο όριο της σελίδας.
canvas.offsetTop = απόσταση του canvas από το πάνω οριζόντιο όριο της σελίδας.
*/
function myDown(e){
if (e.pageX < x + 15 + canvas.offsetLeft && e.pageX > x - 15 +
canvas.offsetLeft && e.pageY < y + 15 + canvas.offsetTop &&
e.pageY > y -15 + canvas.offsetTop){
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
/* Τα x - 15, y - 15 τα βάλαμε ώστε οι παραπάνω δύο γραμμές να είναι πιο απλές στο παράδειγμα. Αν αντί να τραβήξετε το ποντίκι σας κάνετε απλώς ένα click σε μια γωνία θα δείτε να μετακινεί εκεί το κέντρο του το ορθογώνιο. Αυτό το κάνουν οι παραπάνω 2 γραμμές. */
dragok = true;
canvas.onmousemove = myMove;
}
}
/* Η function που σταματάει την κίνηση. */
function myUp(){
dragok = false;
canvas.onmousemove = null;
}
/* Με τη function init() δημιουργήσαμε το canvas object. Τώρα σε αυτό προσθέτουμε event με το παρακάτω.
Όταν ο χρήστης κάνει click με το ποντίκι του στο canvas ενεργοποιείται το canvas.onmousedown event και καλεί τη function myDown(). Η myDown λαμβάνει ένα event object (το e) που έχει τις ιδιότητες (properties) του event. Μεταξύ των άλλων ιδιοτήτων του το event έχει τα pageX και pageY όπου βρίσκονται οι τιμές των τρεχόντων συντεταγμένων x και y του ποντικιού.
Προσοχή: Οι συντεταγμένες (coordinates) αναφέρονται στη σελίδα, όχι στο παράθυρο ή στο canvas.
*/
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
</script>
</section>
</body>
</html>
Drag and Drop πολλαπλών boxes
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8" />
<style>
#myCanvas {
border: 1px solid #9C9898;
}
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="500"></canvas>
<script type="text/javascript">
var canvas;
var context;
var dragok;
var box2move = null;
var units = [
{ name: 'red', x: 50, y: 300, width: 50, height:50, color:"red"},
{ name: 'blue', x: 75, y: 200, width: 25, height:100, color:"blue"},
];
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
function init() {
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
return setInterval(drawRect, 10);
}
function drawRect () {
context.clearRect(0, 0, canvas.width, canvas.height);
for (i=0;i<units.length;i++) {
context.beginPath();
context.rect(units[i].x, units[i].y, units[i].width, units[i].height);
context.closePath();
context.fillStyle = units[i].color;
context.fill();
}
}
function myDown(e){
for (i=0;i<units.length;i++) {
if (e.pageX > units[i].x + canvas.offsetLeft && e.pageX < units[i].x + canvas.offsetLeft + units[i].width && e.pageY > units[i].y + canvas.offsetTop && e.pageY < units[i].y + canvas.offsetTop + units[i].height) {
box2move = i;
units[i].x = e.pageX - canvas.offsetLeft;
units[i].y = e.pageY - canvas.offsetTop;
dragok = true;
canvas.onmousemove = myMove;
}
}
}
function myUp(){
dragok = false;
canvas.onmousemove = null;
box2move = null;
}
function myMove(e){
if (dragok){
units[box2move].x = e.pageX - canvas.offsetLeft;
units[box2move].y = e.pageY - canvas.offsetTop;
}
}
</script>
</body>
</html>
Σχεδίαση γραμμής με το ποντίκι
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8" />
<style>
#myCanvas {
border: 1px solid #9C9898;
}
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="500"></canvas>
<script type="text/javascript">
var canvas;
var context;
var dragok;
var lineArrayX = new Array();;
var lineArrayY = new Array();;
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
function init() {
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
return setInterval(drawLine, 10);
}
function drawLine () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
if (typeof lineArrayX[0] !== 'undefined' && lineArrayX[0] !== null) {
for (i=0;i<lineArrayX.length;i++) {
if (i == 0) {
context.moveTo(lineArrayX[i], lineArrayY[i]);
}
else {
context.lineTo(lineArrayX[i], lineArrayY[i]);
}
}
context.lineJoin = 'round';
context.stroke();
}
}
function myDown(e){
var lineX = e.pageX - canvas.offsetLeft;
var lineY = e.pageY - canvas.offsetTop;
lineArrayX.push(lineX);
lineArrayY.push(lineY);
dragok = true;
canvas.onmousemove = myMove;
}
function myUp(){
dragok = false;
canvas.onmousemove = null;
}
function myMove(e){
if (dragok){
var lineX = e.pageX - canvas.offsetLeft;
var lineY = e.pageY - canvas.offsetTop;
lineArrayX.push(lineX);
lineArrayY.push(lineY);
}
}
</script>
</body>
</html>
Onmousedown σε Canvas
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8" />
<style>
#myCanvas {
border: 1px solid #9C9898;
}
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="500"></canvas>
<p><span id="unitname">Click on a unit to see it's name here</span>
<script type="text/javascript">
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var units = [
{ name: 'red', x: 50, y: 300, width: 50, height:50, color:"red"},
{ name: 'blue', x: 75, y: 200, width: 25, height:100, color:"blue"},
];
drawRect();
document.getElementById('myCanvas').addEventListener("mousedown", doMouseDown, false);
function doMouseDown(e) {
for (i=0;i<units.length;i++) {
if (e.pageX > units[i].x + canvas.offsetLeft && e.pageX < units[i].x + canvas.offsetLeft + units[i].width && e.pageY > units[i].y + canvas.offsetTop && e.pageY < units[i].y + canvas.offsetTop + units[i].height) {
document.getElementById('unitname').innerHTML = units[i].name;
}
}
}
function drawRect () {
context.clearRect(0, 0, canvas.width, canvas.height);
for (i=0;i<units.length;i++) {
context.beginPath();
context.rect(units[i].x, units[i].y, units[i].width, units[i].height);
context.closePath();
context.fillStyle = units[i].color;
context.fill();
}
}
</script>
</body>
</html>