24150


HTMLにおいてCSSまたはJavaScriptを利用しテキスト（テキストを含む要素ではなく、テキスト、文字それ自体）にマウスカーソルが乗っているかを判定し効果をつける方法はありますか。  
CSSなら

[code]

    <style>
    #box:hover { /* css */ }
    </style>
    
    <div id="box">てきすと</div>
    
[/code]

というのではなくて、たとえば疑似コードを書くなら

[code]

    <style>
    #box:textShape:hover { /* css */ }
    </style>
    
[/code]

みたいなことです。  
SVGのを利用した方法については確認済みですので、タイトルの通りCSSあるいはJavaScriptで可能かどうかを教えていただきたく、また可能であれば参考になるページなどを示していただければ幸いです。  
よろしくおねがいします。


CC BY-SA 3.0
2016-04-16T05:22:55.797
24063
2016-04-19T07:13:45.960
question
javascript html css
CSS/Javascriptでテキストにマウスカーソルが乗っているかの判定


下のスニペットは`canvas`要素を使った例です。  
しかし、おそらく質問者さんは通常のHTML要素で描画されている字形に対して、判定を行ないたいのだと思います。  
それも`canvas`を使った方法の応用で出来るかもしれませんが、少し考えてみないと分かりません。

[code]

    function text_shape(elm){
     "use strict";
     var ctx = elm.getContext("2d");
    
     function set_size(){
      var rect = elm.getBoundingClientRect();
      elm.width = rect.width;
      elm.height = rect.height;
     }
    
     function draw_text(){
      var style = getComputedStyle(elm);
      ctx.font = style.fontSize + " " + style.fontFamily;
      ctx.fillStyle = style.color;
      ctx.textAlign = "left";
      ctx.textBaseline = "top";
      ctx.fillText(elm.textContent, 0, 0);
     }
    
     function check_hover(ev){
      var alpha = ctx.getImageData(ev.offsetX, ev.offsetY, 1, 1).data[3];
      if(alpha){
       elm.classList.add("text_shape_hover");
       return;
      }
      hover_out();
     }
    
     function hover_out(){
      elm.classList.remove("text_shape_hover");
     }
    
     function init(){
      set_size();
      draw_text();
     }
    
     elm.addEventListener("mousemove", check_hover);
     elm.addEventListener("mouseout", hover_out);
     window.addEventListener("resize", init);
    
     init();
    }
    
    text_shape(document.getElementById("text"));
[/code]

[code]

    #text{
     font-size: 2em;
     font-family: serif;
     color: blue;
     width: 100%;
     height: 1em;
    }
    .text_shape_hover{
     -webkit-filter: hue-rotate(100deg);
     filter: hue-rotate(100deg);
    }
[/code]

[code]

    <canvas id="text">○● Text 文字</canvas>
[/code]

上記スニペットで`canvas`要素に描画しているのは文字だけです。  
ポインタ座標の透明度(アルファ値)を取得し、透明でなければ、そこは字形の上だと分かります。  
マウスが動く度に下記のようにこれを判定し、字形の上に来たら`text_shape_hover`というクラスを設定しています。

[code]

    var alpha = ctx.getImageData(ev.offsetX, ev.offsetY, 1, 1).data[3];
            if(alpha){
                elm.classList.add("text_shape_hover");
    
[/code]

`text_shape_hove`クラスには下記のようにスタイルを当てています。  
`canvas`要素の`color`を変えても仕方ないので、フィルタを掛けて色を変えています。

[code]

    .text_shape_hover{
        -webkit-filter: hue-rotate(100deg);
        filter: hue-rotate(100deg);
    }
    
[/code]


CC BY-SA 3.0
2016-04-18T13:47:23.703
24122
2016-04-18T13:47:23.703
3054
24063
answer


mjy様の回答はとても参考になりました。canvasを使える環境であれば、示していただいた手法が解決法の一つとなるでしょう。また、このことを参考に自分でも調査をしてみると、<https://stackoverflow.com/questions/1936021/javascript-
eyedropper-tell-color-of-pixel-under-mouse-cursor>
というQAを発見し、こちらにもやはりcanvasを利用した回答、そして

> It's not possible with JavaScript as it goes against cross-domain security.

というようにjsではここまでが限界のようです。また、

> 通常のHTML要素で描画されている字形に対して、判定を行ないたい

のです。おっしゃるとおりです。

さて私は以前[html2canvas](https://html2canvas.hertzen.com/)というライブラリを使用したことがありまして、これはDOMを読んで独自にレンダリングしcanvas要素にスクリーンショットのようなものを生成してくれるライブラリです。画像の読み込みやiframe,flashなどへのサポートは技術的な制約もあり不完全ですが、テキスト目的という今回の趣旨については十分でしょう。  
判定処理の発想はそのままですが、このスクリーンショットの画像を利用したサンプルを作ってみました。

[code]

    var target = document.querySelector('#box');
    var ssCtx;
    
    html2canvas(target, {
      onrendered: function(canvas) {
        ssCtx = canvas.getContext('2d');
      }
    });
    
    target.addEventListener('mousemove', function (e) {
      if (ssCtx) {
        var pixel = ssCtx.getImageData(e.offsetX, e.offsetY, 1, 1);
        target.className = pixel.data[3] ? 'text_shape_hover' : '';
      }
    });
[/code]

[code]

    #box {
      font-size: 200px;
      font-weight: bold;
      transition: color 0.3s;
    }
    #box.text_shape_hover {
      color: red;
    }
[/code]

[code]

    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
    
    <div id="box">てきすと</div>
[/code]

結果は良好です。細部について（背景色/scroll/動作負荷/各環境のサポート）については未検証ですが、少なくともテキスト要素について利用するならば、canvasをサポートしてさえいればうまく動作するよう実装できるはずです。

結局canvasで力技かよ、と自分でも思いますが、以上で一応の自己解決として回答を載せておきたいと思います。


CC BY-SA 3.0
2016-04-19T07:13:45.960
24150
2016-04-19T07:13:45.960
2017-05-23T12:38:55.307
-1
24063
answer