Showing posts with label JQUERY. Show all posts
Showing posts with label JQUERY. Show all posts

Sunday, January 3, 2021

x-comment jquery plugin: Jquery plugin for commenting or discussion

With x-comment, users' comments can be displayed hierarchically and users can respond to each other. There is no level limit while answering. x-comment allows adding new comments, reply to comments, and runs entirely on json and javascript objects.

Github:

https://github.com/vyigity/x-comment

Dependency

  • Jquery
  • Bootstrap
  • Fontawesome
  • Globalize

Configuration- Plugin

  • mode: Can be set as "array" or "remote". With "array" value, data is processed locally by using the javascript array given to the plugin. This method can be used for batch input and output operations. The data is accessed by running the function that returns Jquery Deferred in the dataSource field with "remote" value. (required)
  • items: In "array" mode, data is given to the plugin here. Also, after the data is loaded in "remote" mode, it can be read as a javascript array.(required in array mode)
  • dataSource: Can be set as a function that returns a jquery Deferred object. Data is obtained by running this function by the plugin. Data must be sent as parameter to promise resolve function.(required in remote mode)
  • authorName: The name written here is used by the plugin when responding. (required)
  • width: It allows the size of the plugin to be set to px. (optional)
  • allowInsert: Can be set as "true/false". It allows to show the form that enables inserting. (optional - Default:true)
  • allowReply: Can be set as "true/false". Ensures that comments can be answered or not. (optional - Default:true)
  • allowDelete: Can be set as "true/false". Ensures that comments can be deleted or not. (optional - Default:true)
  • onInserting: Can be set as a function that returns a jquery Deferred object. Is triggered when adding a new record. 
    • Parameters: 
      • instance: Instance of plugin. For example, it can be used to access the items or the plugin can be refreshed. 
      • value: Value that is typed by user.
  • onReplied: Can be set as a function that returns a jquery Deferred object. Is triggered when replying to a comment. 
    • Parameters: 
      • instance: Instance of plugin. For example, it can be used to access the items or the plugin can be refreshed. 
      • value: Value that is typed by user. 
      • item: Comment that is answered to.
  • onDeleting: Can be set as a function that returns a jquery Deferred object. Is triggered when deleting a comment. 
    • Parameters: 
      • instance: Instance of plugin. For example, it can be used to access the items or the plugin can be refreshed. 
      • item: Comment about to be deleted.
  • onError: Is triggered on error that occurs in functions that return a jquery Deferred object. Deferred object must be used with reject function. 
    • Parameters: 
      • data: The value sent through the reject function of the Deferred object.
  • texts: Can be configured text in plugin. A javascript object. (optional)

Configuration - texts (optional)

  • sendButtonText: Determines the text on the button in the new comment creation section.
  • inputTextAreaPlaceHolder: Allows editing of placeholder that appears in comment text area.
  • sendReplyButtonText: Determines the text on the reply send button.
  • cancelButtonText: Determines the text on the button that enables the cancellation of the response..
  • replyButtonText: Determines the text on the button that enables the answering process.
  • deleteButtonText: Determines the text on the button that allows the comments to be deleted.

Configuration - items

  • id: A unique value of a comment item.
  • parent: Parent value of a comment item.
  • deletable: Can be set as "true/false". The value that indicates the comment that can be deleted or not.
  • content: Content of a comment item.
  • created: Creation date time of a comment item. Value must be formatted as JSON. For example, "2020-12-31T20:52:00Z"
  • fullName: User name of owner of comment item.




Example (data.js):
var comments = [
    {
        id: 1,
        parent: null,
        deletable: true,
        content: "1. yorum",
        created: "2020-12-31T20:52:00Z",
        fullName: "Veli Yigit Yolcu"
    },
    {
        id: 2,
        parent: null,
        deletable: true,
        content: "2. yorum",
        created: "2020-12-31T21:52:00Z",
        fullName: "Veli Yigit Yolcu"
    },
    {
        id: 3,
        parent: 2,
        deletable: true,
        content: "2. yoruma cevap",
        created: "2020-12-31T22:52:00Z",
        fullName: "Veli Yigit Yolcu"
    }
];
Example (index.html):
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link href="css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/comment.css" rel="stylesheet" />
    <link href="css/fontawesome.min.css" rel="stylesheet" />
    <link href="css/brands.css" rel="stylesheet" />
    <link href="css/solid.css" rel="stylesheet" />

    <script src="js/jquery-3.5.1.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/x-comment.js"></script>

    <script src="cldr/cldr.js"></script>
    <script src="cldr/event.js"></script>
    <script src="cldr/supplemental.js"></script>

    <script src="globalize/globalize.js"></script>
    <script src="globalize/message.js"></script>
    <script src="globalize/number.js"></script>
    <script src="globalize/currency.js"></script>
    <script src="globalize/date.js"></script>

    <script src="cldr-data/supplemental.js"></script>
    <script src="cldr-data/tr.js"></script>

    <script src="data/data.js"></script>
</head>
<body>

    <script>

        Globalize.locale("tr");

        var currentId = 100;

        $(document).ready(function () {

            $("#xcomment").xcomment({

                mode: "array",
                items: comments,
                allowInsert: true,
                authorName: "Veli Yigit Yolcu",
                width: 600,
                onInserting: function (instance, value) {

                    let def = $.Deferred();

                    instance.items.splice(0, 0,
                        {
                            id: currentId,
                            parent: null,
                            deletable: true,
                            content: value,
                            created: new Date().toJSON(),
                            fullName: "Veli Yigit Yolcu"
                        });

                    currentId++;

                    def.resolve();

                    return def;
                },
                onReplied: function (instance, item, value) {

                    let def = $.Deferred();

                    instance.items.push(
                        {
                            id: currentId,
                            parent: item.id,
                            deletable: true,
                            content: value,
                            created: new Date().toJSON(),
                            fullName: "Veli Yigit Yolcu"
                        }
                    );

                    currentId++;

                    def.resolve();

                    return def;
                },
                onDeleting: function (instance, item) {

                    let def = $.Deferred();

                    for (var i = 0; i < instance.items.length; i++) {

                        if (instance.items[i].id === item.id) {

                            instance.items.splice(i, 1);
                        }
                    }

                    def.resolve();

                    return def;
                }
            });
        });

    </script>

    <div id="xcomment" ></div>

</body>
</html>

Friday, January 1, 2021

x-comment: Jquery için yorum-tartışma eklentisi - x-comment: Jquery plugin for commenting or discussion

For english:


Geçenlerde bir projede yorumlama eklentisi kullanma ihtiyacım oldu. İnternette araştırma yaptım ve ilginç bir şekilde iyi bir jquery eklentisi bulamadım. Bulduğum da (ismini burada vermeyeyim) kullanışlı olmadı ve hata verdi. İnternette bulduğum en iyi şey Semantic UI css dosyası oldu. Bende elimdekileri kullanarak bir jquery eklentisi olarak x-comment eklentisini yazdım. x-comment' i aslında sunucu odaklı çalışacak şekilde düşünmüştüm fakat sonradan lokal olarak da çalışabilecek şekilde geliştirdim. Bu yazıdaki örnek lokal kullanıma (array mod) örnektir.


x-comment ile kullanıcıların yorumları birbirlerine yanıt verecek şekilde hiyerarşik olarak gösterilebilmektedir. Yanıtlamada seviye sınırı yoktur. x-comment yeni yorum eklenmesine, yorumların yanıtlanmasına olanak verir ve tamamen json ve javascript nesneleri üzerinden çalışır. Aşağıdaki GitHub bağlantısından kodlara erişilebilir.

GitHub:


Bağımlılıklar
  • Jquery
  • Bootstrap
  • Fontawesome
  • Globalize
Ayarlar - Eklenti
  • mode: "array" veya "remote" değerlerini alabilir. "array" değerinde eklentiye verilen javascript array kullanılarak lokal olarak işlem yapılır. Toplu giriş çıkış işlemler için bu yöntem kullanılabilir. "remote" değerinde dataSource alanındaki Jquery Deferred döndüren fonksiyon çalıştırılarak veriye ulaşılır. (Zorunlu)
  • items: "array" modda eklentiye veri buradan verilir. Ayrıca "remote" modda veri yüklendikten sonra buradan javascript array olarak okunabilir.(Array modda zorunlu)
  • dataSource: Jquery Deffered nesnesi döndüren bir fonksiyon içerebilir. Eklenti tarafından bu fonksiyon çalıştırılarak veri elde edilir. Veri promise nesnesinin resolve fonksiyonuna parametre olarak gönderilmelidir. (Remote modda zorunlu)
  • authorName: Yanıtlama yapılırken eklenti tarafından burada yazan isim kullanılır. (Zorunlu)
  • width: Eklentinin boyutunun px olarak ayarlanması sağlar. (Zorunlu değil)
  • allowInsert: "true/false" değeri alabilir. Giriş yapılmasını sağlayan formun gösterilmesini sağlar. (Zorunlu değil - Default:true)
  • allowReply: "true/false" değeri alabilir. Yorumların yanıtlanabilir veya yanıtlamaz olmasını sağlar. (Zorunlu değil - Default:true)
  • allowDelete: "true/false" değeri alabilir. Yorumların silinebilir veya silinemez olmasını sağlar. (Zorunlu değil - Default:true)
  • onInserting: Jquery Deffered nesnesi döndüren bir fonksiyon içerebilir. Yeni kayıt eklenirken tetiklenir.
    • Parametreler: 
      • instance: Yorum eklentisinin instance değeridir. Örn. items alanına ulaşmak için kullanılabilir veya eklenti buradan yenilenebilir.
      • value: Kullanıcı tarafından girilen değerdir.
  • onReplied: Jquery Deffered nesnesi döndüren bir fonksiyon içerebilir. Bir yoruma cevap verildiğine tetiklenir.
    • Parametreler: 
      • instance: Yorum eklentisinin instance değeridir. Örn. items alanına ulaşmak için kullanılabilir veya eklenti buradan yenilenebilir.
      • value: Kullanıcı tarafından girilen değerdir.
      • item: Yanıt verilen yorumdur.
  • onDeleting: Jquery Deffered nesnesi döndüren bir fonksiyon içerebilir. Bir yorum silinirken tetiklenir.
    • Parametreler: 
      • instance: Yorum eklentisinin instance değeridir. Örn. items alanına ulaşmak için kullanılabilir veya eklenti buradan yenilenebilir.
      • item: Silinmek istenen yorumdur.
  • onError: Jquery Deffered nesnesi döndüren fonksiyonlar içinde hata olması durumunda tetiklenir. Deferred nesnesi reject fonksiyonu ile kullanılmalıdır.
    • Parametreler: 
      • data: Deferred nesnesinin reject fonksiyonu aracılığıyla gönderilen değerdir.
  • texts: Eklenti içindeki nesneler üzerinde yazıların ayarlanmasını sağlayan javascript nesnesini içerebilir. (Zorunlu değil)
Ayarlar - texts (Zorunlu değil)
  • sendButtonText: Yeni yorum oluşturma kısmında yer alan tuş üzerindeki yazıyı belirler.
  • inputTextAreaPlaceHolder: Yorum girilen yazı alanının üzerinde beliren yazının düzenlenmesini sağlar.
  • sendReplyButtonText: Yanıt gönderme tuşunun üzerindeki yazıyı belirler.
  • cancelButtonText: Yanıt verilme işleminin iptal edilmesini sağlayan tuş üzerindeki yazıyı belirler.
  • replyButtonText: Yanıtlama işleminin yapılmasını sağlayan tuş üzerindeki yazıyı belirler.
  • deleteButtonText: Yorumların silinmesini sağlayan tuş üzerindeki yazıyı belirler.
Ayarlar - items 
  • id: Yoruma ait eşsiz bir değerdir.
  • parent: Hangi yorumun alt yorumu (yanıtı) olduğunu belirten değerdir.
  • deletable: "true/false" değeri alabilir. Yorumun silinebilir olmasını veya olmamasını sağlayan değerdir.
  • content: Yorumun içeriğini belirtir.
  • created: Yorumun oluşturulma zamanını belirtir. JSON formatlı tarih değeri içermelidir. Örn. "2020-12-31T20:52:00Z"
  • fullName: Yorumu yapan kullanıcının adını içerir.

Örnek (data.js):
var comments = [
    {
        id: 1,
        parent: null,
        deletable: true,
        content: "1. yorum",
        created: "2020-12-31T20:52:00Z",
        fullName: "Veli Yigit Yolcu"
    },
    {
        id: 2,
        parent: null,
        deletable: true,
        content: "2. yorum",
        created: "2020-12-31T21:52:00Z",
        fullName: "Veli Yigit Yolcu"
    },
    {
        id: 3,
        parent: 2,
        deletable: true,
        content: "2. yoruma cevap",
        created: "2020-12-31T22:52:00Z",
        fullName: "Veli Yigit Yolcu"
    }
];
Örnek (index.html):
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link href="css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/comment.css" rel="stylesheet" />
    <link href="css/fontawesome.min.css" rel="stylesheet" />
    <link href="css/brands.css" rel="stylesheet" />
    <link href="css/solid.css" rel="stylesheet" />

    <script src="js/jquery-3.5.1.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/x-comment.js"></script>

    <script src="cldr/cldr.js"></script>
    <script src="cldr/event.js"></script>
    <script src="cldr/supplemental.js"></script>

    <script src="globalize/globalize.js"></script>
    <script src="globalize/message.js"></script>
    <script src="globalize/number.js"></script>
    <script src="globalize/currency.js"></script>
    <script src="globalize/date.js"></script>

    <script src="cldr-data/supplemental.js"></script>
    <script src="cldr-data/tr.js"></script>

    <script src="data/data.js"></script>
</head>
<body>

    <script>

        Globalize.locale("tr");

        var currentId = 100;

        $(document).ready(function () {

            $("#xcomment").xcomment({

                mode: "array",
                items: comments,
                allowInsert: true,
                authorName: "Veli Yigit Yolcu",
                width: 600,
                onInserting: function (instance, value) {

                    let def = $.Deferred();

                    instance.items.splice(0, 0,
                        {
                            id: currentId,
                            parent: null,
                            deletable: true,
                            content: value,
                            created: new Date().toJSON(),
                            fullName: "Veli Yigit Yolcu"
                        });

                    currentId++;

                    def.resolve();

                    return def;
                },
                onReplied: function (instance, item, value) {

                    let def = $.Deferred();

                    instance.items.push(
                        {
                            id: currentId,
                            parent: item.id,
                            deletable: true,
                            content: value,
                            created: new Date().toJSON(),
                            fullName: "Veli Yigit Yolcu"
                        }
                    );

                    currentId++;

                    def.resolve();

                    return def;
                },
                onDeleting: function (instance, item) {

                    let def = $.Deferred();

                    for (var i = 0; i < instance.items.length; i++) {

                        if (instance.items[i].id === item.id) {

                            instance.items.splice(i, 1);
                        }
                    }

                    def.resolve();

                    return def;
                }
            });
        });

    </script>

    <div id="xcomment" ></div>

</body>
</html>

Friday, April 14, 2017

Jquery ve ChartJs ile Gerçek Zamanlı Grafik Çizdirmek

Bu yazıda Jquery ve ChartJs 2.5.0 kullanarak bir web sitesi üzerinde dinamik grafik çizdireceğiz. CharJs ücretsiz bir grafik çizdirme kütüphanesi olup HTML kanvas  üzerine çizim yapmaktadır. Bu kütüphane pasta, çubuk ve çizgi gibi birçok grafik türüne destek vermektedir. Blog üzerinde hazırlanan grafik rastgele verileri çizecek olup bu uygulama dinamik döviz oranlarının gösterimi gibi amaçlarla kullanılabilir.  Grafiği çizdirebilmemiz için gerekli kanvas öğesini aşağıdaki gibi eklememiz gerekiyor:

<div style="width:400px;height:400px">

  <canvas id="myChart"></canvas>
    
</div>

Yukarıda boyutlar gelişigüzel seçilmiştir.  Sonraki aşamada gerekli javascript kodlarını aşağıdaki gibi ekleyelim.


var myChart;

var options = {

   maintainAspectRatio: false,
   responsive: true
};

var data = {

    labels: ["January", "February", "March", "April", "May", "June", "July"],

    datasets: [
        {
            label: "Buraya başlık gelecek",
            fill: true,
            lineTension: 0,
            backgroundColor: "rgba(75,192,192,0.4)",
            borderColor: "rgba(75,192,192,1)",
            borderCapStyle: 'butt',
            borderDash: [],
            borderDashOffset: 0.0,
            borderJoinStyle: 'miter',
            pointBorderColor: "rgba(75,192,192,1)",
            pointBackgroundColor: "#fff",
            pointBorderWidth: 1,
            pointHoverRadius: 1,
            pointHoverBackgroundColor: "rgba(75,192,192,1)",
            pointHoverBorderColor: "rgba(220,220,220,1)",
            pointHoverBorderWidth: 2,
            pointRadius: 1,
            data: [65, 59, 80, 81, 56, 55, 40],
            spanGaps: false                   
         }]              
};


$(document).ready(function () {

    var ctx = document.getElementById("myChart");

    myChart = new Chart(ctx, { type: 'line', data: data, options: options });
    var i = 0;

    startAnim(i);

});

function startAnim(i)
{
    setTimeout(function () {
        changeGrap(i);
    }, 500);
}

function changeGrap(i)
{
    myChart.config.data.datasets[0].data.shift();
    myChart.config.data.datasets[0].data.push(Math.random() * 100);
    myChart.update(100);

    startAnim(++i);
}

Burada data nesnesi verilerin gösterimi için gerekli değişkenleri içermektedir. Bu yazıda bunlar anlatılmayacak olup detaylı bilgiye buradan ulaşabilirsiniz. Yukarıda kodlarda options nesnesi içinde genel şekillendirme özellikleriyle ilgili bilgiler tanımlanmıştır. Bu nesne içindeki "maintainAspectRatio"  ile grafiğin görüntü oranına "aspect ratio" bağlı kalmadan taşıyıcı elementin boyutlarına genişlemesi sağlanmıştır. "responsive" özelliği taşıyıcı elementin boyunutun değişmesi drumunda grafiğin de yeniden boyutlanması amacıyla kullanılmaktadır.

"data" nesnesi içindeki "labels" dizisi ile grafiğin alt kısmının hangi etiketlerle kaç parça olacak şekilde bölümleneceği belirtilmektedir.

"datasets" dizisi içindeki ilk nesne ile grafiğimizin çizimi ile ilgili özellikler belirtilmektedir. Bu nesne içindeki "label" özelliği ile grafiğin başlığı tanımlanmaktadır. "fill" özelliği ile çizgi grafiğin çizgi altında kalan kısmın boyanması sağlanmaktadır. "data" dizisi içinde grafiğin başlangıç verisi tanımlanmaktadır (Grafiği dinamik kullanmayacaksanız grafiğin verisini tanımlamaktadır").

Jquery "ready" fonksiyonu içinde grafiğin oluşturma kodu çizgi grafik olarak (type:line) tanımlanmıştır.

"startAnim" fonksiyonu dinamik grafik güncellemesinin yapılması için kullanılmaktadır. Buradaki önemli nokta "changeGrap" fonksiyonu içindeki javascript "shift" fonksiyonu ile dizinin ilk elemanı diziden çıkarılmakta ve "push" fonksiyonu ile son eleman olarak rastgele oluşturulan yeni sayı atanmaktadır. Son olarak grafik nesnesinin (myChart) update fonksiyonu ile grafik güncellenmektedir.

Yukarıdaki kodların çalıştırılması sonucunda grafik aşağıdaki gibi oluşmaktadır:



Wednesday, August 31, 2016

Jquery ile Blogger Üzerinde Facebook Benzeri Odaklanma Uygulaması - Focusing Application like on Facebook with Jquery on Blogger

Bu yazıda yenice facebook'ta karşılaştığım odaklanma uygulamasını blog sayfama nasıl uyguladığımı anlatacağım. Facebook üzerinde durum güncellemesi amacıyla ilgili yazı alanına tıkladığınızda yorum yazılacak yerin dışında kalan kısımların karardığını göreceksiniz. Bu uygulamanın odaklanmada pozitif etkisi olduğu, bu yüzden de bir blog sitesi için de gayet yararlı olacağını düşündüğüm için uygulamayı gerçekleştirme kararı aldım. Öncelikle bir CSS sınıfı tanımlaması yapmamız gerekiyor:

.onFocusMeContainer
{
     background-color:#000000;
     opacity:0.7;
     z-index:12;
     width:100%;
     height:100%;
     position:fixed;  
     top:0;
     left:0;
     display:none;
}

Bu uygulamada bize lazım olan en öncekli element siyah, saydam ve ekranı kaplayan siyah bir elementtir. Bu element bütün ekranı kaplayacak ve odaklama yapacağımız ögenin arkasında, diğer bütün sayfanın üzerinde yer alacaktır. Tabi kırmızı uçan kartalımızın üzerine siyah bir örtü örtmek istemeyeceğimizden dolayı kartalı taşıyan ögenin "z-index" CSS değerini artırdım. "onFocusMeContainer" CSS sınıfında "opacity" değeri ile elemente saydamlık kazandırdık. Elementin "display" özelliğini kullanarak elementi görünmez yapıp, bütün ekranı kaplaması ve pencereyi kaydırdığımız zaman kaymaması için "position" özelliğini "fixed" olarak belirledik. Elementin "z-index" değerini blog için uygun bir değer seçmemiz gerektiği için "12" olarak belirledik, çünkü sitemizin diğer ögelerinin "z-index" değeri 12'den küçüktür. Bu CSS sınıfını oluşturduktan sonra bu sınıfı içeren bir "div" elementini  "body" içine aşağıdaki kod ile ekliyoruz.

<div class="onFocusMeContainer"></div>

Bir sonraki aşamada gerekli fonksiyonaliteyi sağlamak amacıyla bazı javascript kodları tanımlamız gerekiyor.

$(".post-outer").click(function (event) {

   if (lastClicked == null) {

          if (!$(event.target).is("a")) {

               lastClicked = $(event.target);

               while (!$(lastClicked).hasClass("post-outer")) {

                   lastClicked = $(lastClicked).parent();
               }

               $(lastClicked).css("position", "relative");
               $(lastClicked).css("z-index", 5000);
               $(".onFocusMeContainer").show("fast");
          }
    } 
});

$(".onFocusMeContainer").click(function (event) {
   
   $(lastClicked).css("position", "relative");
   $(lastClicked).css("z-index", 0);
   $(".onFocusMeContainer").hide("fast");
   lastClicked = null;
});

Blogger'da yazdığımız makaleler "post-outer" sınıfını içeren bir taşıyıcı kontrol içinde sunulduğu için bu ögenin "click" olayını tanımlamamız gerekiyor. Burada bir döngü aralığıyla "post-outer" sınıfını içeren taşıyıcıya ulaşana kadar "parent" fonksiyonu aracılığıyla DOM üzerine yukarı doğru çıkıyoruz. Bunun sebebi daha önceki bir yazımda bahsettiğim "Event Bubbling" yani olayın yukarı doğru iletilmesi sebebiyledir. Kısaca olayı özetlemek gerekirse, bir taşıyıcı içindeki bir kontrole tıklandığında tıklama olayı en yukarıdaki taşıyıcı elemente kadar iletilmektedir.  Taşıyıcı elementi bulduktan sonra "z-index" özelliğinin çalışması için bu elementin "position" özelliğini "relative" yapmamız gerekiyor. Daha sonra "z-index" değerini büyük bir sayı yaparak elementin yukarıda kalmasını sağlıyoruz. Son aşamada siyah saydam kontrolümüzü görünür hale getiriyoruz. Link ("a") elementlerine tıklandığında ilgili özelliğimiz çalışmaması için "is" fonksiyonunu kullanarak üzerine tıklanan elementin bir "a" elementi olup olmadığını da kontrol etmemiz gerekiyor.

Siyah saydam kontrolümüzün tıklama olayı üzerinde tanımlı fonksiyon aracılığıylada yukarıda yaptığımız düzenlemeleri geri alıyoruz. "lastClicked" değişkeni global olarak tanımlanmıştır ve en son odaklanmış elementi göstermektedir.

Uygulama blog üzerinde şuan aktif olduğu için yazı üzerine tıklayarak uygulamayı deneyimleyebilirsiniz.


Wednesday, March 23, 2016

Jquery ile Yukarı Çık Uygulaması (Uçan Kartal) - Go Up Component with Jquery (Flying Eagle)

Bu yazıda bloğa yeni eklediğim yukarı çık uygulamasının nasıl oluşturulduğu üzerinde duracağım. Bu uygulama ile kullanıcı sayfanın aşağı taraflarına doğru indiğinde sağ alt köşede görünen bileşen yardımıyla en üstüne çıkabilmektedir. Bu yazı aynı zamanda jquery ile "scroll" işlemlerinin nasıl yapıldığı anlatılmaktadır.

Öncelikle CSS kodlarını tanımlayalım:

<style>

        .FlyingEagle {

            position:fixed;
            background-image:url('Images/eagle5.png');
            width:150px;
            height:150px;
            background-size:150px 150px;
            display:none;
            top:100%;
            left:100%;
            margin-top:-180px;
            margin-left:-180px;
            opacity:0.7;
        }

</style>

Yukarıdaki CSS kodlarında önemli noktalardan ilki "position:fixed" tanımlamasıdır. Bu tanımlama ile sınıfın üyesi olan elementin tarayıcı penceresine (window) göre pozisyon alması sağlanmaktadır. Yine "margin" değerleri kullanılarak elementin pozisyondan istediğimiz bir miktarda sapması (disposition) sağlanmaktadır. Elementin saydamlığı "opacity" niteliği kullanılarak azaltılmaktadır. Görüntünün taşıcıyı içine düzgün bir şekilde yerleştirilmesi amacıyla "background-size" niteliği kullanılmıştır. Bu nitelik ile görüntü elementin içine esnetilerek veya daraltılarak yerleştirilmektedir.

Sonraki aşamada javascript kodlarını tanımlayalım:

$(document).ready(function () {

            $(".FlyingEagle").click(function () {

                $("html, body").animate({ scrollTop: 0 }, 500);
            });

            $(window).scroll(function () {

                if ($(window).scrollTop() > 50) {

                    $(".FlyingEagle").show("fast");
                } else {

                    $(".FlyingEagle").hide("fast");
                }
            });
        });

Jquery "scroll" olayı yakalanarak kartal animasyonunun yönetimi yapılmaktadır. Jquery "show" fonksiyonu ile kartal gösterilmekte, "hide" fonksiyonu ile de saklanmaktadır. Jquery scrollTop fonksiyonu ekranın üstüne kaç piksellik kısımın kaydığını döndürmektedir. Bu yüzden sıfır değeri hiç kayma olmadığını göstermektedir. Bu kapsamda sayfa en fazla $(document).height() - $(window).height() kadar kaydırılabilir. Jquery "animation" fonksiyonu ile yukarı yumuşak bir biçimde çıkılması sağlanmaktadır. Son olarak da CSS sınıfı "FlyingEagle" olan bir "div" elementi sayfaya eklenir.

Wednesday, March 16, 2016

Jquery AJAX ile Dinamik Görüntü Yükleme - Dynamically Loading Images with Jquery AJAX

Bu yazıda AJAX kullanılarak görüntülerin tarayıcıya dinamik olarak yüklenmesi sağlanacaktır. Bilindiği üzere HTTP protokolü yazı (text) temelli çalışan bir protokoldür. Bu sebeple AJAX ile bilgi alışverişi yazı (text) olarak yapılmaktadır. Bir görüntünün sunucudan tarayıcıya HTTP protokolüyle yüklenmesi için görüntünün yazıya dönüştürülmesi gerekir. Bu amaçla daha önce anlatılan Base64 kodlama kullanılacaktır. Öncelikle AJAX işlemini gerçekleştirecek javascript kodlarını tanımlayalım:

      
$.ajax({
          type: "POST",
          url: "./WebForm3.aspx/GetImage",
          data: '{"FotoId": "10" }',
          contentType: "application/json; charset=utf-8",
          dataType: "json",
          success: function (msg) {
                    
                 var imageSrc = "data:image/jpg;base64," + msg.d;
                 $("#Base64Image").attr("src", imageSrc);
             },
             error: function (msg) {

                 alert("Hata Oluştu.");
             }
       });

Burada önemli nokta HTML img nesnesinin src niteliğine elde ettiğimiz değerin nasıl ekleneceğidir. Aşağıdaki gibi resmin Base64 biçimi src niteliğine atanarak tarayıcının otomatik olarak görüntüyü çözümleyip göstermesi sağlanmaktadır.

data:image/jpg;base64,...

Burada src içinde kodlu verinin jpg görüntüsü olduğu ve Base64 olarak kodlandığı belirtilmektedir. Son olarak görüntüyü kodlayıp tarayıcıya gönderen sunucu taraflı kodu yazalım:

        
[WebMethod]
public static string GetImage(string FotoId)
{
    byte[] arr = File.ReadAllBytes("IMAGE_PATH");

    string base64 = Convert.ToBase64String(arr);

    return base64;
}

Burada "Convert" nesnesinin "ToBase64String" fonksiyonu kullanılarak byte dizisi biçimindeki görüntü Base64 olarak kodlanıp tarayıcıya gönderilmiştir.

Thursday, March 10, 2016

Jquery ile Yılan Oyununun Gerçeklenmesi - Implementing Snake Game with Jquery

Bu yazıda telefonlarda eskiden sıklıkla oynanan yılan oyununu javascript ve jquery ile oluşturacağız. Yılan oyununun ana fikri yılanı oluşturan parçalarının tren katarları gibi birbirini izlemesidir. Yem alındıkça puan güncellenmeli ve yılan büyümelidir. Yılan kendine veya duvarlara çarptığında oyun bitecektir. İlk olarak CSS kodlarımızı oluşturalım:

<style>

    .SGContainer
    {
        width:204px;
        height:auto; 
    }

    .SGCanvas
    {
        background-color:lightblue;
        width:204px;
        height:204px;
        position:relative;
       
    }

    .SGCanvas:focus
    {
        border:solid;
        border-width:2px;
        border-color:darkgreen;
    }

    .SGSnakePart
    {
        background-color:black;
        position:absolute;
        width:5px;
        height:5px;
    }

    .SGSnakeFood
    {
        background-color:darkred;
        position:absolute;
        width:5px;
        height:5px;
    }

    .SGFinish
    {
        font-weight:bold;
        background-color:brown;
        color:white;
        z-index:1;
        position:absolute;
        top:50%;
        left:50%;
        margin-top:-25px;
        margin-left:-50px;
        width:100px;
        height:50px;
        justify-content: center;
        align-items: center;   
        display:flex;   
    }
</style>

Yukarıdaki CSS kodlarında önemli nokta flex kutusu (flex box) kullanımıdır. Flex kutusu klasik kutuya göre daha esnek özellikler sunmaktadır. Burada "align-items" ile flex kutusunun içeriği dikey olarak, "justify-content" ile de yatay olarak konumlandırılmıştır. Sonraki aşamada javascript kodlarını tanımlayalım:

var Snake = [];
var Food = [];

var Direction = "Right";
var MoveNumber = 5
var Canvas = null;
var Interval = null;
var IsGameStarted = false;
var Score = 0;

var SnakePart = function () {

    this.X = -1;
    this.Y = -1;
    this.DomObject = null;
}

function StartGame() {

    IsGameStarted = false;
    Canvas = $(".SGCanvas");
    $(Canvas).children().remove();
    Snake = [];
    Food = [];
    Direction = "Right";
    Score = 0;

    StopAnimation();

    for (var i = 10; i > -1; i--) {

        var part = new SnakePart();
        part.X = i * 5;
        part.Y = 100;

        var domPart = $('<div class="SGSnakePart"></div>');
        part.DomObject = domPart;

        part.DomObject.css({ top: part.Y, left: part.X });

        Snake.push(part);

        AddPartToCanvas(part.DomObject)
    }

    $(Canvas).focus();

    $(Canvas).keydown(function (event) {

        event.preventDefault();
        SGUpdateDirection(event.keyCode);
    });

    $(Canvas).focusout(function () {

        if (IsGameStarted)
            StopAnimation();
    });

    $(Canvas).focusin(function () {

        if (IsGameStarted)
            StartAnimation();
    });
    
    GenerateFood();

    StartAnimation();
    IsGameStarted = true;
}

function StartAnimation() {

    if (Interval == null)
        Interval = setInterval(SGUpdate, 50);
}

function StopAnimation() {

    if (Interval != null)
        clearInterval(Interval);
    Interval = null;
}

function AddPartToCanvas(part)
{
    $(Canvas).append(part);
}

function GenerateFood() {

    var x = parseInt((Math.random() * 100) % 40) * 5;
    var y = parseInt((Math.random() * 100) % 40) * 5;

    var part = new SnakePart();
    part.X = x;
    part.Y = y;

    var domPart = $('<div class="SGSnakeFood"></div>');
    part.DomObject = domPart;
    part.DomObject.css({ top: part.Y, left: part.X });

    Food.push(part);

    AddPartToCanvas(part.DomObject);
}

function EatFood() {

    if(Snake[0].Y == Food[0].Y && Snake[0].X == Food[0].X)
    {
        Score++;
        Snake.push(Food.pop());
        GenerateFood();
    } 
}

function SGUpdateDirection(key) {
  
    if (key == 39 && Direction != "Left") {

        Direction = "Right";
    }

    if (key == 37 && Direction != "Right") {

        Direction = "Left";
    }

    if (key == 38 && Direction != "Down") {

        Direction = "Up";
    }

    if (key == 40 && Direction != "Up") {

        Direction = "Down";
    }
}

function SGUpdate() {


    for (var i = Snake.length - 1; i > 0; i--) {

        Snake[i].X = Snake[i - 1].X;
        Snake[i].Y = Snake[i - 1].Y;
    }

    if (Direction == "Right") {

        Snake[0].X += MoveNumber;
    }

    if (Direction == "Left") {

        Snake[0].X -= MoveNumber;
    }

    if (Direction == "Up") {

        Snake[0].Y -= MoveNumber;
    }

    if (Direction == "Down") {

        Snake[0].Y += MoveNumber;
    }

    if (SGIsGameOver())
    {
        SGGameOver();
        return;
    }

    EatFood();
    UpdateScore();
    SGUpdateCanvas();
}

function SGUpdateCanvas()
{
    for (var i = Snake.length - 1; i > -1; i--) {

        $(Snake[i].DomObject).css({ top: Snake[i].Y, left: Snake[i].X });
    }
}

function SGIsGameOver() {

    for (var i = Snake.length - 1; i > 0; i--) {

        if (Snake[0].X == Snake[i].X && Snake[0].Y == Snake[i].Y)
            return true;
        if (Snake[0].X == 200 || Snake[0].X < 0 || Snake[0].Y == 200 || Snake[0].Y < 0)
            return true;
    }

    return false;
}

function UpdateScore() {

    $("#SGPuan").text(Score);
}

function SGGameOver() {

    IsGameStarted = false;
    StopAnimation();
    $(Canvas).append($('<div class="SGFinish">OYUN BİTTİ!</div>'));
}

Yukarda yer alan fonksiyonların açıklamaları şöyledir:

* StartGame(): Oyunun sıfırlanmasını ve başlamasını sağlayan fonksiyondur. Burada başlangıç olarak 10 parça yılan oluşturulmakta, canvasla ilgili klavye olaylarına jquery ile fonksiyon atanmakta ve ilgili fonksiyonlar aracılığıyla animasyon başlatılmaktadır. Jquery keydown olayı bir klavye tuşuna basıldığında tetiklenmektedir. Bu fonksiyon içinde kullanılan "event.preventDefault()" ile ok tuşlarının ekranı oynatması engellenmekte yani tuşun ön tanımlı özelliği pasivize edilmektedir. Jquery focus() fonksiyonu ile herhangi bir elemente focus (odaklanma) yapılması sağlanmaktadır. Bu fonksiyonun düzgün çalışması için odaklanılacak elementin "tabindex" niteliği -1 olmalıdır. Jquery focusin() odaklanma olduğunda, focusout() ise odaklanma kaybedildiğinde tetiklenmektedir. İlgili olaylar tetiklendiğinde animasyon durdurulmakta veya devam ettirilmektedir.

* StartAnimation(): Oyun animasyonunun başlatılmasını sağlayan fonksiyondur. Javascript setInterval(çağrılacakfonksiyon, süre) fonksiyonu ile animasyon oynatılmaktadır. Bu fonksiyon ile parametre olarak gönderilen çağrılacak fonksiyon her süre dolduğunda çalıştırılmaktadır. Bu fonksiyon setTimeout() fonksiyondan farklı olarak devamlı olarak çağrıma devam etmektedir. Javascript setTimeout() fonksiyonu süre dolduğunda çağrılacak fonksiyonu çalıştırır ve bir daha çalıştırmaz. Süre parametresi millisecond (ms) olarak ifade edilmektedir. 1000 ms = 1 sec olarak kullanılır.

* StopAnimation(): Javascript clearInterval(interval) fonksiyonu ile animasyonun durdurulması sağlanmaktadır. Parametre olarak setInterval() fonksiyonu tarafından döndürülen değer kullanılmaktadır.

* AddPartToCanvas(): Jquery ile oluşturulan DOM nesnelerinin DOM'a eklenmesini sağlamaktadır.

* GenerateFood(): Rastgele bir pozisyona yem yerleştirilmesini sağlamaktadır. Bunu sağlarken Math.Random() fonskiyonunu kullanmaktadır. Bu fonksiyon 0 ile 1 arasında [0,1) bir reel sayı üretmektedir. Koordinatlar üretilirken kanvas uzunluğumuzun 200px ve aralıkların 5 px olduğu göz önünde bulundurularak elde edilen sayı 100 ile çarpılmakta ve 2 basamaklı rastgele bir sayı elde edilmektedir. Bu sayının 40'a göre modu alınarak rastgele 40'tan küçük bir sayı elde edilmiş olmaktadır. Elde edilen son değer 5 ile çarpılarak koordinat hesaplanmış olmaktadır. Yukarıdaki matematiksel işlemler incelendiğinde elde edilen rastgele sayının [0,200) aralığında olduğu görülebilmektedir.

* EatFood(): Bu fonksiyon ile yılanın baş parçasının konumunun yem konumuyla aynı olup olmadığı kontrol edilmekte ve aynı ise puan artırılmakta, yeni bir yem oluşturulmakta ve yılan büyütülmektedir.

* SGUpdateDirection(key): Okunan klavye tuşunun koduna göre yılanın yönünü belirleyen fonksiyondur.

* SGUpdate(): Diğer bütün fonksiyonların yönetimini sağlayan ve yılanın hareketinin mantıksal hesaplamasını yapan ana animasyon fonksiyonudur.

* SGUpdateCanvas(): SGUpdate() fonksiyonunda belirlenen oyunun yeni durumuna göre kanvası güncelleyen fonksiyondur.

* SGIsGameOver(): Yılanın kanvas dışına çıkıp çıkmadığına veya zaten işgal ettiği bir koordinata yeniden girmesine veya girmemesine göre oyunun bitip bitmediğinin anlaşılmasını sağlayan fonksiyondur.

* UpdateScore(): Kanvasın sağ üstünde bulunan mavi puan sayısını güncelleyen fonksiyondur.

* SGGameOver(): Oyun bittiğinde gerekli işlemlerin yapıldığı fonksiyondur. Oyun bittiğinde animasyon durdurulmakta ve "OYUN BİTTİ!" yazısını taşıyan flex kutusu kanvasa eklenmektedir.

Son aşama olarak HTML kodlarını tanımlayalım:

<div class="SGContainer">
    <div style="margin-bottom:10px">
        <input id="Button1" class="btn btn-success" type="button" value="BAŞLA" onclick="StartGame()"/>
        <span id="SGPuan" class="label label-info" style="float:right; font-size:large">0</span>
    </div>
    <div class="SGCanvas" tabindex="-1">

    </div>
</div>

Yukarıda yer alan kodların çalıştırılması ile aşağıdaki sonuç elde edilmektedir:
(Oyun ok tuşlarıyla oynanmaktadır)


0

Saturday, March 5, 2016

Jquery ile Bulmaca Oyunu - Jquery Puzzle Game

Bu yazı daha önceki yazıların devamı olarak görülmelidir, bu sebeple bu yazıda öncekilerde anlatılan konular anlatılmayacaktır. Bu yazıda karışık olarak yer alan resim parçalarının doğru bir şekilde bir araya getirilerek çözülecek bir bulmaca oyunu tasarladık. Burada önceki yazılarda yer alan script ve css kodlarına (Jquery, Bootstrap) ek olarak sayfaya JqueryUI eklenmesi gereklidir. Bu amaçla JqueryUI CDN kodunu sayfaya ekleyelim:

<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js" type="text/javascript"></script>

JqueryUI sayfada kullanıcı etkileşimlerini veya animasyon efektlerini yönetmek amacıyla kullanılabilecek fonksiyonları içeren bir kütüphanedir. Bulmaca uygulamasında resimler üzerinde sürükle-bırak (drag-drop) yapılmasını sağlamak amacıyla kullanılmıştır.

Uygulamayı oluştururken ilk olarak CSS kodlarını tanımlayalım:

<style>
        .PuzzleContainer
        {
            width: 545px;
            height: 545px;
        }
        
        .PuzzleBoard
        {
            width: 545px;
            height: 545px;
        }
        
        .PuzzleBox
        {
            width: 50px;
            height: 50px;
            float: left;
            margin: 2px;
            border: solid;
            border-width: 1px;
        }
        
        .PuzzlePartContainerDiv
        {
            width: 50px;
            height: 50px;
            background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijeyFxpSRzHq2d4NyPPy8bA9ybJECYVC1wmPTxj3yI5ih7711-T5Lfmqf44OT_4vx6TQVVko_cOMxGZoWW6CaZOpdRVr6LeMA88Go6S2nvsE8zktavDbEe9c2TBT6pwDvJd0dNUcvzKlo/s1600/puzzle1.jpg);
            background-size: 500px 500px;
            float: left;
            margin: 2px;
        }
        
        .PuzzlePartContainerDiv:hover
        {
            padding: 2px;
            background-clip: content-box;
        }
        
        .PuzzlePartContainerDiv:active
        {
            border: solid;
            border-width: 2px;
            border-color: red;
        }
        
        .PuzzleBoxHover
        {
            border: solid;
            border-color: red;
        }
        
        .PuzzleBoxActive
        {
            background-color: lightblue;
        }
        
        .PuzzleContainerActive
        {
            background-color: lightgray;
        }
</style>

Yukarıdaki CSS kodlarında "PuzzleContainer" karışık halde resim parçalarını içeren kanvasın sınıfını, "PuzzleBoard" resimlerin yerleştirileceği kanvasın sınıfını, "PuzzleBox" resimlerin yerleştirileceği kanvasın içinde yer alan resimlerin içine oturacağı kare alanların sınıfını, "PuzzlePartContainerDiv" "PuzzleBox" içine yerleştirilecek "PuzzleContainer" içinde yer alan resim parçalarının sınıfını, "PuzzlePartContainerDiv:hover" "PuzzleContainer" içinde yer alan resim parçalarının üzerine fareyle gelindiğinde uygulanacak CSS niteliklerini içeren sınıfı, "PuzzlePartContainerDiv:active" "PuzzleContainer"içinde yer alan resim parçalarının üzerine tıklandığında uygulanacak CSS niteliklerini içeren sınıfı, "PuzzleBoxHover" resim parçalarının "PuzzleBox" üstüne getirildiğinde uygulanacak nitelikleri içeren sınıfı, "PuzzleBoxActive" sürükleme esnasında "PuzzleBox" sınıfının üyelerine uygulanacak CSS niteliklerini içeren sınıfı ve son olarak "PuzzleContainerActive" sürükleme esnasında resim parçalarını içeren kanvasa uygulanacak nitelikleri içeren sınıfı ifade etmektedir.

Yukarıdaki önemli noktalardan ilki "background-size: 500px 500px;" belirtimidir. Bu nitelik ile arka plan olarak ayarlanan görüntünün arka planda 500px-500px olarak yeniden boyutlanması sağlanmaktadır. Bir diğer önemli nokta ise "background-clip: content-box;" niteliğidir. Bu nitelik ile arka plan resminin içerik kutusuna yani padding ile kısıtlanmış alana çizilmesi sağlanmaktadır. Yukarıda yer almayan fakat bootstrap ile eklenen ve bu uygulama için kritik olan bir diğer nitelik ise "box-sizing: border-box" belirtimidir. Bu nitelik "border-box" yapılarak margin dışındaki diğer belirtimlerin yani padding, border ve content değerlerinin, belirtilen width (genişlik) ve height (yükseklik) değerlerinin içinde olduğu belirtilmektedir. Yani bir ögeye border kalınlığı 2 olan bir border tanımlasak bile genişlik ve yükseklik değeri daha önce belirttiğimiz değer üzerinde sabit kalacaktır.

Bir sonraki aşama olarak javascript kodlarını tanımlayalım:

<script>

        var PuzzleArray = [];
        var PuzzleTmpArray = [];

        $(document).ready(function () {

            CreateMyWorld(true);
        });

        var PuzzleWrapper = function () {

            this.ActualX = -1,
            this.ActualY = -1,
            this.CurrentX = -1,
            this.CurrentY = -1
        }

        function CreateMyWorld(Shuffle) {

            $(".PuzzleContainer").children().remove();
            $(".PuzzleBoard").children().remove();

            PuzzleArray = CreateArray(10, 10);

            SliceImageAndCreatePuzzle();
            ShuffleImages(Shuffle);
            ConfigurePuzzle();
        }

        function CreateButtonClick() {

            var isShuffle = $("#CBShuffle").is(":Checked");
            CreateMyWorld(isShuffle);
        }

        function ConfigurePuzzle() {

            $(".PuzzlePartContainerDiv").draggable({ snap: ".PuzzleBox", snapMode: "inner", helper: "clone" });

            $(".PuzzleContainer").droppable({

                activeClass: "PuzzleContainerActive",
                drop: function (event, ui) {

                    var parentBox = $(ui.draggable).parent();

                    if ($(parentBox).is(".PuzzleBox")) {

                        var x = parseInt($(parentBox).attr("pX"));
                        var y = parseInt($(parentBox).attr("pY"));

                        PuzzleArray[x][y].CurrentX = -1;
                        PuzzleArray[x][y].CurrentY = -1;
                    }

                    $(parentBox).css("border", "solid");
                    $(parentBox).css("border-width", "1px");
                    $(ui.draggable).css("margin", "2px");
                    $(ui.draggable).appendTo(event.target);
                }
            });

            $(".PuzzleBox").droppable({

                activeClass: "PuzzleBoxActive",
                hoverClass: "PuzzleBoxHover",
                drop: function (event, ui) {

                    var x2 = parseInt($(event.target).attr("pX"));
                    var y2 = parseInt($(event.target).attr("pY"));

                    var container = $(ui.draggable).parent();

                    if ($(event.target).children().length > 0)
                        return false;

                    if ($(container).is(".PuzzleBox")) {

                        $(container).css("border", "solid");
                        $(container).css("border-width", "1px");
                    }

                    $(ui.draggable).css("margin", "0px");
                    $(event.target).css("border", "none");
                    $(ui.draggable).appendTo(event.target);

                    var x = parseInt($(ui.draggable).attr("pX"));
                    var y = parseInt($(ui.draggable).attr("pY"));

                    PuzzleArray[x2][y2].CurrentX = x;
                    PuzzleArray[x2][y2].CurrentY = y;

                    if (IsGameFinished()) {

                        $(".PuzzleBox").animate({ duration: "slow", margin: 0 });
                    }
                }
            });

        }

        function IsGameFinished() {

            for (var y = 0; y < 10; y++) {

                for (var x = 0; x < 10; x++) {

                    if (PuzzleArray[x][y].ActualX != PuzzleArray[x][y].CurrentX || PuzzleArray[x][y].ActualY != PuzzleArray[x][y].CurrentY)
                        return false;
                }
            }

            return true;
        }

        function SliceImageAndCreatePuzzle() {

            var ContainerDiv = $(".PuzzleContainer");
            var puzzleBoard = $(".PuzzleBoard");

            for (var y = 0; y < 10; y++) {

                for (var x = 0; x < 10; x++) {

                    var item = $('<div class="PuzzlePartContainerDiv" pX=' + x + ' pY=' + y + ' style="background-position:-' + x * 50 + 'px -' + y * 50 + 'px"></div>');
                    var itemBox = $('<div class="PuzzleBox" pX=' + x + ' pY=' + y + '></div>');

                    PuzzleArray[x][y].ActualX = x;
                    PuzzleArray[x][y].ActualY = y;

                    PuzzleTmpArray.push(item);
                    puzzleBoard.append(itemBox);
                }
            }
        }

        function ShuffleImages(Shuffle) {

            var containerDiv = $(".PuzzleContainer");

            if (Shuffle) {

                while (PuzzleTmpArray.length > 0) {

                    var rnd = Math.random();

                    var a = PuzzleTmpArray.shift();

                    if (rnd < 0.3) {
                        $(containerDiv).append(a);
                    } else
                        PuzzleTmpArray.push(a);
                }
            } else {

                while (PuzzleTmpArray.length > 0) {

                    var a = PuzzleTmpArray.shift();

                    $(containerDiv).append(a);
                }
            }
        }

        function CreateArray(width, height) {

            var arr = [];
            for (var x = 0; x < width; x++) {
                arr[x] = [];
                for (var y = 0; y < height; y++) {
                    arr[x][y] = new PuzzleWrapper();
                }
            }

            return arr;
        }

</script>


Yukarıdaki javascript kodları içinde yer alan fonksiyonların açıklamaları şöyledir:

* CreateMyWorld(Shuffle): İçine görüntülerin karıştırılıp karıştırmayacağını belirleyen bir boolean parametre alarak oyunu kuran ana fonksiyondur.

* CreateButtonClick(): Oyun üzerinde yer alan ve Shuffle paremetresini yanındaki CheckBox'dan alan yeşil "Oyunu Oluştur" tuşuna basıldığında çalışan fonksiyondur.

* ConfigurePuzzle(): Resim parçalarına sürüklenebilirlik (draggable) özelliğini kazandırıldığı ve resim parçalarını içeren ve bu parçaların yerleştirildiği alanlara düşürülebilirlik (droppable) özelliğinin kazandırıldığı fonksiyondur.

* IsGameFinished(): Oyunun tamamlanıp tamamlanmadığının sonucunu döndüren fonksiyondur.

* SliceImageAndCreatePuzzle(): Resimlerin parçalandığı, ve resimlerin yerleştirileceği kutuların oluşturulduğu fonksiyondur. Bu fonksiyon sonlandığında kutular DOM'a yerleştirilmiş olurken resim parçaları bir dizi içinde saklanmış olmaktadır.

* ShuffleImages(Shuffle): Resim parçalarının karıştırılıp karıştırılmayacağını belirleyen parametreye göre bu parçalara gerekli işlemleri yapıp DOM'a yerleştiren fonksiyondur.

Son olarak da oyun için gerekli HTML kodlarını ekleyelim:

<div>
<div>
<div class="checkbox-inline">
<label>
<input checked="checked" id="CBShuffle" type="checkbox" />Görüntüleri Karıştır</label>
</div>
<button class="btn btn-success" onclick="CreateButtonClick()" type="button">
OYUNU OLUŞTUR</button>
</div>
<br />
<div class="PuzzleBoard">
</div>
<div class="PuzzleContainer">
</div>
</div>


Yukarıda yer alan kodların çalıştırılması ile elde edilen sonuç aşağıdadır:



Sunday, February 28, 2016

Jquery ile Boostrap Açık-Kapalı Dikey Akordiyon Menü Oluşturmak - Designing Bootstrap Open-Close Vertical Accordion Menu with Jquery

Bu yazıda daha önce oluşturulan akordiyon menü sola yaslı açınıp kapanabilen bir yapıya dönüştürülecektir. Bu yazı daha önceki yazının devamı niteliğinde olup akordiyon menü anlatımı için bu yazıya bakmak gerekmektedir.

Öncelikle CSS kodlarını tanımlayalım:

<style>
        
        .menuContainerVyy
        {
            position:relative;
            width: 200px;
            height: auto;
            left:0;
            top:0;
            border-right: 3px solid black;
            background-color:Orange;            
        }
        
        .menuSubContainerVyy
        {
            overflow: hidden;
            background-color:White;
            margin-right:10px;
        }
        
        .menuButtonVyy
        {
            position: absolute;
            left: 100%;
            top: 50%;
            margin-left: -3px;
            margin-top: -15px;
        }
        
        .menuContainerVyy .nav
        {
            width: 200px;
        }
        
</style>

Burada önemli noktalardan ilki "position" tanımlamasıdır. Bu niteliği "relative" olan element mevcut konumuna göre göreceli olarak yerleştirilmektedir. Niteliği "absolute" olan element ise ebeveyn elementi "static" olmayan yani pozisyonlanmış elemente göre göreceli yerleştirilmektedir. Yazı içinde sunum maksadıyla taşıyıcı element "relative" olarak pozisyonlanmıştır. Taşıycı elementin bu niteliği "absolute" yapılarak ve kodları uygun yere konularak menü web uygulaması içinde istenilen bir yere konumlandırılabilir.

Burada bir diğer önemli nokta ise "overflow" niteliğidir. Bu nitelik değeri "hidden" yapılarak animasyonun menü kapsayıcı elementi sıkıştırırken iç yapıyı bozmaması sağlanmıştır. Yani sıkıştırma işlemi sırasında iç elementler kapsayıcı elementin içine sığmayarak taşmakta, bu durumda bu taşan kısımlar gizlenerek daha akıcı bir animasyon oluşturulmakta, ayrıca kapanma animasyonu sonunda menünün tamamen gizlenmesi sağlanmaktadır.

Sonraki aşamada javascript kodlarını tanımlayalım:

function toggleMenu(sender) {

            var parentElement = $(sender).parent("div");

            if (parentElement.width() > 0) {
                parentElement.animate({ width: '0px' }, "slow");
            }
            else {
                parentElement.animate({ width: '200px' }, "slow");
            }
        }

Yukarıda fonksiyon menü açma-kapama işlemini yerine getirmektedir. Bunu yaparken kapsayıcı elementin genişlik değerinin sıfır olup olmadığı kontrol edilmekte, durumu göre kapsayıcı element jquery "animate" fonksiyonu kullanılarak animasyonlu genişletilip daraltılmaktadır.

Bir önceki yazıdan farklı olarak menünün DOM içinde bulunmasında aşağıdaki kod yerine sınıf üzerinden arama yapan yeni kod kullanılmıştır:

#VerticalMenu1.nav.nav-pills.nav-stacked > li
.menuContainerVyy .nav.nav-pills.nav-stacked > li

Son olarak Bootstrap menü kodlarını sarmalayan HTML kodlarını ekleyelim:

<div class="menuContainerVyy">
<button class="btn btn-default menuButtonVyy" onclick="toggleMenu(this);" type="button">
<span class="glyphicon glyphicon-menu-hamburger"></span>
</button>
<div class="menuSubContainerVyy">
BURADA MENÜ KODLARI BULUNMAKTA!
</div>
</div>

Yukarıda yer alan kodlar çalıştırıldığında aşağıdaki sonuç elde edilmektedir:

Friday, February 26, 2016

Jquery ile Boostrap Akordiyon Menü Oluşturmak - Designing Bootstrap Accordion Menu with Jquery

Bu yazıda Bootstrap "Pills" kullanılarak akordiyon menü oluşturulacaktır. İlk aşamada "Vertical Pills" yani dikey hapları oluşturacak Bootstrap kodunu yazalım:

<ul id="VerticalMenu1" class="nav nav-pills nav-stacked">
    <li><a data-toggle="tab" href="#">Home <span class="glyphicon glyphicon-chevron-down" style="float: right;"></span></a></li>
    <div class="panel-body" style = "display:none;">
    Section1
    </div>
    <li><a data-toggle="tab" href="#">Menu 1<span class="glyphicon glyphicon-chevron-down" style="float: right;"></span></a></li>
    <div class="panel-body" style = "display:none;">
    Section2
    </div>
    <li><a data-toggle="tab" href="#">Menu 2<span class="glyphicon glyphicon-chevron-down" style="float: right;"></span></a></li>
    <div class="panel-body" style = "display:none;">
    Section3
    </div>
    <li><a data-toggle="tab" href="#">Menu 3<span class="glyphicon glyphicon-chevron-down" style="float: right;"></span></a></li>
    <div class="panel-body" style = "display:none;">
    Section4
    </div>
  </ul>

Burada önemli unsurlardan biri "data-toggle" niteliğidir. Bu nitelik ile ögenin üstüne tıklandığında otomatik olarak "active" sınıfının ögeye eklenmesi sağlanmaktadır. Detay gösteren div'lerin display niteliği "display:none" yapılarak div'ler görünmez hale getirilmektedir.

Akordiyon özelliğini tanımlamak amacıyla aşağıdaki javascript kodlarını oluşturalım:

$(document).ready(function(){

   $("#VerticalMenu1.nav.nav-pills.nav-stacked > li").click(function(){
     
     var parentElement = this;
     var section = $(parentElement).next("div").first();

     if(!$(section).is(":visible"))

       $(section).slideDown({ duration:"fast", complete: function(){
  
            UpdateArrow($(section).is(":visible"), parentElement);
       }});
     else
       $(section).slideUp({ duration:"fast", complete: function(){

            UpdateArrow($(section).is(":visible"), parentElement);
       }});

   });

});

function UpdateArrow(Visible, Obj)
{
   if(Visible)
   {
      $(Obj).find("span").addClass("glyphicon-chevron-up");
      $(Obj).find("span").removeClass("glyphicon-chevron-down");
   }else
   {
      $(Obj).find("span").removeClass("glyphicon-chevron-up");
      $(Obj).find("span").addClass("glyphicon-chevron-down");
   }

}

Burada jquery "slideUp()" fonksiyonuyla detay alanı kapatılmakta, "slideDown()" fonksiyonu ile detay alanı açılmaktadır. Jquery "next()" fonksiyonuyla sonraki çocuk elementler seçilmektedir. Jquery "find()" fonksiyonu ile DOM üzerinde derin arama yapılmaktadır.

Ok, animasyon olay akışı dışında güncellendiği zaman animasyonun iptal edildiği durumlarda yanlış durama geçebilmektedir (Örn. Hızlı çift tıklama veya seri tıklama). Bu sebeple ok durumunu güncelleme işlemi "complete" olayında yapılmaktadır. Bu olay animasyon tamamlandığında tetiklenmektedir. Animasyon tamanlandığında detay div'in görünürlüğü kontrol edilmekte ve ok durumu düzenlenmektedir.

Yukarıda yer alan kodların çalıştırılması ile aşağıdaki sonuç elde edilmektedir:

Thursday, February 25, 2016

Jquery ile Açılıp Kapanabilen Bootstrap Panel Oluşturmak - Designing Open-Close Bootstrap Panel with Jquery

Bu yazıda bootstrap panelin nasıl açılıp kapanabilen bir yapı haline getirilebileceği konusu işlenecektir. Bootstrap panel div elementleri ile oluşturulan, yorum alanları, içerik görüntülemeleri veya kısa gösterimler gibi bir çok alanda kullanılabilen kullanım alanı geniş bir ögedir. Bootstrap panel aşağıdaki kod bloğu ile oluşturulmaktadır:

<div class="panel panel-primary">
<div class="panel-heading">
Panel with panel-primary class <span class="glyphicon glyphicon-circle-arrow-up" style="float: right;"></span></div>
<div class="panel-body">
Panel Content</div>
</div>

Burada "panel panel-primary" ile "primary" tipinde bir bootstrap panel oluşturulacağı belirtilmektedir. "panel-heading" panelin başlık alanını, "panel-body" ise panelin içeriği taşıyacağı esas alanını belirtmektedir. Başlık içine eklenen "glyphicon" içeren "span" elementi ile panelin durumunu gösteren resim panel başlağına eklenmektedir. "float:right" yapılarak ok işaretinin sağ tarafa kayması sağlanmaktadır. "glyphicon-circle-arrow-up" yukarı işaretinin ekleneceğini belirtmektedir.

Panel HTML kodları oluşturulduktan sonra açılıp kapanma özelliğinin panele kazandırılması için aşağıdaki Jquery javascript kodlarının eklenmesi gerekmektedir:

$(document).ready(function(){
    $(".panel-primary").children(".panel-heading").click(function(){
        $(this).parent().children(".panel-body").toggle();
        $(this).children(".glyphicon").toggleClass("glyphicon-circle-arrow-up");
        $(this).children(".glyphicon").toggleClass("glyphicon-circle-arrow-down");
    });
});

Yukarıdaki kod ile başlık ögesinin "click" olayı yakalanmakta ve toggle() fonksiyonu ile panel içeriğinin görünüp kaybolması sağlanmaktadır. "span" elementinin sınıfı da aynı anda değiştirilerek okun durumu güncellenmektedir.

Yukarıda yer alan kodların çalıştırılması ile aşağıdaki sonuç elde edilmektedir:

Panel with panel-primary class
Panel Content
Panel Content2
Panel Content3
Panel Content4

Wednesday, February 24, 2016

Jquery ile Mayın Tarlası Oyunu (2. Bölüm) - Mine Sweeper Game with Jquery (Section 2)

Bu yazıda mayın tarlası oyununda mayın olmayan yere tıklandığında mayınsız bölgenin otomatik açılması işlemini, mayına basıldığında tüm oyunun açılmasını ve gerekli renklendirmeleri yapacağız.

1. Bölümde ekranı oluşturmuş ve mayınları rastgele yerleştirmiştik. Şimdi bir önceki makalede yer alan CSS kodlarını mayın tuşunun durumuna göre aşağıdaki gibi güncelleyelim:

<style>

        .MineGameCanvas {

            width:500px;
            height:500px;

        }

        .MineButton {

            float:left;
            width:25px;
            height:25px;
        }

        .MineButtonPressed {

            float:left;
            width:25px;
            height:25px;
            pointer-events:none;
            background-color:gray;
            border:inset;
            
        }

        .MineButtonT {

            float:left;
            width:25px;
            height:25px;
            background-color:red;
            pointer-events:none;
        }

        .MineButtonT2 {

            float: left;
            width: 25px;
            height: 25px;
            background-color: orange;
            pointer-events:none;
            
        }
</style>

Burada mayına basılması durumu için "MineButtonT" sınıfı, mayına basılıp oyun sonlandığında diğer mayınları göstermek içi "MineButtonT2" ve boş mayın tarlası alanlarını göstermek için "MineButtonPressed" sınıfları eklenmiştir. Bir diğer önemli nokta ise "pointer-events:none" bilgisidir. Bununla tuşun olay yakalayıcıları etkisizleştirilmektedir (tuş disable yapılmaktadır).

Mayın taraması işleminin ve diğer ek fonksiyonların çalıştırılması için javascript kodu aşağıdaki gibi güncellenmiştir:

<script type="text/javascript">

        var mineCount = 50;
        var arr = [];
        var width = 20;
        var height = 20;
        var possibility = mineCount / (width * height);

        var BoomClass = "MineButtonT";
        var BoomClassShow = "MineButtonT2";
        var MinePressed = "MineButtonPressed";

        var MineSweeperWrapper = function () {

            this.HasMine = false,
            this.IsEnabled = true,
            this.IsPressed = false,
            this.IsFlagged = false,
            this.MineButton = null
        }

        function ButtonPressed(sender) {

            var btNumx = $(sender).attr("btNumx");
            var btNumy = $(sender).attr("btNumy");

            var x = parseInt(btNumx);
            var y = parseInt(btNumy);

            if (arr[x][y].HasMine) {

                arr[x][y].IsPressed = true;
                OpenAll();
            } else {

                EvaluateSituation(x, y);
            }
        }

        function PressMine(X, Y) {

            arr[X][Y].IsEnabled = false;
            $(arr[X][Y].MineButton).toggleClass(MinePressed);
        }

        function EvaluateSituation(X, Y) {

            var stack = [];

            var neighborCount = 0;

            if (ControlButtonHasMine(X, Y + 1, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X, Y - 1, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X + 1, Y, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X + 1, Y - 1, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X + 1, Y + 1, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X - 1, Y, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X - 1, Y - 1, stack)) {
                neighborCount++;
            }

            if (ControlButtonHasMine(X - 1, Y + 1, stack)) {
                neighborCount++;
            }

            if (arr[X][Y].IsEnabled)
                PressMine(X, Y);

            if (neighborCount > 0) {

                $(arr[X][Y].MineButton).val(neighborCount);

            } else {

                while (stack.length > 0) {

                    var neighbour = stack.pop();

                    EvaluateSituation(neighbour.X, neighbour.Y);

                }
            }

        }

        function ControlButtonHasMine(X, Y, stack) {

            if (X >= 0 && X < width && Y >= 0 && Y < height) {

                if (arr[X][Y].IsEnabled) {

                    stack.push(arr[X][Y]);

                    if (!arr[X][Y].HasMine) {

                        return false;

                    } else {

                        return true;
                    }
                }
            }
        }

        function OpenAll() {

            for (var x = 0; x < width; x++) {

                for (var y = 0; y < height; y++) {

                    if (arr[x][y].HasMine) {

                        if (!arr[x][y].IsPressed)
                            $(arr[x][y].MineButton).toggleClass(BoomClassShow);
                        else
                            $(arr[x][y].MineButton).toggleClass(BoomClass);
                    } else {

                        if (arr[x][y].IsEnabled) {

                            $(arr[x][y].MineButton).toggleClass(MinePressed);
                            arr[x][y].IsEnabled = false;
                        }
                    }

                    arr[x][y].IsEnabled = false;
                }
            }
        }

        $(document).ready(function () {

            arr = CreateArray(width, height, 0);

            PlantMines();

            GenerateMineField();


        });

        function GenerateMineField() {

            var canvas = $(".MineGameCanvas");

            for (var x = 0; x < width; x++) {

                for (var y = 0; y < height; y++) {

                    var button = $('<input id="Button-' + x + '-' + y + '" type="button" value="" class ="MineButton" btNumx="' + x + '" btNumy="' + y + '" onClick="ButtonPressed(this)"/>');
                    arr[x][y].MineButton = button;
                    arr[x][y].X = x;
                    arr[x][y].Y = y;
                    canvas.append(button);
                }
            }
        }

        function CreateArray(witdh, height, defaultValue) {

            var arr = [];
            for (var x = 0; x < width; x++) {
                arr[x] = [];
                for (var y = 0; y < height; y++) {
                    arr[x][y] = new MineSweeperWrapper();
                }
            }

            return arr;
        }

        function PlantMines() {

            for (var x = 0; x < width; x++) {
                for (var y = 0; y < height; y++) {

                    if (!arr[x][y].HasMine) {

                        var deger = Math.random();

                        if (deger <= possibility) {
                            arr[x][y].HasMine = true;
                            mineCount--;

                            if (mineCount == 0)
                                return;
                        }
                        else {
                            arr[x][y].HasMine = false;;
                        }
                    }
                }
            }

            if (mineCount > 0)
                PlantMines();
        }

    </script>

Bir önceki makalede anlatılmayan ve yeni eklenen fonksiyonların işlevleri şöyledir:

* PressMine fonksiyonu bir tuşa basıldığında tuş ile ilgili gerekli sınıf değişiklikleri ve durum değişikliklerini yapmaktadır.

* EvaluateSituation fonksiyonu mayın olmayan boş bir alana tıklandığında mayınsız alanı tarama ve mayınları sayma işlemlerinin yerine getirildiği recursive fonksiyondur.

* ControlButtonHasMine fonksiyonu tuş üzerinde mayın olup olmadığını ve kontrol edilen tuşun geçerli bir tuş olup olmadığını kontrol eden fonksiyondur. Ayrıca tuş çevresinde yer alan komşu tuşların eğer kontrol edilmemişlerse yığına eklenme işlemi de burada yapılmaktadır. Yığın içinde yer alan komşu tuşlar EvaluateSituation fonsiyonu içinde tekrar çağrılarak değerlendirilmektedir.

* OpenAll fonksiyonu mayına basılıp oyun sonlandığında bütün mayın alanını açık hale getiren fonksiyondur.

Bu makalede önemli noktalardan ilki javascript sınıf tanımlamasıdır:

var MineSweeperWrapper = function () {

            this.HasMine = false,
            this.IsEnabled = true,
            this.IsPressed = false,
            this.IsFlagged = false,
            this.MineButton = null
        }

Yukarıda görüldüğü gibi constructer olarak kullanılan bir fonksiyon üzerinden tanımlama yapılmaktadır. Sınıf ve arr dizisi kullanılarak tarama işleminin hızlı yapılması sağlanmaktadır. Diğer durumda DOM üzerinden işlem yapmak daha zordur.

MineSweeperWrapper sınıfı gerekli algoritmik alanları ve ilgili DOM nesnesine referans içermektedir. Bu alanlardan "HasMine" tuş üzerinde mayın olup olmadığı bilgisini, "IsEnabled" tuşun kullanılabilir olup olmadığı bilgisini, "IsPressed" basılan tuşun işaret bilgisini, "IsFlagged" tuşa bayrak konulup konulmadığı bilgisini (sonraki makalede işlenecektir) ve son olarak "MineButton" DOM nesnesine referans bilgisini sağlamaktadır.

Bu yazıda diğer önemli nokta ise yığın (stack) kullanımıdır. Yığınlara kasik diziler ile aynı şekilde tanımlanırken yığına ekleme için push(), yığında çıkarma için pop() fonksiyonları kullanılmaktadır.

Yukarıdaki kodların çalıştırılması sonucu elde edilen sonuç aşağıdaki gibidir: