2020/09,江端さんの忘備録,江端さんの技術メモ

私が今使っているWordPressは、現時点での最新バージョンなのですが、どうしても、Prism For WPのメニューが出てこなくて、ずっと悩んでいました。

で、色々しらべた結果、

をインストールする必要があるらしく、これを入れることでメニューがでるようになりました。

が今度は、画像イメージのコピペができなくなりました。

で、さらに、

をインストールして、この画面のようにコピペを張りつけるように戻すことができるようになりました。

なんか、やりたいことを実現していくと、どんどんWordPressのダウングレードをしているような気になってきました(プラグインもどんどん入れることになって、気持ち悪いです(経験上、プラグインの入れすぎは、トラブルの元になります))。

 

2020/09,江端さんの技術メモ

常日頃から御指導頂いているSさんから、Bad Elf 2300の位置情報をキャプチャするhtmlファイルの内容を教えて頂いた。忘れないように、残しておく。
Bad ElfをBTでリンクしたiPadで稼働を確認済み(iPhoneでは稼働確認できなかった)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>geolocation-sample</title>
</head>
<body>
  <div id="output"></div>
 
<script>
    var output = document.getElementById('output');
 
    // 位置情報の取得に成功した際のコールバック
    const successCallback = (position) => {
        console.log(position);
		output.innerHTML += "<P>==========";
		output.innerHTML += "<P>time:" + position.timestamp;
		output.innerHTML += "<P>latitude:" + position.coords.latitude;
		output.innerHTML += "<P>longitude:" + position.coords.longitude;
		output.innerHTML += "<P>altitude:" + position.coords.altitude;
		output.innerHTML += "<P>accuracy:" + position.coords.accuracy;
		output.innerHTML += "<P>altitudeAccuracy:" + position.coords.altitudeAccuracy;
		output.innerHTML += "<P>heading:" + position.coords.heading;	
		output.innerHTML += "<P>speed:" + position.coords.speeed;	
    };
 
    // 位置情報の取得に失敗した際のコールバック
    const errorCallback = (err) => {
        console.log(err);
		output.innerHTML += "Error\n";		
    };
 
    // 位置を監視する構成オプション
    // オプションの内容は次のリンクに書かれています。
    // https://developer.mozilla.org/ja/docs/Web/API/PositionOptions
    const options = {
        enableHighAccuracy: true,
        timeout: 5000,
        maximumAge: 0
    };
 
    let watchPositionID;
 
    window.onload = () => {
        // navigator.geolocation.watchPositionについては次のURLにかかれています。
        // https://developer.mozilla.org/ja/docs/Web/API/Geolocation/watchPosition
        watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
    };
 
    // ブラウザーを閉じる前に位置の監視を止めます
    window.onbeforeunload = () => {
        navigator.geolocation.clearWatch(watchPositionID);
    }
</script>
</body>
</html>

2020/09,江端さんの忘備録,江端さんの技術メモ

このコンテンツはパスワードで保護されています。閲覧するには以下にパスワードを入力してください。

2020/09,江端さんの忘備録,江端さんの技術メモ

ChromeにAdd-onを追加

ChromウェブストアのMarkdown Preview Plusのページを開きます
https://chrome.google.com/webstore/detail/markdown-preview-plus/febilkbfcbhebfnokafefeacimjdckgl?hl=ja

[Chromeに追加]ボタンをクリックします

と、ここまではいいんだけど、次をやらないと表示しない

chrome://extensions/

から、

から「詳細」を選び

をアクティブにするのが重要。

さらに、WordPressでは、エディタ「Gutenberg」を入れると、最初からMarkdownが使える

なかなか便利です。

以上

2020/09,江端さんの技術メモ

ここのところ、Websocket通信のセキュア化のコーディングで、かなり嵌ってしまっている私に、師匠のSさんから、

GoのサーバーでWSSやHTTPSのプロトコルを直接扱うことをせず、かわりに、リバースプロキシサーバーでHTTPSやWSSプロトコルを扱い、GoのサーバーではHTTPやWSプロトコルを扱うように構成を変更する、というのはいかがでしょうか?

とのご提言を頂きました。

あ、そりゃそうだ ―― と思いました。私は、Websocket通信のアタックさえ回避できれば、なんでも良いわけでして、何がなんでもwssをやりたい訳ではありません。

インターネットの中でセキュアが担保できれば、内部システムなんぞスカスカでも構いません(そもそも、システム内部に侵入されたら、その時点で"システムとしては、"The END"です)。

とりあえずPC(Windows10 Box)の中でnginx(Webサーバ)を立てようと思いました。

いや、驚くほど簡単。「インストールから実行まで10秒を切ったWebサーバ」というのは生まれて始めてかもしれません。

http://nginx.org/en/download.html から、Stable versionをダウンロードして、

解凍して、"nginx.exe"を叩くだけ。(私の場合、ダウンロードの場所は、C:\の直下にしておきました)

これで、ブラウザから、http://localhost と入力して稼動確認

ちなみに、トップページは、htmlフォルダの中にあるので、適当に変更すれば、普通のWebサーバにもなります。

それはさておき。

今回の場合、クライアントからnginxまでのセキュアが確保できれば足り、その後ろは、普通のwebsocketの通信ができれば良い、とします(golangでwebsocketのセキュア通信って、もう気が狂いそうになるほど面倒)。

Sさんからは、nginx.confを送付して貰ったのですが、まあ、当然ですが、一発では動きませんでしたので、先ず、セキュア通信なしのリバースプロキシを動かしてみます。

nginxでポート8000で受けて、それを、エコーサーバ(8080)に転送するだけのものですが、NginxのリバースプロキシでWebソケットを通す際の設定 とSさんから送って頂いた設定ファイルを参考にさせて頂いて、以下のようにconf/nginx.confの内容を書き換えました。

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    map $http_upgrade $connection_upgrade { 
        default upgrade;    
        ''      close;
    } 

    server {
        listen 8000;
        server_name localhost;

        location / {
            proxy_pass   http://localhost:8080;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Frame-Options SAMEORIGIN;

            proxy_read_timeout 86400;

        }
    }
}

ちなみにエコーサーバは、以下のものをそのまま使っています。

でもって、こんな感じでちゃんと動いています。もちろんlocalhost:8080でも動きます。

ーーーー

では、ここから、ngnixまでのセキュア化の検討を開始します。

ここでしばしスタック中。TLSがちゃんと動いているのか不安になったので、普通のWebでできるか、以下のようなnginx.confを使って、index.htmlで試してみました。

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    server {
        listen       443;
        server_name  localhost;

        ssl                  on;
        ssl_certificate      algo.crt; # https://wp.kobore.net/2020/09/post-1124/で作ったもの
        ssl_certificate_key  algo.key; # 同上

        location / {
            root html;
            index index.html index.htm;
        }
    }
}  

https://localhost/ でも、http://localhost/ でも動いていますので、algo.crt, algo.keyについては(多分)大丈夫だと思われます。

では、元の問題に戻りましょう。(4時間格闘)

どうやら、外向けをセキュアにするには、nginx.confを3箇所だけ変更追加すれば良い、と記載されていたので、以下のようなnginx.confに改造した “#change"と、"#add"のところだけ。

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    map $http_upgrade $connection_upgrade { 
        default upgrade;    
        ''      close;
    } 

    server {
        #listen 8000;
        listen 443 ssl;  # change

        server_name localhost;

        ssl_certificate algo.crt; #add
        ssl_certificate_key algo.key; #add



        location / {
            proxy_pass   http://localhost:8080;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Frame-Options SAMEORIGIN;

            proxy_read_timeout 86400;

        }
    }
}

ところが、https://localhost を実施しても、サーバ側から、以下のエラーがでてきて、どうにもならない。

upgrade:websocket: the client is not using the websocket protocol: 'websocket’ token not found in 'Upgrade’ header

Visual Studio Codeにかけて、サーバでトレースしても読めないし(htmlの部分だから無理ない)、正直もうどうして良いか分からなくなってきたとき、「あ、chromoのディベロッパーツールを使えばいいか」と気が付きました。

そんでもって、

これで気がつきました。ここって"ws:"ではなくて、"wss:"にしないとアカンのじゃないかな、と。

で、ここを修正して、ECHOサーバを立ち上げ直したら、無事稼動することが確認できました。

まあ、まだまだ課題山積ですが、とりあえず、家(システム)の外はセキュアにする目処が立ちましたので、wssの通信プログラムで苦労するのは「やめる方向」で決定しました。

nginxをリバースプロキシにして、そこまではガチガチにしておき、家の中はユルユルに作るで、進めていくことにします。

以上

2020/09,江端さんの技術メモ

$ git clone https://github.com/GuyBrand/WssSample

で取ってきた、コードで、色々調べている。

サーバは、以下で起動。

クアイアントは、

で起動(に失敗)

以下、色々ごそごそやってみる。

ちなみに、getCrtホルダは、証明鍵を作るプログラムのようす
C:\Users\ebata\WssSample\genCrt>ls
genCrt.go new.crt new.key

C:\Users\ebata\WssSample\goClient>curl localhost:9200
Client sent an HTTP request to an HTTPS server.

C:\Users\ebata\WssSample\goClient>curl https://localhost:9200
curl: (77) schannel: next InitializeSecurityContext failed: SEC_E_UNTRUSTED_ROOT (0x80090325) – 信頼されていない機関によって証明書チェーンが発行されました。

「信頼されていない機関」って「私」か。そりゃそうだが。

うーん、では、curlコマンドを使ってHTTPSのAPIを叩く と 、SSL通信時発生する証明書エラーとその仕組みを理解する を参考にして、

C:\Users\ebata\WssSample\goClient>curl -k https://localhost:9200

を実行。

色々でてきた。ということは、サーバとしては機能しているようです。

とは言え、

は、解決されていないです。

そもそも、私、SSLの仕組み、きちんと理解できていると思っていません(だからAWSのhttps化で地獄を見ることになった)。今回、イケメンとラブレターで学ぶSSLの仕組み で、なんとか分かったような気になりました。

C:\Users\ebata\WssSample\server の中に入っている、algo.crt を叩いてみたら、

が出てきました。インストールして良いものかどうか迷いましたが、(有効期間内だったようだし)「証明証のインストール」のボタンを押してみました。

よく分かりませんが、言われるがまま(にボタンを押していきました。

そんでもって、サーバ側からは、C:\Users\ebata\WssSample\server>go run main.go hub.go conn.go クライアント側には、C:\Users\ebata\WssSample\goClient>go run goClient.go conn.go hub.go を入力しましたが ―― うん、症状改善なし、でした。

一応ブラウザから https://localhost:9200 を押下したみたのですが、

こんな感じですねえ。サーバのエラー表示はこんな感じです。

「詳細設定」ボタンを押して、「localhost にアクセスする(安全ではありません)」を押下すると、一応動きます。

この画面2枚上げると、表示が連動しているのが分かります。

Windows10の環境設定画面から、以下のような設定もやってみたけどダメでした(ので消しました(別の問題を引き起こしそうだったので))

(一時休憩)

現在勉強中のページ

MacでGolangでhttpdでTLSでLet’s Encryptを使ってみた。

ここで困っていたら、普段からご教示して頂いているSさんから「mkcertを使ってみたら」というアドバイスを頂きました。で、get clone https://github.com/FiloSottile/mkcert.git などもやってみたのですが、ソースコードしか入っていなくて、このコンパイル方法も良く分かりませんでした。

https://github.com/FiloSottile/mkcertを除いてみたら、バイナリがダウンロードできそうことが分かりました。

でもって、ここから、Windows10で使えそうなバイナリをダウンロードしました。

ダウンロードしたところから、直接叩いてみたら、C:\Users\Ebata\AppData\Local\mkcert の中に、鍵ができていましたが、最初に、mkcer -installしろ、と言われています。

本当はmkcertにリネームした方が良いのでしょうが、面倒なので、そのまま mkcert-v1.4.1-windows-amd64.exe -install でセットしました。

その後、mkcert-v1.4.1-windows-amd64.exe localhost 127.0.0.1 と入力すると、"localhost" と “127.0.0.1"を含む鍵が、カレントディレクトリにできるようです。

で、"localhost+1-key.pem"を “algo.key"とリネームして、"localhost+1.pem"を"algo.crt"とリネームして、C:\Users\ebata\WssSample\serverに放り込む。

C:\Users\ebata\WssSample\server>go run main.go conn.go hub.go
file algo.crt found switching to https

とこの状態で、ブラウザから、https://localhost:9200を入力

おお! 警告が出なくなった!!! サーバはちゃんと動いているみたい。

では、クライアントのプログラムも・・・

画像に alt 属性が指定されていません。ファイル名: image-28.png

うん、こっちはダメだな。

    ws, _, err := websocket.NewClient(c, u, wsHeaders, 1024, 1024)
    if err != nil {
            fmt.Println(err.Error())
            return
    }

トレースで、このNewClient()でエラーが出ているのは分かっているんですが、この原因は分かりません。

クライアント側のコードでは、鍵の読み込みをしていないようです。

ちなみに、WssSample/gemCrt に鍵を生成するプログラムが入っていますが、これで作った鍵では、httpsの認証問題をクリアできませんでしたので、素直に「mkcertを使ってみたら」と申し上げます。

(もう一度チャレンジしますが今日は▽ここまで)。

2020/09,江端さんの技術メモ

Freemindのノード(orセル?)の表示欄を長くしたくて、これまで色々奮闘してきましたが、上手くいっておりません。

上記の赤い円でくくった部分を、3倍程度の長さにしたいのです。

「長文編集(alt+Return)」を使えば? という指摘はもっともなのですが、画面を移動させるきに、思考が一瞬停止する煩わしさが嫌いで、「長文編集(alt+Return)」を使わずになんとかしたいのです。

この不便さを理解して貰うのは難しのですが、私は、SKKIMEという特殊なIMEを使っています。SKKIMEでは、漢字変換中の文字が、このノードの終端にくると表示されなくなり、文章が書けなくなるのです。

見落している設定があるのかもしれないと期待していますが、もしダメなら諦めて、他のMindMapツールを探そうと思っています。

私、10年以上も、MindManagerを使ってきたのですが、古いバージョンがWindowsのバージョンでは動かなくなって、Freemindに乗り換えた、という経緯があります(加えて、MindManagerは、私が必要としない機能が満載で、高価で、もう個人では手がでません)。

私の場合、「MindMapでコラムを執筆する」という特殊な使い方をしていますので、Mindmapの本来の思想(単語レベルでの入力)と外れていることは分かっています。しかし、Freemindを使い続けられるのであれば、大変助かります。

ちなみに、わずかではありますが、「ソースコードレベルの改造」も視野に入れていますので、その点からアドバイスを頂けても大変助かります。

何卒、お助け頂けますよう、お願い申し上げます。

お手数ですが、ご連絡先は、こちらをご利用頂ければ幸甚と存じます。

http://kobore.net/mailAddress.gif

2020/09,江端さんの技術メモ

AnacondaとJupyter notebookのインストール

https://www.anaconda.com/download/

http://jupyter.org/ をインストールしておく。

Anaconda Prompt(anaconda3)を起動

>pip install qiskitでライブラリをインストールする

>conda listで qiskitがインストールされているかを確認できる。

つぎにAnaconda Nabigation(anaconda3)を起動する

Juypyter Notebook(anaconda3)

python3の入力環境を立ち上げる

で、こんな感じで入力する。

取り敢えず、ここまで(直ぐに忘れるのでメモ)

2020/09,江端さんの技術メモ

以下、https://github.com/SINTEF-9012/PruneCluster の簡単な翻訳

PruneCluster is a fast and realtime marker clustering library.
PruneClusterは、高速でリアルタイムなマーカークラスタリングライブラリです。

Example 1: 150 000 randomly moving markers.
例1:150,000個のマーカーをランダムに移動させる。

 Example 2: Realtime clusters of tweets.
例2. リアルタイムでツイートのクラスターを作成します。

It’s working with Leaflet as an alternative to Leaflet.markercluster.
Leaflet.markerclusterの代替としてLeafletと連携しています。

The library is designed for large datasets or live situations. The memory consumption is kept low and the library is fast on mobile devices, thanks to a new algorithm inspired by collision detection in physical engines.
このライブラリは、大規模なデータセットやライブの状況を想定して設計されています。物理エンジンの衝突検出にヒントを得た新しいアルゴリズムを採用しているため、メモリ消費量は低く抑えられており、ライブラリはモバイルデバイス上で高速に動作します。

Features
特徴

Realtime
リアルタイム

The clusters can be updated in realtime. It’s perfect for live datasets or datasets you want to filter at runtime.
クラスターをリアルタイムで更新することができます。ライブデータセットや、実行時にフィルタリングしたいデータセットに最適です。

Fast
高速化

Number of markers
マーカーの数
First step
最初のステップ
Update (low zoom level)
更新(低倍率)
Update (high zoom level)
更新(高倍率)
100instantinstantinstant
1 000instantinstantinstant
10 00014ms3ms2ms
60 00070ms23ms9ms
150 000220ms60ms20ms
1 000 0001.9s400ms135ms

These values are tested with random positions, on a recent laptop, using Chrome 38. One half of markers is moving randomly and the other half is static. It is also fast enough for mobile devices.
これらの値は、最近のノートパソコンで、Chrome 38を使用して、ランダムな位置でテストされています。マーカーの半分はランダムに動き、残りの半分は静止しています。モバイル端末でも十分に高速です。

If you prefer real world data, the 50k Leaflet.markercluster example is computed in 60ms (original).
実世界のデータをお望みなら、50k Leaflet.markercluster の例は 60ms (オリジナル) で計算されています。

Weight
ウエイト

You can specify the weight of each marker.
各マーカーのウエイトを指定することができます。

For example, you may want to add more importance to a marker representing an incident, than a marker representing a tweet.
例えば、ツイートを表すマーカーよりも、事件を表すマーカーの方がウエイトが高い場合があります。

Categories
カテゴリ

You can specify a category for the markers. Then a small object representing the number of markers for each category is attached to the clusters. This way, you can create cluster icons adapted to their content.
マーカーのカテゴリを指定することができます。そして、各カテゴリのマーカーの数を表す小さなオブジェクトがクラスタに添付されます。このようにして、その内容に合わせたクラスタアイコンを作成することができます。

Dynamic cluster size
動的なクラスタサイズ

The size of a cluster can be adjusted on the fly (Example)
クラスターの大きさをその場で調整可能(例)

Filtering
フィルタリング

The markers can be filtered easily with no performance cost.
性能コストをかけずに、簡単にマーカーをろ過することができます。

Usage
使用方法

Classic Way
古典的な方法

	<!-- In <head> -->
	<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
  integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
  crossorigin=""/>

	<!-- In <head> or before </body> -->
	<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"
  integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
  crossorigin=""></script>
	<script src="PruneCluster/dist/PruneCluster.js"></script>

Webpack & NPM

npm install exports-loader prunecluster

import { PruneCluster, PruneClusterForLeaflet } from 'exports-loader?PruneCluster,PruneClusterForLeaflet!prunecluster/dist/PruneCluster.js'

Example

var pruneCluster = new PruneClusterForLeaflet();

...
var marker = new PruneCluster.Marker(59.8717, 11.1909);
pruneCluster.RegisterMarker(marker);
...

leafletMap.addLayer(pruneCluster);

PruneClusterForLeaflet constructor

PruneClusterForLeaflet([size](#set-the-clustering-size), margin);

You can specify the size and margin which affect when your clusters and markers will be merged.
クラスターとマーカーがマージされるときに影響するサイズとマージンを指定できます。

size defaults to 120 and margin to 20.
サイズはデフォルトで120、マージンは20に設定されています。

Update a position
ポジションの更新

marker.Move(lat, lng);

Deletions
削除

// Remove all the markers
pruneCluster.RemoveMarkers();

// Remove a list of markers
pruneCluster.RemoveMarkers([markerA,markerB,...]);

Set the category
カテゴリを設定する

The category can be a number or a string, but in order to minimize the performance cost, it is recommended to use numbers between 0 and 7.
カテゴリは数字でも文字列でも構いませんが、パフォーマンスコストを最小限に抑えるために、0~7の間の数字を使用することをお勧めします。

marker.category = 5;

Set the weight
ウエイトを設定する

marker.weight = 4;

Filtering
フィルタリング

marker.filtered = true|false;

Set the clustering size
クラスタリングサイズを設定する

You can specify a number indicating the area of the cluster. Higher number means more markers “merged". (Example)
クラスタの領域を示す数値を指定することができます。数値が大きいほど、より多くのマーカーが “マージ “されていることを意味します。(例)

pruneCluster.Cluster.Size = 87;

Apply the changes
変更を適用する

Must be called when ANY changes are made.
変更が行われたときに呼び出されなければなりません。

pruneCluster.ProcessView();

Add custom data to marker object
マーカーオブジェクトにカスタムデータを追加

Each marker has a data object where you can specify your data.
各マーカーには、データを指定できるデータオブジェクトがあります。

marker.data.name = 'Roger';
marker.data.ID = '76ez';

Setting up a Leaflet icon or a Leaflet popup
リーフレットアイコンやリーフレットのポップアップを設定する

You can attach to the markers an icon object and a popup content
マーカーにはアイコンオブジェクトとポップアップコンテンツを添付することができます。

marker.data.icon = L.icon(...);  // See http://leafletjs.com/reference.html#icon
marker.data.popup = 'Popup content';

Faster leaflet icons
より高速なリーフレットアイコン

If you have a lot of markers, you can create the icons and popups on the fly in order to improve their performance.
マーカーが多い場合は、その場でアイコンやポップアップを作成しておくとパフォーマンスが向上します。

function createIcon(data, category) {
    return L.icon(...);
}

...

marker.data.icon = createIcon;

You can also override the PreapareLeafletMarker method. You can apply listeners to the markers here.
PreapareLeafletMarkerメソッドをオーバーライドすることもできます。ここではマーカーにリスナーを適用することができます。

pruneCluster.PrepareLeafletMarker = function(leafletMarker, data) {
    leafletMarker.setIcon(/*... */); // See http://leafletjs.com/reference.html#icon
    //listeners can be applied to markers in this function
    leafletMarker.on('click', function(){
    //do click event logic here
    });
    // A popup can already be attached to the marker
    // bindPopup can override it, but it's faster to update the content instead
    if (leafletMarker.getPopup()) {
        leafletMarker.setPopupContent(data.name);
    } else {
        leafletMarker.bindPopup(data.name);
    }
};

Setting up a custom cluster icon
カスタム クラスター アイコンの設定

pruneCluster.BuildLeafletClusterIcon = function(cluster) {
    var population = cluster.population, // the number of markers inside the cluster
        stats = cluster.stats; // if you have categories on your markers

    // If you want list of markers inside the cluster
    // (you must enable the option using PruneCluster.Cluster.ENABLE_MARKERS_LIST = true)
    var markers = cluster.GetClusterMarkers() 
        
    ...
    
    return icon; // L.Icon object (See http://leafletjs.com/reference.html#icon);
};

Listening to events on a cluster
クラスタ上のイベントを聞く

To listen to events on the cluster, you will need to override the BuildLeafletCluster method. A click event is already specified on m, but you can add other events like mouseover, mouseout, etc. Any events that a Leaflet marker supports, the cluster also supports, since it is just a modified marker. A full list of events can be found here.
クラスタ上のイベントをリッスンするには、BuildLeafletClusterメソッドをオーバーライドする必要があります。クリックイベントはすでに m で指定されていますが、マウスオーバーやマウスアウトなどの他のイベントを追加することができます。リーフレットマーカーがサポートしているイベントはすべて、クラスタもサポートしています。イベントの完全なリストはこちらを参照してください。

Below is an example of how to implement mouseover and mousedown for the cluster, but any events can be used in place of those.
以下にクラスタのマウスオーバーとマウスダウンの実装例を示しますが、これらの代わりに任意のイベントを使用することができます。

pruneCluster.BuildLeafletCluster = function(cluster, position) {
      var m = new L.Marker(position, {
        icon: pruneCluster.BuildLeafletClusterIcon(cluster)
      });

      m.on('click', function() {
        // Compute the  cluster bounds (it's slow : O(n))
        var markersArea = pruneCluster.Cluster.FindMarkersInArea(cluster.bounds);
        var b = pruneCluster.Cluster.ComputeBounds(markersArea);

        if (b) {
          var bounds = new L.LatLngBounds(
            new L.LatLng(b.minLat, b.maxLng),
            new L.LatLng(b.maxLat, b.minLng));

          var zoomLevelBefore = pruneCluster._map.getZoom();
          var zoomLevelAfter = pruneCluster._map.getBoundsZoom(bounds, false, new L.Point(20, 20, null));

          // If the zoom level doesn't change
          if (zoomLevelAfter === zoomLevelBefore) {
            // Send an event for the LeafletSpiderfier
            pruneCluster._map.fire('overlappingmarkers', {
              cluster: pruneCluster,
              markers: markersArea,
              center: m.getLatLng(),
              marker: m
            });

            pruneCluster._map.setView(position, zoomLevelAfter);
          }
          else {
            pruneCluster._map.fitBounds(bounds);
          }
        }
      });
      m.on('mouseover', function() {
        //do mouseover stuff here
      });
      m.on('mouseout', function() {
        //do mouseout stuff here
      });

      return m;
    };
};

Redraw the icons
アイコンを再描画

Marker icon redrawing with a flag:
マーカーアイコンを旗で再描画。

marker.data.forceIconRedraw = true;

...

pruneCluster.ProcessView();

Redraw all the icons:

pruneCluster.RedrawIcons();

Acknowledgements
謝辞

This library was developed in context of the BRIDGE project. It is now supported by the community and we thank the contributors.
このライブラリはBRIDGEプロジェクトの文脈で開発されました。現在はコミュニティによってサポートされており、貢献者に感謝しています。

Licence
ライセンス

The source code of this library is licensed under the MIT License.
このライブラリのソースコードはMITライセンスの下でライセンスされています。

インストール方法

C:\Users\ebata>git clone https://github.com/SINTEF-9012/PruneCluster.git
Cloning into 'PruneCluster’…
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 1054 (delta 3), reused 2 (delta 1), pack-reused 1044
Receiving objects: 100% (1054/1054), 68.39 MiB | 9.96 MiB/s, done.
Resolving deltas: 100% (699/699), done.
Updating files: 100% (54/54), done.

C:\Users\ebata>cd PruneCluster

ここで初めてドキュメントに目を通す。

PruneClusterは、高速でリアルタイムなマーカークラスタリングライブラリです。

Leaflet.markerclusterの代替としてLeafletと連携しています。

このライブラリは、大規模なデータセットやライブ状況向けに設計されています。物理エンジンの衝突検出に着想を得た新しいアルゴリズムのおかげで、メモリ消費量は低く抑えられ、ライブラリはモバイルデバイス上で高速に動作します。
クラスターをリアルタイムで更新することができます。ライブデータセットや、実行時にフィルタリングしたいデータセットに最適です。
各マーカーの重みを指定できます
たとえば、ツイートを表すマーカーよりも、事件を表すマーカーの方が重要度が高い場合があります。
マーカーのカテゴリを指定することができます。そして、各カテゴリのマーカーの数を表す小さなオブジェクトがクラスタに添付されます。このようにして、その内容に合わせたクラスタアイコンを作成することができます。

C:\Users\ebata\PruneCluster\examples>の中にあるサンプルのhtmlの中の座標をいじるだけで、こんなことができました。

https://kobore.net/soft/PruneCluster/examples/toyosu.100.html

このクラスタを無くすには、例えば

var leafletView = new PruneClusterForLeaflet(1,1);  // (120,20)がデフォルト

とかすればいいみたい。

その上で、オブジェクトを1000個に増やしたものが以下になります。

https://kobore.net/soft/PruneCluster/examples/toyosu2.1000.html

以上