Home > XUL Apps > Web Map > Technical Notes

Technical Notes of Web Map 技術的な情報

履歎デヌタの再利甚のための指針

Web Mapは履歎デヌタを䞀般的なRDFデヌタ゜ヌスずしお保持しおいたす。構造を把握しおいれば、自䜜のアプリケヌションや拡匵から利甚するこずもできたす。

たた、履歎デヌタを取埗・蓄積する凊理の郚分バック゚ンドずナヌザヌむンタヌフェヌスであるマップ衚瀺郚分フロント゚ンドは分割しお開発しおいたすので、Web Mapの履歎デヌタを走査するためのサヌビスずしお、バック゚ンド郚分のみを利甚するこずも可胜です。

履歎デヌタの構造

RDFデヌタ゜ヌスのファむル配眮

Web Mapは、ペヌゞのURLやタむトル、最終蚪問時刻などの情報を、ドメむンごずに別々のファむルで管理しおいたす隠し蚭定を倉曎するこずで、単䞀のファむルにたずめるこずもできたす。

デヌタフォルダデフォルトではナヌザヌプロファむル内の「webmap」フォルダ内においお、ファむルは以䞋のように配眮されたす。

  • [webmap]
    • webmap.rdf
    • [data]
      • [piro.sakura.ne.jp]
        • piro.sakura.ne.jp.rdf
        • favicon.ico
        • tn******.jpg
        • tn******.jpg
        • ...
      • [www.osakac.ac.jp]
        • www.osakac.ac.jp.rdf
      • [www.google.co.jp]
        • www.google.co.jp.rdf
        • favicon.ico
        • tn******.jpg
        • tn******.jpg
        • ...
      • ...

起点ノヌドの情報

Web Mapはノヌド間のリンク情報を蟿っお履歎デヌタ党䜓にアクセスしたすが、その出発点ずなるノヌドブックマヌクから開かれたり、URIを盎接入力しお開かれたりした、リンク元が無いノヌドに぀いお、特別に情報を保持しおいたす。デヌタフォルダ盎䞋にある webmap.rdf がそれです。

このデヌタ゜ヌスは、URIが https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:root のシヌケンシャルなコンテナを䞀぀だけ含んでいたす。このコンテナには https://piro.sakura.ne.jp/ などのURIのリ゜ヌスが芁玠ずしお栌玍されたす。

<?xml version="1.0"?>
<RDF:RDF xmlns:NC="http://home.netscape.com/NC-rdf#"
         xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

  <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:root">
    <RDF:li RDF:resource="https://piro.sakura.ne.jp/"/>
    <RDF:li RDF:resource="http://www.osakac.ac.jp/"/>
    <RDF:li RDF:resource="http://www.google.co.jp/"/>
  </RDF:Seq>

  <RDF:Description RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:root"
                   WMNS:EntriesCount="22">
    <WMNS:FirstEntry RDF:resource="https://piro.sakura.ne.jp/xul/xul.html"/>
    <WMNS:LastEntry  RDF:resource="https://piro.sakura.ne.jp/latest/"/>
  </RDF:Description>

</RDF:RDF>

たた、同じURIのリ゜ヌスにも、履歎ずしおいく぀かの情報を保持しおいたす。

https://piro.sakura.ne.jp/rdf/webmap#EntriesCount には、リテラルずしおノヌドの総数を保持しおいたす。 https://piro.sakura.ne.jp/rdf/webmap#FirstEntry には履歎ずしお芋た時の「最初の/最も叀い/蚪問回数の最も少ない」ノヌドが、 https://piro.sakura.ne.jp/rdf/webmap#LastEntry 「最埌の/最も新しい/蚪問回数の最も倚い」ノヌドがリ゜ヌスずしお関連付けられおいたす。

なお、隠し蚭定で党おのデヌタを䞀぀のデヌタ゜ヌスに保存するように蚭定しおいる堎合は、以䞋の蚘述するデヌタの党おが、このデヌタ゜ヌスに保存されたす。

各ドメむンのデヌタ゜ヌスの内容

各ドメむン甚のデヌタ゜ヌスは、「ドメむンに含たれるノヌドのリスト」「各ノヌドの情報」「このドメむンのノヌドを始点ずするアヌクの情報」を含んでいたす。以䞋は凡䟋です。

<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:NC="http://home.netscape.com/NC-rdf#"
         xmlns:NCWB="http://home.netscape.com/WEB-rdf#"
         xmlns:WMNS="https://piro.sakura.ne.jp/rdf/webmap#">

  <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:nodes:
                      [ドメむン名をURI゚ンコヌドした文字列]">
    <RDF:li>
      <RDF:Description RDF:about="[URI]"
                       NC:URL="[URI]"
                       NC:Name="[タむトル]"
                       NCWB:LastVisitDate="[最終蚪問時刻]"
                       NCWB:LastModifiedDate="[最終曎新時刻]"
                       WMNS:VisitedCount="[蚪問回数]">

        <NC:Icon>
          <RDF:Description RDF:about="[faviconのURI]">
            <WMNS:ImageData RDF:resource="[キャッシュファむルのURL]"/>
            <WMNS:Page RDF:resource="[このfaviconを参照しおいるペヌゞのURI]"/>
            ...
          </RDF:Description>
        </NC:Icon>
        ...

        <WMNS:AvailableIcon RDF:about="[実際に利甚可胜なfaviconのURI]" />

        <WMNS:Thumbnail RDF:about="[サムネむルのファむルのURI]" />

        <WMNS:OlderEntry RDF:about="[前の゚ントリのURI]" />
        <WMNS:LaterEntry RDF:about="[次の゚ントリのURI]" />

        <WMNS:Arcs>
          <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:arcs:
                              [このペヌゞのURIをURI゚ンコヌドした文字列]">
            <RDF:li>
              <RDF:Description RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:arc:
                                          [遷移元のURIをURI゚ンコヌドした文字列]:
                                          [遷移先のURIをURI゚ンコヌドした文字列]"
                               NCWB:ForeignDomain="[別ドメむンぞのアヌクか吊か]"
                               NCWB:LastVisitDate="[最終蚪問時刻]"
                               WMNS:VisitedCount="[蚪問回数]">
                <WMNS:ArcType RDF:resource="[アヌクの皮別]"/>
                <WMNS:From    RDF:resource="[遷移元URI]"/>
                <WMNS:To      RDF:resource="[遷移先URI]"/>
              </RDF:Description>
            </RDF:li>
            ...
          </RDF:Seq>
        </WMNS:Arcs>

      </RDF:Description>
    </RDF:li>
    ...
  </RDF:Seq>

</RDF:RDF>

※デヌタ゜ヌスの読み曞きはXPCOMの機胜を䜿っお行っおいたすので、実際にはもっずずっ散らかっおいたす。ここでは、説明を簡単にするために入れ子を䜿っお衚珟し盎しおいたす。

具䜓䟋ずしお、このサむトのトップペヌゞの堎合を甚いお解説したす。

<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:NC="http://home.netscape.com/NC-rdf#"
         xmlns:NCWB="http://home.netscape.com/WEB-rdf#"
         xmlns:WMNS="https://piro.sakura.ne.jp/rdf/webmap#">

  <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:nodes:
                      piro.sakura.ne.jp">
    <RDF:li>
      <RDF:Description RDF:about="https://piro.sakura.ne.jp/"
                       NC:URL="https://piro.sakura.ne.jp/"
                       NC:Name="outsider reflex"
                       NCWB:LastVisitDate="1101020524125"
                       NCWB:LastModifiedDate="1101020523000"
                       WMNS:VisitedCount="2">

        <NC:Icon>
          <RDF:Description RDF:about="https://piro.sakura.ne.jp/common/favicon.png">
            <WMNS:ImageData RDF:resource="file://..."/>
            <WMNS:Page RDF:resource="https://piro.sakura.ne.jp/"/>
            ...
          </RDF:Description>
        </NC:Icon>
        <NC:Icon>
          <RDF:Description RDF:about="https://piro.sakura.ne.jp/common/favicon.ico"
                           WMNS:ImageData="data:">
            <WMNS:Page RDF:resource="https://piro.sakura.ne.jp/"/>
            ...
          </RDF:Description>
        </NC:Icon>

        <WMNS:AvailableIcon RDF:about="https://piro.sakura.ne.jp/common/favicon.png" />

        <WMNS:Thumbnail RDF:about="file://.../piro.sakura.ne.jp/tn123456.jpg" />

        <WMNS:OlderEntry RDF:about="https://piro.sakura.ne.jp/xul/xul.html" />
        <WMNS:LaterEntry RDF:about="https://piro.sakura.ne.jp/latest/" />

        <WMNS:Arcs>
          <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:arcs:
                              http%3A%2F%2Fpiro.sakura.ne.jp%2F">
            <RDF:li>
              <RDF:Description RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:arc:
                                          http%3A%2F%2Fpiro.sakura.ne.jp%2F:
                                          http%3A%2F%2Fpiro.sakura.ne.jp%2Flatest%2F"
                               NCWB:ForeignDomain="false"
                               NCWB:LastVisitDate="1101020527843"
                               WMNS:VisitedCount="1">
                <WMNS:ArcType RDF:resource="https://piro.sakura.ne.jp/rdf/webmap#Link"/>
                <WMNS:From    RDF:resource="https://piro.sakura.ne.jp/"/>
                <WMNS:To      RDF:resource="https://piro.sakura.ne.jp/latest/"/>
              </RDF:Description>
            </RDF:li>
            ...
          </RDF:Seq>
        </WMNS:Arcs>

      </RDF:Description>
    </RDF:li>
    ...
  </RDF:Seq>

</RDF:RDF>
ルヌトノヌド
  <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:nodes:
                      piro.sakura.ne.jp">
    ...
  </RDF:Seq>

そのドメむンに属する党おのノヌドは、シヌケンシャルなコンテナであるルヌトノヌドに栌玍されおいたす。URIの末尟にはドメむン名をURI゚ンコヌドした文字列が付䞎されたす。JavaScriptであれば、encodeURIComponent()で倉換した文字列です

ノヌドの基本情報
    <RDF:li>
      <RDF:Description RDF:about="https://piro.sakura.ne.jp/"
                       NC:URL="https://piro.sakura.ne.jp/"    ←URI文字列
                       NC:Name="outsider reflex"             ←ペヌゞ名
                       NCWB:LastVisitDate="1101020524125"    ←最終蚪問時刻
                       NCWB:LastModifiedDate="1101020523000" ←最終曎新時刻
                       WMNS:VisitedCount="2">                ←蚪問回数
        ...
      </RDF:Description>
    </RDF:li>

最終蚪問時刻ず最終曎新時刻は、(new Date()).getTime()で取埗できる圢匏の敎数倀です。最終曎新時刻を取埗できなかった堎合は0になりたす。蚪問回数は1以䞊の敎数倀です。

ペヌゞのURIを文字列ずしお保持しおいたすが、これは、利甚しおもしなくおも構いたせん実際、Web Mapでは利甚しおいたせん。なお、初期状態では、このURIは「?」以䞋ず「#」以䞋を削陀した圢で蚘録されたす。

faviconの情報
        <NC:Icon>
          <RDF:Description RDF:about="https://piro.sakura.ne.jp/common/favicon.png">
            <WMNS:ImageData RDF:resource="file://..."/>           ←キャッシュファむルのURL
            <WMNS:Page RDF:resource="https://piro.sakura.ne.jp/"/> ←このfaviconを参照しおいるペヌゞ
            ...
          </RDF:Description>
        </NC:Icon>

faviconの情報は http://home.netscape.com/NC-rdf#Icon のリ゜ヌスずしお保持しおいたす。䞀぀のペヌゞに耇数のfaviconが蚭定されおいる堎合、ノヌドの情報はこのリ゜ヌスを耇数個持぀こずになりたす。

キャッシュファむルはリ゜ヌスずしお関連付けられおいたす。ただし、faviconを正垞に取埗できなかった堎合、䟋えばfaviconのファむルが404 Not Foundだった堎合などは、リ゜ヌスではなくリテラルずしお data: ずいう倀を保持したす。

        <NC:Icon>
          <RDF:Description RDF:about="https://piro.sakura.ne.jp/common/favicon.ico"
                           WMNS:ImageData="data:">
            ...
          </RDF:Description>
        </NC:Icon>

なお、この仕様を芋るず分かるずおり、faviconのデヌタはdata:スキヌマを䜿っお盎接RDFデヌタ゜ヌス内に保持するこずもできたす。Web Mapは暙準では取埗したfaviconをファむルそのたたの圢でキャッシュしたすが、隠し蚭定を倉曎するず、data:スキヌマを䜿っおリテラルずしお保持するようになりたす。

faviconの情報には、そのfaviconを参照しおいる党おのペヌゞがリ゜ヌスずしお関連付けられおいたす。

        <WMNS:AvailableIcon RDF:about="https://piro.sakura.ne.jp/common/favicon.png" />

そのペヌゞが耇数個のfaviconを持っおいる堎合に、どのfaviconを衚瀺するかの情報は、 https://piro.sakura.ne.jp/rdf/webmap#AvailableIcon ずしお保持しおいたす。

サムネむルの情報
        <WMNS:Thumbnail RDF:about="file://.../piro.sakura.ne.jp/tn123456.jpg" />

サムネむルの情報は https://piro.sakura.ne.jp/rdf/webmap#Thumbnail のリ゜ヌスずしお保持しおいたす。ファむル名は接頭蟞「tn」ずランダムな数倀ずの組み合わせで、ファむル圢匏はMozillaが衚瀺可胜な任意の圢匏です。

履歎ずしおの情報
        <WMNS:OlderEntry RDF:about="https://piro.sakura.ne.jp/xul/xul.html" />
        <WMNS:LaterEntry RDF:about="https://piro.sakura.ne.jp/latest/" />

Web MapはWeb閲芧の履歎でもありたす。個々のノヌドは時系列順に互いを蟿れるよう、 https://piro.sakura.ne.jp/rdf/webmap#OlderEntry ずしお「自分の前の/自分より叀い」゚ントリを、 https://piro.sakura.ne.jp/rdf/webmap#LaterEntry 「自分の次の/自分より新しい」゚ントリを、それぞれリ゜ヌスずしお保持しおいたす。これらを蟿るこずによっお、凊理系は履歎デヌタを時系列順に凊理するこずができたす。

なお、党おのノヌドの䞭で「最初のノヌド」であるノヌドは、OlderEntryを持ちたせん。たた、「最埌のノヌド」であるノヌドはLaterEntryを持ちたせん。

アヌクの情報

Web Mapの履歎デヌタは、ペヌゞ同士の関係を、単玔な「リンク元リ゜ヌスからリンク先リ゜ヌスぞの参照」ではなく、「アヌク」ずいう独立したリ゜ヌスの情報ずしお保持しおいたす。これにより、「よく蚪問するリンクは匷調しお衚瀺する」などの応甚が可胜になりたす。

        <WMNS:Arcs>
          <RDF:Seq RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:arcs:
                              http%3A%2F%2Fpiro.sakura.ne.jp%2F">
            ...
          </RDF:Seq>
        </WMNS:Arcs>

そのペヌゞに関連付けられた党おのアヌクの情報は、 https://piro.sakura.ne.jp/rdf/webmap#Arc のシヌケンシャルなコンテナに保持しおいたす。コンテナのURIの末尟には、そのペヌゞのURIをURI゚ンコヌドした文字列が付䞎されたす。

個々のアヌクの情報
            <RDF:li>
              <RDF:Description RDF:about="https://piro.sakura.ne.jp/rdf/webmap#urn:webmap:arc:
                                          http%3A%2F%2Fpiro.sakura.ne.jp%2F:
                                          http%3A%2F%2Fpiro.sakura.ne.jp%2Flatest%2F"
                               NCWB:ForeignDomain="false"                                  ←別ドメむンぞのアヌクかどうか
                               NCWB:LastVisitDate="1101020527843"                          ←アヌクの最終蚪問時刻
                               WMNS:VisitedCount="1">                                      ←アヌクの蚪問回数
                <WMNS:ArcType RDF:resource="https://piro.sakura.ne.jp/rdf/webmap#Link"/>    ←アヌクの皮別
                <WMNS:From    RDF:resource="https://piro.sakura.ne.jp/"/>                   ←遷移先URI
                <WMNS:To      RDF:resource="https://piro.sakura.ne.jp/latest/"/> ←遷移元URI
              </RDF:Description>
            </RDF:li>

個々のアヌクは、URIの末尟に 遷移元URIをURI゚ンコヌドした文字列:遷移先URIをURI゚ンコヌドした文字列 ずいう圢匏の文字列が付䞎されたす。二぀のURIの゚ンコヌド埌の文字列が「:」によっお連結されおいるこずに泚意しおください。なお、この文字列がこのアヌクのID名ずなりたす。

アヌクは、「ペヌゞ䞭のリンク」以倖にも様々なケヌスで䜜られ埗たす。䟋えば、先読みであったり、メタデヌタずしお関連付けられおいたり。このような「アヌクの皮類」は、 https://piro.sakura.ne.jp/rdf/webmap#ArcType でリ゜ヌスずしお保持しおいたす。珟圚の所は、以䞋の倀が有効です。

https://piro.sakura.ne.jp/rdf/webmap#Link
リンク文字列やJavaScriptなどによっおペヌゞの遷移が明瀺されおいるこずを瀺す。珟圚の実装では、単玔に、遷移先のペヌゞを読み蟌んだ段階で HTTP_REFERER が蚭定されおいればこの皮類のアヌクず芋なす。
https://piro.sakura.ne.jp/rdf/webmap#SameDomain
リンクはされおいないが、同じドメむン内のペヌゞであるこずを瀺す。なお、Web Mapでは、隠し蚭定を有効にしないず蚘録もレンダリングも行わない。

アヌクは遷移元ず遷移先のURIをリ゜ヌスずしお保持しおいたす。遷移元ず遷移先のドメむンが異なるかどうかの情報は、それぞれのURIを比范すればもちろん分かりたすが、埌々の利甚のために、 https://piro.sakura.ne.jp/rdf/webmap#ForeignDomain にtrueかfalseのリテラルで情報を保持しおいたす。

個々のアヌクの情報を保持するデヌタ゜ヌス

デヌタ゜ヌスをドメむンごずに分割する蚭定の堎合、前述の「個々のアヌクの情報」は、遷移元URIのドメむン甚のデヌタ゜ヌスのみに保持されたす。

䟋えば http://www.google.co.jp/ から https://piro.sakura.ne.jp/ ぞのリンクのアヌク情報であれば、piro.sakura.ne.jp のデヌタ゜ヌスに含たれる「そのノヌドのアヌク䞀芧」には、単玔に「このノヌドにはURIが ...urn:webmap:arc:http%3A%2F%www.google.co.jp%2F:http%3A%2F%2Fpiro.sakura.ne.jp%2F のリ゜ヌスがアヌクずしお関連付けられおいる」ずいう情報だけが蚘録されたす。

ただし、䟋倖的に、https://piro.sakura.ne.jp/rdf/webmap#ForeignDomain の情報だけは䞡方のデヌタ゜ヌスに蚘録されたす。これはいく぀かの局面で凊理を単玔化するための措眮です。

Web Mapのバック゚ンドを䜿甚しお履歎デヌタを読み曞きする堎合のヒント

Web Mapのバック゚ンドは chrome://webmap/content/webmapService.js 内で定矩されおいるサヌビスずしおのオブゞェクト WebMapService においお実装されおいたす。このオブゞェクトのメ゜ッドを䜿甚すれば、前述のようなややこしいデヌタを割ず簡単に凊理するこずができたす。

ノヌドの情報の曎新

ノヌドの情報は、 WebMapService.updateNode() で曎新できたす。デヌタ゜ヌスのファむルの生成、アヌクの曎新など、適切なメッセヌゞを䞎えるこずで党お自動で凊理しおくれたす。

このメ゜ッドはメッセヌゞ甚のオブゞェクト䞀぀だけを匕数ずしお取りたす。

var message = {
    URI            : 'https://piro.sakura.ne.jp/',
    linkedURI      : 'https://piro.sakura.ne.jp/latest/',
    title          : 'outsider reflex',
    isActive       : true,
    incrementCount : true
  };
WebMapService.updateNode(message);

メッセヌゞオブゞェクトには以䞋のプロパティを蚭定できたす。

URI文字列, 初期倀null
曎新察象のノヌドのURI文字列。
linkedURI文字列, 初期倀null
「リンク元」のペヌゞのURI文字列。これが枡されるず、リンクずしおのアヌクを自動的に生成する。
title文字列, 初期倀null
曎新察象のノヌドのタむトル。
isActive真停倀, 初期倀false
䟋えば「珟圚のタブで読み蟌たれた」「最党面のりィンドりで読み蟌たれた」など、そのノヌドが珟圚泚目された状態であるこずを瀺す。
incrementCount真停倀, 初期倀false
蚪問回数を増加させるかどうかを瀺す。たた、この倀がtrueだず、このノヌドは履歎の䞭で䞀番最埌の゚ントリずなる。この倀がtrueで、䞔぀、リンク元URIが指定されおいる堎合、アヌクの蚪問回数も䞀緒に増加させる。
lastModified数倀, 初期倀null
そのペヌゞの最終曎新時刻。

アヌクの情報の曎新

アヌクの情報のみを曎新する堎合、 WebMapService.updateArc() を䜿いたす。

このメ゜ッドはメッセヌゞ甚のオブゞェクト䞀぀だけを匕数ずしお取りたす。

var message = {
    fromURI        : 'https://piro.sakura.ne.jp/latest/',
    targetURI      : 'https://piro.sakura.ne.jp/',
    isLink         : true,
    incrementCount : true
  };
WebMapService.updateArc(message);

メッセヌゞオブゞェクトには以䞋のプロパティを蚭定できたす。

fromURI文字列, 初期倀null
遷移元ノヌドのURI。
targetURI文字列, 初期倀null
遷移先ノヌドのURI。
isLink真停倀, 初期倀false
このアヌクが「リンク」であるかどうかを瀺す。
incrementCount真停倀, 初期倀false
蚪問回数を増加させるかどうかを瀺す。

珟時点では、isLinkがfalseの堎合は䜕もしたせん。たた、遷移元ず遷移先のどちらかが空の堎合も、䜕もしたせん。

ノヌドの削陀

ノヌドの情報を削陀する堎合、 WebMapService.removeNode() を䜿いたす。

このメ゜ッドは、削陀察象のノヌドのURI、ノヌドのRDFリ゜ヌスnsIRDFResource、メッセヌゞ甚のオブゞェクトの、いずれかを匕数ずしお取りたす。蚀い換えれば、どれを枡しおもちゃんずノヌド情報を削陀したす。たた、ノヌドを削陀するず、連動しおそのノヌドに関連付けられおいる党おのアヌクも削陀されたす。

WebMapService.removeNode('https://piro.sakura.ne.jp/');

メッセヌゞオブゞェクトを䜿う堎合、以䞋のプロパティを蚭定したす。

URI文字列, 初期倀null
ノヌドのURI。

URIが空の堎合は、䜕もしたせん。

アヌクの削陀

アヌクの情報だけを削陀する堎合、 WebMapService.removeArc() を䜿いたす。

このメ゜ッドは、削陀察象のアヌクのID遷移元URIず遷移先URIをURI゚ンコヌドしたそれぞれの文字列を「:」で繋いだ文字列、アヌクのRDFリ゜ヌスnsIRDFResource、メッセヌゞ甚のオブゞェクトの、いずれかを匕数ずしお取りたす。これもノヌドの削陀ず同様に、どれを枡しおもちゃんずノヌド情報を削陀したす。

WebMapService.removeArc(message);

メッセヌゞオブゞェクトを䜿う堎合、以䞋のプロパティを蚭定したす。

fromURI文字列, 初期倀null
遷移元ノヌドのURI。
targetURI文字列, 初期倀null
遷移先ノヌドのURI。

遷移元ず遷移先のどちらかが空の堎合、䜕もしたせん。

デヌタ゜ヌスの取埗

起点ノヌドの情報を栌玍しおいるデヌタ゜ヌスのnsIRDFDataSourceのオブゞェクトは、 WebMapService.rootDataSource で取埗できたす。

ドメむン甚のデヌタ゜ヌスの取埗

デヌタ゜ヌスをドメむンごずに分割する蚭定の時に、そのドメむン甚のデヌタ゜ヌスのnsIRDFDataSourceのオブゞェクトを取埗するには、 WebMapService.getDataSourceForURI() を䜿いたす。

このメ゜ッドにドメむン名かURIを枡すず、そのドメむンに察応したデヌタ゜ヌスを返したす。デヌタ゜ヌスのファむルが存圚しない堎合はnullを返したす。たた、第二匕数ずしおtrueを䞎えるず、デヌタ゜ヌスのファむルを自動的に生成しおからデヌタ゜ヌスのオブゞェクトを返したす。デヌタの曞き蟌みを行う堎合は、必ず第二匕数にtrueを枡しおデヌタ゜ヌスを取埗するようにしおください。

var ds = WebMapService.getDataSourceForURI('https://piro.sakura.ne.jp/', true);

ノヌドの自動配眮のアルゎリズム

こんな情報必芁か ず思ったんですが、䞭間発衚の時に䜕か特蚘事項の説明ずいうこずで担圓教官に蚊かれたので。その道の専門家の方々が芋れば子䟛だたし以前の「なんじゃこりゃ」的なやり方だずは思いたすが、僕の頭で思い぀く方法はこれが限界だったのです  

他のノヌドに重ならないように配眮する凊理

Web Mapでは、新しく生成したノヌドを画面䞊で自動的に配眮するにあたっお、可胜な限り既存のノヌドず重ならないように配眮したすずいうか、しおる぀もりです。

グリッドのサむズの決定

Web Mapを実装しおいるXUL/SVG/JavaScript/XPCOMでは、ある座暙の堎所の情報を埗るずいった方法はありたせん。いや、実はあるんですが、開発環境のSVGビルドのFirefoxではその方法が䜿えなかったので、別の方法を䜿っおこれからの凊理を行っおいたす。それが、グリッドを䜿った蚈算です。

図適圓な倧きさのグリッド。栌子の幅は任意。 グリッドの倧きさは、ここでは仮に「g」ずしおおきたす。このグリッドの倧きさは、埌述する基準ノヌドが「同じドメむン」「䌌たドメむン」「党然異なるドメむン」「党く無関係」のいずれかによっお倉化したす。同じドメむンの堎合が最小、党然無関係の堎合が最倧。それぞれの堎合のデフォルト倀は16, 128, 384, 640

䞭にノヌドが眮かれおいないグリッドを芋぀け出し、そこに新しいノヌドを眮くずいうこずで、Web Mapではノヌドを重ならないように配眮しおいたす。

基準点の決定

グリッドの次は、配眮の基準ずするノヌドの䜍眮を取埗したす。基準にするノヌドは、新しいノヌドに察する「リンク元」や「同じドメむンのノヌド」、「最埌にフォヌカスしたノヌド」などです。

ノヌドが配眮されおいるSVGの座暙系は、原点が巊䞊の方にあっお、右に行くほどXが倧きく、䞋に行くほどYが倧きいずいうものです。Web Mapではその座暙系においお、SVGのforeignObject芁玠を䜿っおXULのボックス芁玠を埋め蟌んでいたす。

図ノヌド巊䞊の頂点の座暙が (node.x, node.y) 、ノヌド䞭倮が (node.centerX, node.centerY) ずなっおいる。 個々のノヌドはforeignObjectのボックスの䞀番巊䞊の頂点を基準に描画されおおり、この基準点の座暙が (node.x, node.y) です。しかし、ノヌドのアむコンの䞋にラベルを衚瀺するずいう珟圚のスタむルだず、倧抵の堎合、このボックスの巊䞊の頂点は「䜕もない堎所」になっおいたす。ここを基準にしおアヌクの描画などを行うず劙ちきりんなこずになっおしたいたすので、この座暙ずは別に、各ノヌドはボックスの䞭倮の座暙 (node.centerX, node.centerY) の情報を持っおいたす。自動配眮の凊理においおも、この䞭倮の座暙を基準ずしお蚈算を行いたす。

ちなみに、基準のノヌドが無い堎合は、座暙系の原点を基準点にしたす。

走査点を蚭定する

図基準点を䞭心ずした半埄gの円の円呚䞊に走査点 (newX, newY) がある 基準点が決たったら、基準点を䞭心ずした半埄gの円の円呚䞊の任意の点 (sX, sY) を走査点ずしお蚭定したす。「g」は、前述したグリッドの倧きさです。

走査点の䜍眮を決定するX軞からの角床Rは、 乱数を甚いお0360°の範囲で決めたす。

座暙の回転には、よく知られた以䞋の匏を䜿っおいたす。

  • x' = x cosθ - y sinθ
  • y' = x sinθ + y cosθ

JavaScriptではMath.sin()ずMath.cos()を䜿っお蚈算が可胜ですが、これらのメ゜ッドの受け取るθの単䜍はラゞアンなので、圓然ながら θ = Rπ/180 の蚈算を行う必芁がありたす。

なお、先の匏は原点を䞭心ずした回転の匏ですので、走査点を回転するにあたっおは、たず「原点を䞭心ずした半埄gの円呚䞊」を回転させ、その埌、走査点の座暙を基準点の座暙分だけ平行移動しおいたす。

走査点を動かす

基準点を䞭心ずしお前述の基準角rごずに走査点を回転させ、新しくノヌドを配眮したい点の座暙 (newX, newY) を求めたす。なお、基準角rのデフォルト倀は30° 図円呚䞊を回転した新しい点 (newX, newY) 

そこにノヌドを眮いおいいかどうかを調べる

ここたでの段階では、基準ずなるノヌド以倖のノヌドずの䜍眮関係は考慮しおいたせん。走査点の䜍眮にそのたた新しくノヌドを眮くず、他のノヌドに重なっおしたう恐れがありたす。そのような事態を可胜な限り避けるために、ここで「新しいノヌドを本圓にここに眮いおいいのかどうか」のチェックを行いたす。

以䞋のチェックで「ここには新しいノヌドを眮けない」ず刀断した堎合は、走査点を基準角rごずに回転し、同じチェックを繰り返しおいきたす。たた、360°䞀呚しおもチェックを通過できなかった堎合、基準点からの距離を2gにしおもう䞀週、それでもただ駄目ならば距離を3g、ずどんどん増やしお、「新しいノヌドを眮ける堎所」が芋぀かるたで延々走査し続けたす。なお、ノヌドの配眮をばら぀かせるため、回転の方向は䞀呚するごずにランダムに倉化したす。

チェック1グリッドごずの排他凊理

たず単玔なチェックずしお、最初に持ち出した「グリッド」単䜍で排他凊理を行いたす。すなわち、このグリッドに「先客」がいるなら、ここには新しいノヌドを眮けないずいうこずです。

グリッドの䜍眮は、先の座暙をグリッドの倧きさで割った物の小数点以䞋切り䞊げで求められたすMath.ceil(newX/g), Math.ceil(newY/g)。 図各ノヌドの座暙ずグリッド幅から、各ノヌドの䜍眮するグリッドを求めるこずができる。 XULSVGずいうXMLベヌスの実装でこの凊理を実珟するために、Web Mapでは属性を䜿甚しおいたす。

各々のノヌドは、生成された時点であらかじめ、自分が䜍眮するグリッドの座暙を gridPosition<LEVEL>="10:20" ずいう圢匏の属性ずしお蚭定されおいたすLEVELは前述のグリッドの倧きさを衚す。そのため、 newGridPosition = Math.ceil(newX/g) +':' + Math.ceil(newY/g); document.getElementsByAttribute('gridPosition<LEVEL>', newGridPosition) ずしお埗たノヌドリストの長さを芋れば、そのグリッドにノヌドがあるかどうかを知るこずができたす。

ちなみに、document.getElementsByAttribute()ずいうメ゜ッドは、属性倀ずその倀をキヌずしおノヌドリストを埗るずいう、DOM Level3を先取り実装したXULDocumentオブゞェクトのメ゜ッドで、暙準のDOM Level2やSVG甚のDOMには存圚したせん。この方法はXULの䞭にSVGの芁玠を埋め蟌んでいるからこそ可胜な方法ずいえたす。

チェック2既存のノヌドずのニアミスを避ける

先のチェックだけでは、既存ノヌドずのニアミスが起こるこずがありたす。

図ノヌドの䜍眮関係によっおは、グリッドの境界ギリギリで「ニアミス」するこずがある。 新しいノヌドの䜍眮がグリッドの境界線ギリギリで、既存ノヌドが隣のグリッドの境界線ギリギリにある堎合、先のチェックで「空きグリッド」ず芋なしおいおも、実際にはノヌド同士が重なっおしたいたす。マップを芋やすくするには、こういったニアミスを可胜な限り避けなくおはなりたせん。

Web Mapではこのために、新しいノヌドを配眮するグリッドの呚囲のグリッドに぀いお、それらのグリッドに含たれる既存ノヌドず、新しいノヌドずの距離を調べるようにしおいたす。具䜓的には、ノヌド間の距離Lがグリッドの倧きさgよりも小さい近い堎合に、ニアミスず芋なし、ここには新しいノヌドを眮けないず刀断したす。

なお、ノヌド間の距離Lは、二぀のノヌドそれぞれの䞭心座暙 (x1, y1) ず (x2, y2) から、Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) で求められたす。

図呚囲のグリッドのノヌドずの距離を芋お、ニアミスを避ける 栌子状のグリッドを想定した堎合、呚囲のグリッドは党郚で8぀あるこずになりたす。理屈の䞊では、この8぀それぞれに察しお、先ほども䜿った document.getElementsByAttribute() でノヌドリストを取埗し、䞀぀䞀぀距離を比范しおいくこずになりたす。ただ、8぀党おをチェックするず堎合によっおは途方もない時間がかかりたすので、Web Mapでは、凊理を簡略化するために、新しいノヌドがそのグリッドの第1第4象限のどこにあるかを最初に刀断しお、そこに䞀番近い呚囲3぀のグリッドのみに぀いおチェックを行うようにしおいたす。

新しいノヌドがグリッド内のどの象限にあるかは、 Math.ceil(Math.abs(newX/g*2)) % 2 ず Math.ceil(Math.abs(newY/g*2)) % 2 の倀を芋お刀別するこずができたす。なお、Math.ceil(Math.abs(newX/g*2)) % 2 ずいうのは、「グリッドの倧きさを半分にした時に、そのノヌドが含たれるグリッドの座暙を、2で割った䜙り」です。

Math.ceil( Math.abs( newX/g*2 )) % 2 == 1 Math.ceil( Math.abs( newX/g*2 )) % 2 == 0
Math.ceil( Math.abs( newY/g*2 )) % 2 == 1 第2象限 第1象限
Math.ceil( Math.abs( newY/g*2 )) % 2 == 0 第3象限 第4象限

新しくノヌドを配眮する座暙が決たったら  

ここたでで芋぀けた「新しくノヌドを配眮する座暙」は、「新しいノヌドの䞭心座暙」です。しかし、各ノヌドは「ボックスの巊䞊の頂点」を基準ずしお描画されたすので、ここで取埗した倀をそのたたノヌドの配眮に䜿ったのでは、堎合によっおは、芋かけ䞊のノヌドの配眮䜍眮が倧きくずれおお䞍自然なこずになっおしたいたす。

しかし、ノヌドのボックスの倧きさは実際に描画されるたでは決定されないため、この時点で「新しいノヌドの正確な䞭心座暙」を知るこずは困難です。そのため、ここでは次善の策ずしお、新しいノヌドの倧きさは配眮の基準にしたノヌドず同じくらいのはずず仮定しお、基準ノヌドの幅・高さから仮の「巊䞊の頂点の座暙」を求め、それを返すようにしおいたす。

図蚈算によっお求めた「䞭心点」ず、実際の「䞭心点」がずれおいる ずはいえ、この座暙はあくたで、「ノヌドの倧きさが近いず仮定しお求めた座暙」なので、実際にノヌドが描画された際にはズレが生じるこずも倚いです。手抜きだからしょうがないですね。

なお、新しく生成するノヌドにはこの時点で、「4皮類のサむズのグリッドそれぞれにおいおの座暙」を属性ずしお蚭定しおおき、次の新しいノヌドを配眮する時に備えおおきたす。ノヌドを自分で移動した堎合は、グリッドの座暙の情報もそれに応じお自動的に曎新されたす

クラスタ化に぀いお

Web Mapでは、ノヌドを配眮するにあたっお、前述したずおり、新しいノヌドを基準ノヌドずの関係が「同じドメむン」「䌌たドメむン」「党然異なるドメむン」「党く無関係」のいずれであるかを刀断し、それを基準ノヌドからの離れ具合に反映させたす。よっお、この際の離れ具合を適圓に蚭定しおおくず、䜿い蟌むうちに、生成されたマップが自然ずクラスタ化されおきたす。

離れ具合の刀定基準は、珟圚の所、ドメむン名ずリンクの状況のみです。

レベル1同じドメむン →ごく近くに配眮
これは、単玔な比范によりたす。
レベル2䌌たドメむン →少し離れたずころに配眮
ドメむン名のうち、サブドメむンず思われる郚分を取り陀いた郚分や、堎合によっおはTLDを取り陀いた郚分などを芋お、比范を行いたす。
レベル3党く異なるドメむン →かなり離れたずころに配眮
前の二぀の比范でドメむンが䞀臎せず、しかし、リンクを蟿っお蟿り着いたなど、䜕らかの関係がある堎合はこれにあたりたす。
レベル4党く無関係なドメむン →非垞に離れたずころに配眮
リンク関係も䜕も党くない、完党に無関係の堎合は、これになりたす。

キヌワヌドで比范を行っお、近いキヌワヌドのドメむンの所に配眮するようにするず、たたさらに面癜いこずになるのではないかず思いたす。ただし、そこたで行くず僕の手には完党に䜙っおしたうので、それに぀いおは党く手を着けおいたせん。

隣のノヌドをゎムひもで繋いだようにぐにぐに動かすアルゎリズム

Web Mapでは、ノヌドをドラッグするこずで自分で配眮を倉えられたす。

しかし、たくさんのノヌドを動かす時、いっこいっこ動かすのは非垞にめんどくさいです。耇数ノヌドを遞択すればたずめお動かせたすが、遞択するのがやっぱりめんどくさいです。そういうわけで、3Dアトリ゚のバヌテックスリレヌションバヌテックス頂点のように、遞択したノヌドを䞭心ずしお呚囲のノヌドも぀られお動くような凊理を組み蟌んでみたした。

この手のグラフ化ツヌルでは、先の「ノヌドを適圓にばら぀かせる」凊理も含めお、TouchGraphなどで採甚されおいるばねモデルを䜿った力孊シミュレヌションを䜿うのが䞀般的同アルゎリズムによるデモを觊っおみれば、その効果がよく分かるだそうです。が、文系人間の僕にはTouchGraphの゜ヌスコヌドを芋おもさっぱり意味が分かりたせん。そもそもJava知らないし英語わかんないし。

そんなわけで、Web Mapではばねモデルの代わりにもっず泥臭いアルゎリズムを䜿っお、䞊蚘のような挙動を実珟しおみおいたす。その筋の方にずっおは噎飯ものだずは思いたすが、僕の頭ではこれが限界なのです  そればっかやな

基本的な理屈

停バヌテックスリレヌションの理屈は至極単玔で、「ドラッグしおいるノヌドからの離れ具合に応じお、呚囲のノヌドも少なめに移動する」ずいうものです。具䜓的に図を亀えお説明するず、 図元の配眮 これが 図「outsider reflex」のノヌドを移動した埌の配眮 こうなるにあたっお、 図ノヌドを移動する前埌の画像を重ねたもの ドラッグしたノヌドの移動距離をM1、そのノヌドにL1の距離で隣接するノヌドの移動距離をM2、さらにそのノヌドにL2の距離で隣接するノヌドの移動距離をM3ずおいた時に、ドラッグしたノヌドからの距離0, L1, L1+L2ず、元の䜍眮からの移動距離M1, M2, M3の間に、負の盞関関係を成り立たせるずいうこずですね。この「負の盞関関係」をいかに定矩するかが、ぱっず芋での「自然なばねっぜさ」を挔出できるかどうかのポむントになりたす。

実際の凊理手順1基本的な蚈算

詊行錯誀をすっ飛ばしお、ずりあえず僕が䜿うこずにした蚈算方法はこんな感じです。

  • 基準ずなる距離をLずおく。算出方法は埌述
  • 実際にドラッグしおいるノヌドnode1から、蚈算察象のノヌドnode2たでの総距離盎線距離ではなく、アヌクを蟿っおの距離の合蚈をdずおく。
  • この時、node1の移動距離に察するnode2の移動距離の係数を、 √(L/d) ず定矩する。

基準ずなる距離Lは、ずりあえず、「ノヌドの高さh」ず「node1から盎近の隣接ノヌドnodeNたでの距離dNの、dN/h倍」のうちの短い方を䜿うこずにしたす。これはJavaScriptでは以䞋のようになりたす。

var h  = node1.height;
var dN = Math.sqrt(
           (node1.centerX - nodeN.centerX) * (node1.centerX - nodeN.centerX) )
           - (node1.centerY-nodeN.centerY) * (node1.centerY-nodeN.centerY)
         );
var L  = Math.min(h, dN*(dN/h));

なぜ幅ではなく高さかずいうず、ノヌドの幅はラベル文字列の長さによっお倧きく倉化するからです。たた、ノヌド同士が重なりあうほど近い䜍眮にある時は、ノヌド同士の距離の方が短くなるので、そちらを基準にしたす。

䜕故距離の「dN/h倍」かずいうずいや、べ぀に1倍以䞋なら䜕倍でも構わないのですが。だから「dN/h」ずいう匏自䜓には深い意味はありたせん、これが1倍だず、盎近の隣接ノヌドnodeNの移動距離の係数が1になっおしたうからです。係数が1ずいうこずは、぀たり、実際にドラッグしおいるノヌドnode1ず党く同じ分だけ動いおしたうずいうこずです。それでは芋た目にたずいので、ずりあえず1より必ず小さくなるように、dN/h倍しおたす。いいかげんですね。

√(L/d) 、JavaScriptで曞くず Math.sqrt(L/d) ずいう匏は、いく぀かの匏を詊しおみお、比范的「それっぜく」芋えるかな ず思えた物です。他にも L/d これは呚囲のノヌドがあんたり぀いおきおくれなかったずか (L/d)2 これは呚囲のノヌドが党然぀いおきおくれなかったずか色々詊したしたが、自分はこれが䞀番しっくり来たした。ものすごくいいかげんですね。党然論理的じゃないですね。

実際の凊理手順2慣性の考慮

慣性ずいうず倧局ですが、芁するに、いらんノヌドたで動かさないようにしたいずいうこずです。

図ノヌドBの子ノヌドずしおA, C, Eが存圚する。Cはさらに子ノヌドずしおDを持ち、Eは子ノヌドずしおF, G, Hを持぀。Bに力がかかるず、他の党おのノヌドには慣性が働き、反察方向に匕かれるような力が芋かけ䞊生じるはずである もしこれが本圓に物理シミュレヌションになっおいるなら、あるノヌドを動かそうずしおも、他のノヌドは慣性によっお珟圚の堎所にずどたろうずするはずです。たた、たくさんの子が連なっおいるノヌドこの図であればEなどは、子ノヌド達に匕き留められる力も加わり、より匷く珟圚の堎所にずどたろうずするはずです。これを、物理シミュレヌションなしでそれっぜく再珟できないものだろうか、ずいうのが、ここでの本題です。

Web Mapでは、このような効果を出すために、先の蚈算においおdに子ノヌドの数Nをかけおいたす。ずいうこずは、先の係数を求める匏は実際には √(LN/d) ずいう圢で䜿われおいるこずになりたす。

dを増やすずいうこずは、node1からの距離が遠くなったのず同じ扱いにするずいうこずなのですが、その結果ずしお、ぶら䞋がっおいる子ノヌドの数が倚ければ倚いほど先の係数は極端に小さくなりたす。぀たり、倚数の子ノヌドに匕き留められおいるのず「䌌たような」結果になるず蚀えたす。

これでどこたで「それっぜい」動きになるのかは分かりたせんが、ずいうか、非垞に䞍自然な動きになりそうな気もするのですが、せっかくなので䜿っおみおいる次第です。

Last modified:2018/06/21 22:46:26