しなもんとどこでも遊べるGreasemonkey & Bookmarklet

id:sawat:20060922の続きですが、ふと思うところがあって作ってみました。

しなもんがブラウザ上のマウスカーソルを追いかけてきます。マウスをぐるぐる動かして気が済むまで、しなもんと追いかけっこしましょう。


図1 : しなもんがマウスカーソルを追っかけてくる
いわゆるデスクトップアクセサリーの類です。ただし、ブラウザ内でしか動かないので正しくはブラウザトップアクセサリー。ページが変わるたびに消えてしまうのが難点。
さすがにこれだけじゃつまんないので、おしゃべり機能も搭載してみました。


図2 : しなもんがしゃべった!

はてなブックマークエントリー情報取得APIを使用して、だれかの受け売りコメントを発します。よって、だれもブックマークコメントを書いていないページでは無口です。

Greasemonkey または Trixie は以下をインストール。

http://sawat.jf.land.to/cinnamon/browsertop_accesory_cinnamon.user.js
初期状態では、はてな全域で有効になっていますw

ブックマークレットでもOK
javascript:(function(){var%20s=document.createElement("script");s.charset="Shift_JIS";s.src="http://sawat.jf.land.to/cinnamon/browsertop_accesory_cinnamon.user.js";document.body.appendChild(s)})();

WinXP SP2上の IE6.0 + Trixie ver0.23、および Firefox1.5.0.7 + Greasemonkey0.6.5で確認しました。

まあ、なんの役にも立ちませんが・・・。

ソースは以下

// ==UserScript==
// @name          CINNAMON
// @namespace     http://d.hatena.ne.jp/sawat/
// @description   Browser-top-accesory CINNAMON
// @include       http://*.hatena.*/*
// ==/UserScript==

//
// Bookmarklet
//javascript:(function(){var%20s=document.createElement(%22script%22);s.charset=%22Shift_JIS%22;s.src=%22http://sawat.jf.land.to/cinnamon/browsertop_accesory.js%22;document.body.appendChild(s)})();
//

if(window.CinnamonBrowserTopAccessory === undefined) {
  window.CinnamonBrowserTopAccessory = function () {
    this.initialize();
  };
  CinnamonBrowserTopAccessory.instances = [];
  
  CinnamonBrowserTopAccessory.prototype = {
    initialize: function() {
      this.div = document.createElement("div");
      this.div = document.body.appendChild(this.setStyle(this.div,this.STYLE));
      this.div.style.zIndex = 100;
      this.imgs = this.addImgs(this.div, this.IMAGES);
      this.commentSpan = this.div.appendChild(this.setStyle(document.createElement("span"),this.STYLE));
      this.setStyle(this.commentSpan, {marginLeft: "34px", textAlign: "left", 
                 display:"none", width: "300px", fontSize:"80%", background: "#DDDDFF"});  
      this.mouseX = 0;
      this.mouseY = 0;
      this.prevX = 0;
      this.prevY = 0;
      this.number = CinnamonBrowserTopAccessory.instances.length;
      this.speed = 2 * (this.number % 5) * (1 - 2 * (this.number % 2));
      this.stayPoint = 0;
      this.prevImg = this.imgs.run_ld;
      CinnamonBrowserTopAccessory.getBookmarkInfo();
      var self = this;
      
      this.initEventListener();
        
      setTimeout(function(){setInterval(
        function(){self.action();}, 100);}, 3000); 
      
      CinnamonBrowserTopAccessory.instances.push(this);
    },
    setStyle: function(element, style) {
      for(var s in style) {
        element.style[s] = style[s];
      }
      return element;
    },
    initEventListener: function() {
      var self = this;
      var listener = function(event) {self.mv(event)};
      if(document.body.addEventListener) {
        document.body.addEventListener("mousemove",listener,false);
        document.body.addEventListener("scroll ",listener,false);
      } else if(document.body.attachEvent){
        document.body.attachEvent("onmousemove",listener,false);
        document.body.attachEvent("onscroll",listener,false);
      }
    },
    addImgs: function(parent, img_urls) {
      var imgs = {};
      for(var name in img_urls) {
        var img = document.createElement("img");
        imgs[name] = this.setStyle(img, this.STYLE);
        img.style.visibility = "hidden";
        img.src = img_urls[name];
        parent.appendChild(img);
      }
      return imgs;
    },
    action: function () {
      var dy = this.mouseY-this.prevY-16;
      var dx = this.mouseX-this.prevX-16;
      var dispImg;
      if(Math.abs(dy) > 50 || Math.abs(dx) > 50) {
        if(this.stayPoint > 20) {
          this.stayPoint = Math.floor(this.stayPoint * (1 - 0.5 * Math.random())); 
          return;
        }
        this.stayPoint = 0;
        if(Math.abs(dy) > 0) {
          this.prevY = Math.round(this.prevY + dy/(15+this.speed));
          this.div.style.top = this.prevY + "px";
        }
        if(Math.abs(dx) > 0) {
          this.prevX = Math.round(this.prevX + dx/(15-this.speed));
          this.div.style.left = this.prevX + "px";
        }
        var dypdx = dy / dx;
        
        if(dx < 0 && dypdx < 0.25)  {
          dispImg = this.imgs.run_ld;
        } else if(dx < 0)  {
          dispImg = this.imgs.run_lu;
        } else if(dypdx > -0.25)  {
          dispImg = this.imgs.run_rd;
        } else {
          dispImg = this.imgs.run_ru;
        }
      } else {
          if(this.stayPoint < 200) {
            if(this.stayPoint == 100) {
              var bm = CinnamonBrowserTopAccessory.bookmarkComments;
              if(bm && bm.length != 0) {
                var span = this.commentSpan;
                span.innerHTML = bm[Math.floor(Math.random() * bm.length)];
                span.style.display = "inline";
                setTimeout(function() { span.style.display="none";}, 5000);
              }
            }
            this.stayPoint++;
            dispImg = this.imgs.down;
          } else if(this.stayPoint < 2000) {
            this.stayPoint+= 10;
            dispImg = this.imgs.sleep;
          } else if(this.stayPoint < 10000) {
            this.stayPoint += 50;
            dispImg = this.imgs.deep_sleep;
          }
      }
      if(dispImg != undefined) {
        this.prevImg.style.visibility = "hidden";
        dispImg.style.visibility = "visible";
        this.prevImg = dispImg;
      }
    }, 
    mv: function(event) {
      this.mouseX = document.body.scrollLeft + event.clientX;
      this.mouseY = document.body.scrollTop + event.clientY;
    },
    IMAGES : {
      run_ld : "http://sawat.jf.land.to/cinnamon/cinnamon_run0.gif",
      run_rd : "http://sawat.jf.land.to/cinnamon/cinnamon_run1.gif",
      run_lu : "http://sawat.jf.land.to/cinnamon/cinnamon_run2.gif",
      run_ru : "http://sawat.jf.land.to/cinnamon/cinnamon_run3.gif",
      down   : "http://sawat.jf.land.to/cinnamon/cinnamon7.gif",
      sleep  : "http://sawat.jf.land.to/cinnamon/cinnamon9.gif",
      deep_sleep  : "http://sawat.jf.land.to/cinnamon/cinnamon_sleep.gif"
    },
    STYLE : {
      position: "absolute",
      left: "0px",
      top: "0px",
      borderWidth: "0px",
      background: "transparent",
      margin: "0px",
      padding: "0px",
      clear: "none",
      display: "block"
    }
  };
  CinnamonBrowserTopAccessory.getBookmarkInfo= function() {
    if(CinnamonBrowserTopAccessory.bookmarkComments) return;
    CinnamonBrowserTopAccessory.bookmarkComments = [];
    
    if(typeof(GM_log) == "function") { // for greasemonkey
      GM_xmlhttpRequest({
        method: 'GET',
        url: "http://b.hatena.ne.jp/entry/json/" + document.URL.replace('#','%23'),
        headers: {
          'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
          'Accept': 'application/atom+xml,application/xml,text/xml'
        },
        onload: function(responseDetails) {
          CinnamonBrowserTopAccessory.callback(eval(responseDetails.responseText));
        }
      });
    } else { // for bookmarklet or Trixie
      var url = "http://b.hatena.ne.jp/entry/json/?url="
                  + encodeURIComponent(document.URL) 
                  + "&callback=CinnamonBrowserTopAccessory.callback";
                  
      this.url = url;
      var jsonpScript = document.createElement("script");
      jsonpScript.src = url;
      jsonpScript.type = "text/javascript";
      document.body.appendChild(jsonpScript);
    }
  };
  CinnamonBrowserTopAccessory.callback = function(bookmarkInfo) {
    if(!bookmarkInfo) {
      return;
    }
    for(var i=0,n=bookmarkInfo.bookmarks.length;i<n;i++) {
      var com = bookmarkInfo.bookmarks[i].comment;
      if(com.length != 0) {
        CinnamonBrowserTopAccessory.bookmarkComments.push(com);
      }
    }
  };
}
if(document.body) {
  new CinnamonBrowserTopAccessory();
}