<object> を用いたインタラクティブなSVG?

インタラクティブな SVG ベースのデータ可視化を埋め込もうとしています。SVG は別のシステムで生成していますが、Discourse のインストールと同じセカンドレベルドメイン内にあります。まず OBJECT タグを使って SVG を読み込もうとしました…

<object type="image/svg+xml" data="full_URL_to_foo.svg">
(オブジェクトの読み込みに失敗した場合に表示)
</object>

SVG を IMG タグで単純に読み込むと、画像は表示されますが(予想通り)、インタラクティブ性は失われます。

<img src="full_URL_to_foo.svg">

SVG と Discourse に関するヒントや情報源をご存知ないでしょうか? :slight_smile:

「いいね!」 1

これを機能させる最も簡単な方法は、iframe を使用することです。SVG ドメインを allowed_iframes サイト設定に追加し、HTML を使用して投稿に追加してください。

「いいね!」 5

ふむ、つまりそれが簡単な方法なんですね。

では、試せる難しい方法はありませんか?

…というのも、SVG 内のリンクでブラウザの位置情報を変更したいからです。SVG 内のリンクは、IFRAME 内にある場合、IFRAME 表示内容を変更してしまいます。

おそらく、トピックの IFRAME の直前に JavaScript を埋め込み、SVG 内の onclick でページ内の JavaScript 関数を呼び出す方法も、うまくいかないでしょう。

私の言っていることは通じていますか?Mitigate XSS Attacks with Content Security Policy のような軽量な JavaScript コードを追加し、それを IFRAME 内の SVG から呼び出すべきでしょうか?それとも「IFRAME 内」というのは完全に隔離された要塞なのでしょうか?

もしかすると、SVG をページに直接インライン化する方法を尋ねるべきでしょうか?その後、テーマコンポーネントで注入された JavaScript を使って、他のサーバーと連携し、SVG を動的に更新するのです。

ヒントをお願いします :slight_smile:

「いいね!」 2

SVGを特別な div で囲んで投稿に含め、decorateCooked コールバックを使って theme-component で object タグに変換する方法が機能する可能性があります。詳しくはDiscourse テーマのデベロッパーガイドをご覧ください。

「いいね!」 3

…もし誰かが追っているなら、decorateCooked() は非推奨です。代わりに decorateCookedElement() をいじっています。

「いいね!」 1

CORS(Access-Control-Allow-Origin)の問題に直面しています。その仕組みについては詳しくありません…

2 つのサイトを持っています。ホストされた Discourse サイト(forum.moversmindset.com)と、Apache ベースの WordPress サイト(moversmindset.com)です。WordPress サイトには目立ったコンテンツはありません。RSS フィードの生成やメディアの配信などが行われているだけです。ドメインにアクセスすると、フォーラムへリダイレクトされます。

GET リクエストに対して SVG 形式のレスポンスを返すディレクトリがあります。例えば(実際の URL ではありません)、https://moversmindset.com/foo/bar.php のようなものです。

Discourse のテーマ内でスクリプトコードを実験しています(将来的には正式なプラグインにする予定です)。特定の DIV(data-custom 属性が追加されたもの)に対して api.decorateCooked() を呼び出しています。decorateCooked() によって呼び出される関数内では、以下のような処理を行っています。

$.get(‘https://moversmindset.com/foo/bar.php’ … 以下略

SVG を取得して DOM に追加したいのですが、ブラウザのエラーコンソールには以下のようなエラーが表示されます。

質問:

これは、Discourse インストール側で CORS を設定する必要があるのか、それとも Apache/WordPress 側で設定する必要があるのでしょうか?

Discourse 側では、https://moversmindset.com を CORS で許可する設定はすでに行っています。

「いいね!」 2

多分こっち側だと思います。まだ確認されていないようでしたら、Access-Control-Allow-Origin header - HTTP | MDN をご覧になって、何か手がかりが得られるか確認していただけませんか?

「いいね!」 4

小さな一歩ですが、YES!

Apache/WP サーバーに Access-Control-Allow-Origin ヘッダーを追加する必要がありました。それにより、Discourse プラットフォームから提供されている JavaScript が正常に動作するようになりました。ありがとうございます。

「いいね!」 3

徐々に理解が進んでいます。質問をするには、かなりの準備が必要です。

SVG

私は SVG を生成する Web サーバーを持っています。この質問では、非常にシンプルなテスト SVG を生成します…

<svg xmlns="http://www.w3.org/2000/svg" stroke-linejoin="round" viewBox="0 0 100 100">
<path d="M50,4L4,50L50,96L96,50Z" stroke="#40638C" stroke-width="3"></path>
<path d="M50,5L5,50L50,95L95,50Z" stroke="#333" fill="#40638C" stroke-width="3"></path>
<path d="M37,42c-1,0,11-20,13-20c1,0,15,20,13,20h-9c0,8,9,22,12,25l-4,4l-8,-7v13h-10v-35z" stroke="#40495E" fill="#40495E"></path>
<path d="M35,40c-1,0,11-20,13-20c1,0,15,20,13,20h-9c0,8,9,22,12,25l-4,4l-8,-7v13h-10v-35z" stroke="#333" fill="#555"></path>
</svg>

これは単に見た目が凝った「マージ」記号です。4 つの PATH 要素が含まれている点に注意してください。

インライン化

SVG を投稿に含めるために、テーマ経由で追加された JavaScript を使用しています。

最終目標は、適切なプラグインを作成することですが、今は概念実証(PoC)を構築しようとしています。そのため、単にテーマのカスタマイズにある <head> セクションに貼り付けています。

<script type="text/discourse-plugin" version="0.8">
var UMB = {
    svgload: function(base, target) {
        var url = base + $(target).text();
        $(target).html('');
        $.ajax({
            method: "GET",
            url: url,
            async: false,
            dataType: "text",
            success: function(data) { $(target).append(data); }
        });
        alert('loaded!');
        $(target).children('path').each(function(){alert('here is a path element');});
    },
}
$.fn.umbdv = function() {
    this.each(
        function() {
            UMB.svgload('__URL_REDACTED__', this);
        }
    );
    return this;
};
api.decorateCooked(
  $elem => $elem.children('.cooked div[data-custom="umbdv"]').umbdv(),
  { id: 'umbdv' }
);
</script>

ここで…

var UMB = { は、至る所に巨大な無名関数を記述する必要を避けるための単なるグローバル変数です。

$.fn.umbdv = は、私が思うに JQuery を拡張する「プラグイン」と呼ばれるものです。

api.decorateCooked( を使うと、投稿がブラウザに送信される前に操作できます。

呪文(実装)

トピック内で、以下のように記述します…

<div data-custom="umbdv">/vtest</div>

この DIV に対して UMB.svgload('__URL_REDACTED__', this) が呼び出されます。

UMB.svgload()/vtest という文字列を正しく解析し、URL を構成して AJAX リクエストを発行します。append(data) が正常に実行され、boop で SVG がインライン化されます…

その後、UMB.svgload() 内の alert() が期待通りに発火します。(もちろん、これはデバッグ用のハックですよね? :)

質問(ようやく)

Discourse ホストのフォーラムには、スタッフ専用トピックがあり、そこでこの動作を確認できます。(私は、管理者として私のインストールに直接介入できる Discourse のスタッフやサポート担当者にお話ししています。)

https://forum.moversmindset.com/t/svg-experimentation-in-progress/1109

なぜ…

$(target).children('path').each(function(){alert('here is a path element');});

…が PATH 要素のいずれも選択しないのでしょうか?

何も起きません。エラーもなし。何もないのです。

次のステップ

この些細な alert() の概念実証が機能するようになったら、私は以下に進む予定です…

私が「操作している」DOM の断片は、UMB.svgload() が呼び出された時点では、実際のドキュメント DOM にまだ接続されていないことを認識しています。そのため、$(target)… が必要だと期待しています。

最終的には、はるかに複雑な SVG をインライン化することになり、より複雑な JQuery セレクタを使用する必要があります。$(target) 内の多くの要素を見つけて、他の UMB.… グローバル関数を呼び出すイベントハンドラ(例えば onclick など)をアタッチしたいと考えています。

「いいね!」 1

必要であれば、IFRAME はトップレベルのナビゲーションを変更することも可能です。

http://w3c-test.org/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation_by_user_activation-manual.html

「いいね!」 3

アドバイスありがとうございます!

でも、今はインラインの SVG を圧倒的に好みます。

まあ、どうしようもないね。数週間経ったけど、これは動かない。

SVG をメインドキュメントにインライン化してしまうと、SVG の DOM 要素を操作できないみたいだ。だから、イベントトリガーやアクション(SVG を iframe で読み込んでいれば onclick などで簡単にできるはずだが)を追加する方法が全く見当がつかない。
(iframe を使わないことが私の本来の目的だったんだけどね)

¯\\_(ツ)_/¯

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.