JavascriptProva

mercoledì 6 gennaio 2016

Ipotesi su un'altra modalità di "disegno": disegnare direttamente su una VIew.

L'altro metodo era disegnare sulla View...
Non riesco a capire che differenza ci sia.
Provo un po' a scimmiottare il codice...

...
  setContentView(new MyView(this));
 
  
  
 }
 
 class MyView extends View{
  public MyView(Context context){
   super(context);
  }
  @Override
  protected void onDraw(Canvas dipinto){
   super.onDraw(dipinto);
   
   int w=getWidth();
   int h=getHeight();
   Paint pennello=new Paint();
   pennello.setColor(Color.BLUE);
   dipinto.drawRect(50, 50,200,200,pennello);
  }
In pratica, la tela non viene affatto creata. Ma non capisco perché vengano prese le misure della View in questione se non vengono utilizzate.
Le elimino e traccio un cerchio azzurro...

......
  setContentView(new MyView(this));
 
  
  
 }
 
 class MyView extends View{
  public MyView(Context context){
   super(context);
  }
  @Override
  protected void onDraw(Canvas dipinto){
   super.onDraw(dipinto);
   Paint pennello=new Paint();
   pennello.setColor(Color.CYAN);
   dipinto.drawCircle(100,100,50,pennello);
  }
 }




Funziona ugualmente!
Dunque la differenza che disegnare su una bitmap e poi apporla come sfondo sta nel fatto che qui la bitmap viene già assegnata, ed è delle stesse dimensioni della view. La tela è direttamente sul muro, per cui con la onDraw si dà l'istruzione su come costruire il muro di base, già dipinto, anziché fare come con la tecnica precedente in cui si prende la tela, la si dipinge e poi si appone al muro.

martedì 5 gennaio 2016

Grafica con Canvas in Android.

A questo punto è il momento di ripassare canvas e compagnia, che ho iniziato a studiare proprio ieri.
Se ricordo bene, la Bitmap è la tela, il Canvas è l'immagine, il Paint è il pennello.
Provo a buttare giù un codice...

Ecco, per creare la Bitmap, cosa che non ho mai fatto, si usa un codice Bitmap.createBitmap.
In precedenza, ho creato una bitmap da un file, ma potrei anche dover creare una bitmap vuota per disegnarci sopra col canvas. Ecco, appunto:
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
Il canvas va costruito sulla tela!
  Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
Invece il pennello si crea di per sé: il pennello è qualcosa di staccato dall'immagine e dalla tela.
  Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
Ora intingiamo il pennello sulla tavolozza:
  Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.GREEN);
E ora possiamo disegnare...

  Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.GREEN);
  canvas.drawRect(20, 20,40,20,paint);
...e non succede niente!
Ma abbiamo dimenticato di appendere il quadro!
Proviamo...

Per far questo dobbiamo prima identificare la parete, quindi appendere.
Provo a fare così:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/parete"
    tools:context="com.example.grafica.MainActivity" >
...identifichiamo quindi lo sfondo:
  Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.GREEN);
  canvas.drawRect(20, 20,40,20,paint);
  
  RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete);
...e ora appendiamo il quadro:
  Bitmap bmp= Bitmap.createBitmap(400,400,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.GREEN);
  canvas.drawRect(20, 20,40,20,paint);
  
  RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete);
  parete.setBackgroundDrawable(new BitmapDrawable(bmp));
...e non succede assolutamente nulla!

Forse devo fare la bitmap un po' più grande, come nell'esempio che sto seguendo e interpretando liberamente...

  Bitmap bmp= Bitmap.createBitmap(400,800,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.GREEN);
  canvas.drawRect(50,50,200,200,paint);
  
  RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete);
  parete.setBackgroundDrawable(new BitmapDrawable(bmp));
Ecco, sì, ce l'ho fatta!



Se tolgo tutta quella monnezza da studi precedenti, magari si visualizza anche la bitmap minuscola che avevo creato? Proviamo...

  Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.GREEN);
  canvas.drawRect(20, 20,40,20,paint);
  
  RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete);
  parete.setBackgroundDrawable(new BitmapDrawable(bmp));
No. E' inutile che incollo un'immagine in cui non c'è nulla.
Dubbio: le dimensioni che ho impostato per il rettangolo sono 200 e 200, ossia doveva venire un quadrato! Perché invece è un rettangolo?


Ho risolto!
Evidentemente è dovuto al fatto che le dimensioni della bitmap vengono modellate sulle dimensioni del RelativeLayout, e quindi vengono "stirate". Forse, ho pensato, la soluzione sta nel creare una bitmap delle stesse dimensioni del Layout, ma come fare a individuarle?
Inizialmente ho trovato la soluzione parete.getWidth() e parete.getHeight(), però non ottenevo risultati: richiedendo il valore di queste grandezze sul LogCat ottenevo valori zero.
Poi ho trovato questa pagina sul mitico StackOverflow e ho risolto: evidentemente le misure del layout vengono prese solo all'evento onWindowFocusChanged.
 public void updateSizeInfo(){
  RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete);
  h=parete.getHeight();
  w=parete.getWidth();
  Bitmap bmp=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
  Canvas canvas=new Canvas(bmp);
  Paint paint=new Paint();
  paint.setColor(Color.RED);
  canvas.drawRect(50,50,200,200,paint);
  parete.setBackground(new BitmapDrawable(bmp));
  
 }
 
 public void onWindowFocusChanged(boolean hasfocus){
  updateSizeInfo();
 }
Sono metodi separati dal metodo OnCreate.
Ottengo un quadrato rosso che resta tale anche orientando l'emulatore in modalità Portrait.
Dunque l'evento onWindowFocusChanged recepisce il cambiamento di visualizzazione?
Vediamo di sperimentarlo...

 public void onWindowFocusChanged(boolean hasfocus){
  Log.d("EVENTO","ONWINDOWFOCUSCHANGED");
 }
Ecco il LogCat:
01-04 22:24:14.807: D/EVENTO(4894): ONWINDOWFOCUSCHANGED
01-04 22:25:08.878: D/PAUSE(4894): ONPAUSE
01-04 22:25:08.878: D/STOP(4894): ONSTOP
01-04 22:25:08.928: D/CREATE(4894): ONCREATE
01-04 22:25:08.978: D/START(4894): ONSTART
01-04 22:25:08.978: D/RESUME(4894): ONRESUME
01-04 22:25:09.008: I/Choreographer(4894): Skipped 30 frames!  The application may be doing too much work on its main thread.
01-04 22:25:09.038: D/EVENTO(4894): ONWINDOWFOCUSCHANGED
01-04 22:25:25.238: D/PAUSE(4894): ONPAUSE
01-04 22:25:25.238: D/STOP(4894): ONSTOP
01-04 22:25:25.288: D/CREATE(4894): ONCREATE
01-04 22:25:25.358: D/START(4894): ONSTART
01-04 22:25:25.358: D/RESUME(4894): ONRESUME
01-04 22:25:25.378: I/Choreographer(4894): Skipped 34 frames!  The application may be doing too much work on its main thread.
01-04 22:25:25.448: D/EVENTO(4894): ONWINDOWFOCUSCHANGED
01-04 22:25:33.199: D/PAUSE(4894): ONPAUSE
01-04 22:25:33.199: D/STOP(4894): ONSTOP
01-04 22:25:33.259: D/CREATE(4894): ONCREATE
01-04 22:25:33.269: D/START(4894): ONSTART
01-04 22:25:33.269: D/RESUME(4894): ONRESUME
01-04 22:25:33.339: D/EVENTO(4894): ONWINDOWFOCUSCHANGED
Sì: A ogni movimento dell'emulatore corrisponde un Pause, uno Stop, poi un OnCreate, un OnStart e un OnResume.
Manca OnDestroy, ma mi sono accorto adesso che non avevo messo il codice che ricevesse e mostrasse l'evento.
Lo metto adesso:
 @Override
 protected void onDestroy(){
  super.onDestroy();
  Log.d("DESTROY","ONDESTROY");
 }
E riproviamo!

01-04 22:30:11.403: D/EVENTO(4941): ONWINDOWFOCUSCHANGED
01-04 22:30:11.583: I/Choreographer(4941): Skipped 43 frames!  The application may be doing too much work on its main thread.
01-04 22:30:11.623: D/gralloc_goldfish(4941): Emulator without GPU emulation detected.
01-04 22:30:11.663: D/PAUSE(4941): ONPAUSE
01-04 22:30:11.663: D/STOP(4941): ONSTOP
01-04 22:30:11.663: D/DESTROY(4941): ONDESTROY
01-04 22:30:11.673: D/CREATE(4941): ONCREATE
01-04 22:30:11.723: D/START(4941): ONSTART
01-04 22:30:11.723: D/RESUME(4941): ONRESUME
01-04 22:30:11.833: D/EVENTO(4941): ONWINDOWFOCUSCHANGED
01-04 22:31:05.364: D/PAUSE(4941): ONPAUSE
01-04 22:31:05.364: D/STOP(4941): ONSTOP
01-04 22:31:05.364: D/DESTROY(4941): ONDESTROY
01-04 22:31:05.364: D/CREATE(4941): ONCREATE
01-04 22:31:05.394: D/START(4941): ONSTART
01-04 22:31:05.394: D/RESUME(4941): ONRESUME
01-04 22:31:05.484: D/EVENTO(4941): ONWINDOWFOCUSCHANGED
01-04 22:31:11.634: D/PAUSE(4941): ONPAUSE
01-04 22:31:11.634: D/STOP(4941): ONSTOP
01-04 22:31:11.634: D/DESTROY(4941): ONDESTROY
01-04 22:31:11.694: D/CREATE(4941): ONCREATE
01-04 22:31:11.764: D/START(4941): ONSTART
01-04 22:31:11.764: D/RESUME(4941): ONRESUME
01-04 22:31:11.784: I/Choreographer(4941): Skipped 38 frames!  The application may be doing too much work on its main thread.
01-04 22:31:11.854: D/EVENTO(4941): ONWINDOWFOCUSCHANGED
E infatti...

Okay! Abbiamo risolto!
Adesso, per focalizzare meglio la cosa, rifaccio tutto con una nomenclatura metaforica che aiuti a memorizzare:
 public void Disegna(){
  Bitmap tela=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
  Canvas dipinto=new Canvas(tela);
  Paint pennello=new Paint();
  
  pennello.setColor(Color.CYAN);
  dipinto.drawCircle(100, 100, 200, pennello);
  
  RelativeLayout muro=(RelativeLayout)findViewById(R.id.muro);
  muro.setBackground(new BitmapDrawable(tela));
 }
 
 public void onWindowFocusChanged(boolean hasfocus){
  Disegna();
 }
Un piffero!!! Non ho impostato le variabili w e h ai valori di larghezza e altezza del muro!

Riproviamo...
 public void Disegna(){
  RelativeLayout muro=(RelativeLayout)findViewById(R.id.muro);
  w=muro.getWidth();
  h=muro.getHeight();
  Bitmap tela=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
  Canvas dipinto=new Canvas(tela);
  Paint pennello=new Paint();
  
  pennello.setColor(Color.CYAN);
  dipinto.drawCircle(100, 100, 200, pennello);
  
  
  muro.setBackground(new BitmapDrawable(tela));
 }
 
 public void onWindowFocusChanged(boolean hasfocus){
  Disegna();
 }
Un po' fuori, ma mi sembra un cerchio perfetto!

domenica 3 gennaio 2016

Codici per impostare l'immagine di una view ImageView da Uri, da path e da risorse.

Esercizio: riscrivere il codice per impostare l'immagine di una ImageView a partire da un'immagine salvata in memoria, sia per mezzo dell'URI sia per mezzo del path, sia da risorse.

Con l'URI:
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  setContentView(R.layout.activity_main);
  

  immagine=(ImageView)findViewById(R.id.imageView1);
  
  Intent intent=new Intent();
  intent.setAction(Intent.ACTION_PICK);
  intent.setData(Uri.parse("content://media/external/images/media"));
  startActivityForResult(intent, 0);
 }

...

 protected void onActivityResult(int requestCode, int resultCode, Intent data){
  if(resultCode==RESULT_OK){
   immagine.setImageURI(data.getData());
  }
 }
E fin qui è abbastanza facile...

Adesso facciamo mediante il Path, che dobbiamo andare a risolvere mediante il metodo getContentResolver().query.

@Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  setContentView(R.layout.activity_main);
  

  immagine=(ImageView)findViewById(R.id.imageView1);
  
  Intent intent=new Intent();
  intent.setAction(Intent.ACTION_PICK);
  intent.setData(Uri.parse("content://media/external/images/media"));
  startActivityForResult(intent, 0);
 }
 
 protected void onActivityResult(int requestCode, int resultCode, Intent data){
  if(resultCode==RESULT_OK){
   Bitmap bmp=BitmapFactory.decodeFile(getPathFromUri(data.getData()));
   immagine.setImageBitmap(bmp);
  }
 }
 
  

 public String getPathFromUri(Uri uri){
  Cursor cursor = getContentResolver().query(uri, null, null, null, null);
  cursor.moveToFirst();
  int indice=cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
  String stringa=cursor.getString(indice);
  return stringa;
  
 }
Bene. Funziona!

Adesso dalle risorse:
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  setContentView(R.layout.activity_main);
  

  immagine=(ImageView)findViewById(R.id.imageView1);
  

 
  immagine.setImageResource(R.drawable.faciadecul);
  
 }

sabato 2 gennaio 2016

Primo approccio alla grafica su Android.


E così abbiamo disegnato un cerchio...

Ora disegno la bandiera del Giappone...

        @Override
        public void onDraw(Canvas canvas){
         super.onDraw(canvas);
         int x=getWidth();
         int y=getHeight();
         int radius;
         radius=100;
         Paint paint=new Paint();
         paint.setStyle(Paint.Style.FILL);
         paint.setColor(Color.RED);
         canvas.drawCircle(x/2, y/2, radius, paint);
         
        }




Cerchi concentrici...
        @Override
        public void onDraw(Canvas canvas){
         super.onDraw(canvas);
         int x=getWidth();
         int y=getHeight();
         Paint paint=new Paint();
         paint.setStyle(Paint.Style.FILL);
         paint.setColor(Color.GREEN);
         canvas.drawCircle(x/2, y/2, 100, paint);
         paint.setColor(Color.RED);
         canvas.drawCircle(x/2, y/2, 80, paint);
         paint.setColor(Color.YELLOW);
         canvas.drawCircle(x/2, y/2, 60, paint);
         paint.setColor(Color.BLUE);
         canvas.drawCircle(x/2, y/2, 40, paint);
         paint.setColor(Color.CYAN);
         canvas.drawCircle(x/2, y/2, 20, paint);
         
        }


sabato 26 dicembre 2015

Disegnare rette di DIV su una pagina web

Creiamo un DIV.
<style>
#oggetto{
 position:absolute;
 width:100px;
 height:100px;
 background-color:red;
}
</style>

<script>
function init(){
 var elemento=document.createElement("div");
 elemento.setAttribute("id","oggetto");
 elemento.setAttribute("style","left:200px");
 document.body.appendChild(elemento);
}
</script>
<body onload="init()">

</body> 
Ecco.
Gli attributi di stile spaziali sono resi come formato stringa.
Devo dare un valore numerico e convertirlo.
Proviamo...

Ecco:
function CreaDiv(left){
 var elemento=document.createElement("div");
 elemento.setAttribute("class","oggetto");
 elemento.setAttribute("style","left:"+left.toString()+"px");
 document.body.appendChild(elemento);
}
function init(){
 CreaDiv(100);
}


Andiamo con le due coordinate.
function CreaDiv(left,top){
 var elemento=document.createElement("div");
 elemento.setAttribute("class","oggetto");
 elemento.setAttribute("style","left:"+left.toString()+"px;top:"+top.toString()+"px;");
 document.body.appendChild(elemento);
}
function init(){
 CreaDiv(500,200);
}
Perfetto!!!

Ora costruiamo una funzione...

function CreaDiv(left,top){
 var elemento=document.createElement("div");
 elemento.setAttribute("class","oggetto");
 elemento.setAttribute("style","left:"+left.toString()+"px;top:"+top.toString()+"px;");
 document.body.appendChild(elemento);
}
function init(){
 for(var i=100;i<500;i++){
  CreaDiv(i,i);
 }
}
Ed ecco una retta con angolo di 45 gradi, ossia con tangente 1, dato che x e y sono uguali.
Rendiamo puntiforme il DIV...
<style>
.oggetto{
 position:absolute;
 width:1px;
 height:1px;
 background-color:red;
}
</style> 
E il gioco è fatto! Ecco una retta a 45 gradi!



E via con la grafica di DIV!!!

sabato 19 dicembre 2015

Javascript: comparsa di un quadrato verde trascinabile col mouse, che sparisce al rilascio.

Bene.
Iniziamo con il programma.

Ho bisogno di creare un elemento al click del mouse.
Disponiamo che al click sulla pagina si crei un DIV in una determinata posizione.
Ed ecco che ho creato il codice che fa apparire, al click del mouse, dei div quadrati verdi con l'angolo superiore sinistro corrispondente alla posizione del mouse:
function crea(e){
 var elemento=document.createElement("div");
 elemento.className="classe";
 elemento.style.left=e.clientX+"px";
 elemento.style.top=e.clientY+"px";
 document.body.appendChild(elemento);
}
document.onmousedown=crea;


Però adesso mi serve che l'elemento si distrugga quando lascio il mouse.
Proviamo...

Sono andato abbastanza avanti!
Ecco il codice che fa apparire un quadrato verde al click del mouse, lo trascina intorno liberamente e poi lo distrugge al rilascio del mouse:
<script>
var elemento;
function crea(e){
 elemento=document.createElement("div");
 elemento.setAttribute("id","nome");
 elemento.className="classe";
 elemento.style.left=e.clientX-50+"px";
 elemento.style.top=e.clientY-50+"px";
 document.body.appendChild(elemento);
}
function OnMouseMove(e){
 elemento.style.left=e.clientX-50+"px";
 elemento.style.top=e.clientY-50+"px";
}

function distruggi(e){
 var genitore=document.body;
 elemento=e.target;
 genitore.removeChild(elemento);
}
document.onmousedown=crea;
document.onmouseup=distruggi;
document.onmousemove=OnMouseMove;
</script> 
Va un po' perfezionato, forse...

martedì 15 dicembre 2015

Ripasso e modifica del codice per il DragDrop di un DIV in JavaScript.

E se riprendessi a postare qui i miei progressi? Questo enorme blocco di appunti mi è prezioso...


E infatti vi ho ritrovato il codice per realizzare il drag-drop.

Facciamolo con la sintassi buona per Firefox.

Prendo un DIV e lo rendo quadrato, colorandolo in modo diverso dallo sfondo.
<html>
<head>

<style>
#oggetto{
 background-color:green;
 height:100px;
 width:100px;
}
</style>


<script>

</script>

<body>
<div id="oggetto"></div>

</body>
</html> 


Ecco il risultato:


Bene.
Ora rendo la posizione assoluta...

<html>
<head>

<style>
#oggetto{
 position:absolute;
 background-color:green;
 height:100px;
 width:100px;
}
</style>


<script>

</script>

<body>
<div id="oggetto"></div>

</body>
</html>
E adesso ottengo la posizione, salvandola in variabili.
Iniziamo con il solo asse delle X.

Per prima cosa, definisco una variabile che contiene l'oggetto bersaglio degli eventi, quindi creo le routines degli eventi.
<script>
var dragElement;

function OnMouseDown(event){
 alert(event.target.style.left);
}


document.onmousedown=OnMouseDown;


</script> 
La casella di dialogo non mi restituisce assolutamente nulla.
Forse devo estrarne il numero mediante la funzione ExtractNumber. Come la creo?
Ma un momento... ricordo che le impostazioni di posizione date tramite il CSS non appaiono quando rilevate tramite il JavaScript...


Ecco: ho ricostruito il programma, con qualche ritocco, ossia la capacità di leggere in JavaScript le impostazioni fornite con il CSS mediante ComputedStyle.
<html>
<head>

<style>
#oggetto{
 position:absolute;
 left:100px;
 background-color:green;
 height:100px;
 width:100px;
}
</style>
<script>
var dragElement;
var OffsetX;
var OffsetY;
var StartX;
var StartY;

function Sinistra(oggetto){
 var risultato=parseInt(getComputedStyle(oggetto).left); 
 return isNaN(risultato)==true? null: risultato;
}

function Alto(oggetto){
 var risultato=parseInt(getComputedStyle(oggetto).top); 
 return isNaN(risultato)==true? null: risultato;
}
function OnMouseDown(e){
 dragElement=e.target;
 OffsetX=Sinistra(dragElement);
 OffsetY=Alto(dragElement);
 StartX=e.clientX;
 StartY=e.clientY;
 document.onmousemove=OnMouseMove; 
}

function OnMouseMove(e){
 dragElement.style.left=OffsetX+e.clientX-StartX;
 dragElement.style.top=OffsetY+e.clientY-StartY;
}

function OnMouseUp(){
 document.onmousemove=null;
}
document.onmousedown=OnMouseDown;
document.onmouseup=OnMouseUp;

</script>

<body>
<div id="oggetto"></div>

</body>
</html>
E funziona!!! Incollando su Blocco Note questo codice, e salvando con un'estensione .HTML, col browser Firefox, funziona! Con Internet Explorer sicuramente non funziona, mentre con altri non lo so.