2008年5月14日水曜日

Pagenation

なんか英語だとかっこよく見えるけど、普通にページ切り替えのこと。 LINQ使ってIQueryableなデータをページ切り替えできるようにするってばよ。

ASP.NET MVC: PagedList<T> : Rob Conery

ここのソースをそのまま流用してもよし。少しいじるもよし。自作するもよし。 結局はこういう形に落ち着くはず。 IPagedListとインターフェースを定義しておくのにも訳があり。

ASP.NET MVC - Pagination View User Control | Code-Inside Blog International

↑こういうページ切り替えコントロールを作成する時に、インターフェース渡しにしておくことで、型に依存しなくて済むから。IPagedListを受け取るようにコントロールを作っておけば、どんな型でも関係なく、ページに関する情報のみ取得できるでしょ。

上記、いずれもASP.NET MVCって書いてるけど、LINQだからMVCかどうかは関係ないと思われる。 ところで、ASP.NET MVCに限らず、AJAX的なページの部分更新を行う場合って、一般的な方法というのがあるんだろうか。 今はMVCで作ってるとはいえ、MVCに限った悩みとは思えず。 特に、リストでデータを持ってる場合とか。

<div id="container">
 <ul id="list">
   <li id="item1">Data1</li>
   <li id="item2">Data2</li>
   <li id="item3">Data3</li>
 </ul>
</div>

こんな感じのHTMLを持ってるとして、ulにliを1つ追加するような処理ってどうしましょうか、っていうね。 1.ページ全体更新。 2.ul全体(ulタグ込み)を取得して、divのinnerHTMLを書き換え。 3.追加対象のli(liタグ込み)を取得して、ulのinnerHTMLに書き足し。 4.追加対象のliの中身(liタグ無し)だけを取得して、document.createElement('li')のinnerHTMLに値を入れた後、ulにappendChild。 5.JSONか何かでデータだけを取得して、クライアントサイドですべての表示要素をcreateElement。

上からデータ量の多い順(3と4は誤差の範囲だけど)。 1はそもそも、ページ全体なんだからAjaxとか関係なし。 5はサーバーサイドでのビュー定義がまったくもって役に立たなくなりかねないし、JavaScriptコードが多すぎて面倒。Google Gearとかだとこの方法じゃないとつらいと思われるけど、今回は対象外としたい。 2・3・4のどれを選ぶのが妥当なんだろうか。 2の場合、ページの初回表示の時に使用するであろうコントロール(ASP.NETだとUserControlだし、Railsならpartialか)を、 Ajaxの結果としてResponse.Write。データ1個を返すだけだったりしても、リスト全体が対象になる分、データ量は増えるけど処理は簡単。 3と4の場合(ほとんど一緒)、リスト全体を表現するコントロールと、リストアイテムのコントロールに分けて作っておけば、ページ出力の場合と、部分出力の場合でも、それほどコード量に差が出てくるわけでもないんだけど、データ量は少なく済む。 んじゃ、常に3か4でいいのか?ってことになるんだけど、結局4だとcreatElementしなきゃいけなくて、コードがめんどっちくなる。3はというと、結構いいんだけど、サーバーサイドのコントロール階層が少し深くなって見通し悪しな気がしなくもなく。 でも結局は、2と3の組み合わせ(適材適所で!)になるんだろうとは思うけど。 今はずっとASP.NET MVCで、PostBack方式でのWebFormsを全然使ってないんだけど、サニタイズ気をつけてれば、こっちのほうが自分の思考にあってて作りやすい気がしてならない。 それもこれも結局は好みの問題なんだろね。

ハァ~。NHLプレーオフ生で観たい。デトロイト今年こそやってくれそうだし。

2008年5月6日火曜日

面白いPNGの利用法

nihilogic: Compression using Canvas and PNG-embedded data 面白い人もいるもんだな~。 JavaScriptファイルをPNGファイルにしちゃって、CanvasのgetImageDataを使って再度JavaScriptに復元。 画像ファイルはあまりにも砂嵐。スクリプトの文字コードをそのままRGBにセットして、画像を生成してるからね。なので、8ビット(0~255)グレースケールの画像になるし、1文字が1ピクセル。そりゃ砂嵐だぜ。 CanvasはIEじゃ使えないからFirefoxとOpera、あと最新のWebkitでしか、この方法は使えませんよ、って言う事なんですね。 スゴイな。こんな発想なかった。GZipでいいじゃね~か、と思う自分がちょっと恥ずかしいっす。 スクリプトから画像生成するのはPHPのコードになってたけど、そのままだと試しにくいので、C#で書きなおしてみた(そのままデス)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace MakeJSPng.Controllers
{
 public class HomeController : Controller
 {
   public void Index()
   {
     string js = this.ReadFromRequest("JSSource") + "";
     int hash = Math.Abs(js.GetHashCode());
     string fileName = string.Format("{0}.png", hash);
     string filePath = Request.MapPath("~/PNGs/") + fileName;

     if (js.Length > 0)
     {
       ViewData["JSSource"] = js;
       byte[] bytes = Encoding.UTF8.GetBytes(js);
       int width = (int)Math.Ceiling(Math.Sqrt((double)bytes.Length));
       int height = width;

       using (Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb))
       {
         int pos = 0;
         for (int y = 0; y < height && pos < bytes.Length; y++)
         {
           for (int x = 0; x < width && pos < bytes.Length; x++)
           {
             int val = (int)bytes[pos++];
             bmp.SetPixel(x, y, Color.FromArgb(0, val, val, val));
           }
         }
         bmp.Save(filePath, ImageFormat.Png);
       }
     }

     ViewData["PngPath"] = "/PNGs/" + fileName;

     RenderView("Index");
   }

   public void About()
   {
     RenderView("About");
   }
 }
} 

ASP.NET MVC Preview2で動くよ。 Home/Index.aspxは↓。

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MakeJSPng.Views.Home.Index" %>
<%@ Import Namespace="MakeJSPng.Controllers" %>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">
<script type="text/javascript" src="/Content/pngdata.js"></script>
<% using (Html.Form<HomeController>(c=>c.Index())) { %>

<p>スクリプト</p>
<%=Html.TextArea("JSSource", ViewData["JSSource"]) %>

<p>
<%=Html.SubmitButton("Make", "生成") %>
</p>

<p>画像</p>
<img src="<%= ViewData["PngPath"] %>" id="png" />

<p>復元</p>
<%=Html.TextArea("PNGSource", "") %>
<% } %>


<script type="text/javascript">

var path = '<%= ViewData["PngPath"] %>';
loadPNGData(path, function decodeCallback(data){
 var element = document.getElementById("PNGSource");
 element.value = data;
});

</script>
</asp:Content>

でも、IEじゃ動かないよ! 試しに、prototype.1.6.0.2.jsを圧縮した画像↓。 img.aspx

砂嵐。 本家はこれが30KBなんだけど、こっちは50KBなんでじゃ~!!画像サイズ少し違うし。PHPでのデフォルトエンコードがUTF8じゃないのかもしれないしね。 本家は8bppだけど、こっちは24bppなのが原因?それじゃしょうがないよね! ところでPHPのコードは良くわかんない(GDが良くわかんない?)けど、TrueColorを保存して自動で8ビットになるんでしょうか? ちょっとした息抜きってことで。

2026年06月16日の記事一覧

(全 23 件) そうきたか。マイクロソフトが新しく提案するAI搭載の「社員証」 「WSL」のバージョン3が開発者にもたらす大きなメリット Stack Overflow、AIエージェント同士が掲示板で技術情報を共有する「Stack Overflow fo...