【问题标题】:Canvas clipping mask positioning issue画布剪贴蒙版定位问题
【发布时间】:2016-06-09 20:02:16
【问题描述】:

长话短说 - 看看下面的简单小提琴。长话短说 - 我正在使用 HTML5 Canvas 和 SVG 路径剪贴蒙版从图像中屏蔽自定义形状。除了我尝试将容器放置在其他地方之外,一切都按预期工作。

您可以在此 Fiddle 中看到有问题的问题 - https://jsfiddle.net/eyv35f6k/1/

body {
  padding: 0; 
  margin: 0
  }
  
  .container {
    position:absolute;
    top: 0px;
    /* *********** top: 50px; *********** */
  }

.css-clipped {
  display: block; 
  -webkit-clip-path:url(#svgPath);
  clip-path:url(#svgPath);
  }
<!- Element that cointains image that must be clipped by using custom shape  ->
  <div class="container">
    <img class="css-clipped" src="https://sarasoueidan.com/demos/css-svg-clipping/html-img-clipped-with-css/flowers.jpg">
  </div>


<!- SVG that contains clop path ->
  <svg height="0" width="0">
    <defs>
      <clipPath id="svgPath">
        <path fill="#FFFFFF" stroke="#000000" stroke-width="1.0" stroke-miterlimit="10" d="m49,0c2,0 4,0 6,0c16,1 30,3 36,13c6,9 7,23 7,36c0,13 -1,27 -7,36c-6,10 -20,12 -36,13c-2,0 -4,0 -6,0l0,0c-2,0 -4,0 -6,0c-16,-1 -30,-3 -36,-13c-6,-9 -7,-23 -7,-36c0,-13 1,-27 7,-36c6,-10 20,-12 36,-13c2,0 4,0 6,0l0,0z"/>
      </clipPath>
    </defs>
  </svg>

如果您尝试在 .container 元素周围移动,您会看到容器和其中的图像移动,而画布遮罩保持在页面主体的同一左上角,而不是移动连同它被应用到的元素。我在 Photoshop 中制作了示例图片来说明我想要实现的目标:

您能否告诉我,如何使画布蒙版与它所应用的元素一起移动?提前致谢。

【问题讨论】:

    标签: css html canvas clip


    【解决方案1】:

    您至少可以通过两种方式使用剪辑:

    视口模式:

    当您拖动时,剪辑会在下方较大图像的不同较小部分上显示一个“窗口”。

    Drag-a--static-Clip 模式:

    从较大的图像中剪裁出一个小的静态图像。拖动时,静态图像会在画布周围移动。

    这里是示例代码和演示两种剪辑模式的演示。

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
    function reOffset(){
        var BB=canvas.getBoundingClientRect();
        offsetX=BB.left;
        offsetY=BB.top;        
    }
    var offsetX,offsetY;
    reOffset();
    window.onscroll=function(e){ reOffset(); }
    window.onresize=function(e){ reOffset(); }
    
    var isDown=false;
    var startX,startY;
    
    var ox=0;
    var oy=0;
    var width=75;
    var height=50;
    var mode='Viewport'
    var clippedImage;
    
    var img=new Image();
    img.onload=start;
    img.src="https://sarasoueidan.com/demos/css-svg-clipping/html-img-clipped-with-css/flowers.jpg";
    function start(){
        clipImage=createClipImg(ox,oy,width,height);
        $("#canvas").mousedown(function(e){handleMouseDown(e);});
        $("#canvas").mousemove(function(e){handleMouseMove(e);});
        $("#canvas").mouseup(function(e){handleMouseUpOut(e);});
        $("#canvas").mouseout(function(e){handleMouseUpOut(e);});
        //
        $('input[type=radio][name=group1').change(function(){
            mode=this.value;
            if(mode=='Drag'){
                clippedImage=createClipImg(ox,oy,width,height);
            }
            draw();
        });
        draw();
    }
    
    function draw(){
        ctx.clearRect(0,0,cw,ch);
        if(mode=='Viewport'){
            clippedViewport(ox,oy,width,height);
        }else{
            ctx.drawImage(clippedImage,ox,oy);
        }
    }
    
    function clippedViewport(x,y,w,h){
        ctx.save();
        ctx.beginPath();
        ctx.rect(x,y,w,h);
        ctx.closePath();
        ctx.clip();
        ctx.drawImage(img,0,0);
        ctx.restore();
    }
    
    function createClipImg(x,y,w,h){
        var c=document.createElement('canvas');
        var cctx=c.getContext('2d');
        c.width=w;
        c.height=h;
        cctx.drawImage(img,-x,-y);
        return(c);
    }
    
    
    
    function handleMouseDown(e){
      // tell the browser we're handling this event
      e.preventDefault();
      e.stopPropagation();
      //
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);
      // Put your mousedown stuff here
      if(startX>ox && startX<ox+width && startY>oy && startY<=oy+height){
          isDown=true;
      }
    }
    
    function handleMouseUpOut(e){
      // tell the browser we're handling this event
      e.preventDefault();
      e.stopPropagation();
      // Put your mouseup stuff here
      isDown=false;
    }
    
    function handleMouseMove(e){
      if(!isDown){return;}
      // tell the browser we're handling this event
      e.preventDefault();
      e.stopPropagation();
      //
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      // Put your mousemove stuff here
      var dx=mouseX-startX;
      var dy=mouseY-startY;
      startX=mouseX;
      startY=mouseY;
      //
      ox+=dx;
      oy+=dy;
      draw();
    }
    body{ background-color: ivory; }
    canvas{border:1px solid red; }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    Mode:&nbsp
    <input type=radio name=group1 value=Viewport checked>Viewport
    <input type=radio name=group1 value=Drag>Drag clip
    <hr>
    "Viewport" reveals different part of the image underneath.
    <br>
    "Drag clip" drags the same clipped image part around the canvas.
    <hr>
    <canvas id="canvas" width=300 height=300></canvas>

    [补充:图片剪辑到 html5 画布中]

    您可以将剪切的图像绘制到 html5 画布上(每个图像 1 个画布),然后像使用图像一样使用画布。

    var img=new Image();
    img.onload=start;
    img.src="https://sarasoueidan.com/demos/css-svg-clipping/html-img-clipped-with-css/flowers.jpg";
    function start(){
        var container=document.getElementById('container');
        for(var i=0;i<6;i++){
            makeClippedCanvas(img,100,100,container);
        }
    }
    
    
    function makeClippedCanvas(img,w,h,container){
        var c=document.createElement("canvas");
        var ctx=c.getContext("2d");
        c.width=w;
        c.height=h;
        //
        ctx.moveTo(50,0);
        ctx.bezierCurveTo(100,5, 100,15, 100,50);
        ctx.bezierCurveTo(100,85, 100,95, 50,100);
        ctx.bezierCurveTo(0,95, 0,85, 0,50);
        ctx.bezierCurveTo(0,15, 0,5, 50,0);
        ctx.closePath();
        ctx.stroke();
        ctx.clip();
        ctx.drawImage(img,0,0);
        container.appendChild(c);
        return(c);
    }
    body{ background-color: ivory; }
    #container{width:50%; border:1px solid blue;}
    canvas{margin:5px;}
    <h4>Resize the window</h4>
    <div id=container></div>

    【讨论】:

    • 您好,感谢您的回答-尽管您有点误解了我,但您示例中“静态图像”的结果似乎对我来说是必需的。问题是我实际上不必移动 围绕其中具有剪辑蒙版的那些容器 - 我只是想在网格视图中有多个缩略图(图像数量可以不同),并且每个他们用这个面具剪裁。那么 - 这可以在没有javascript但使用纯CSS的情况下实现吗,就像我原来的帖子一样? - 简单的多个元素,排列在网格视图中(显示内联块或浮动),每个元素内部都有剪辑的图像缩略图?
    • 完美解决方案!非常感谢。也标记为最佳答案!
    • 当然。我强烈推荐 Mike Swanson 的 Adobe Illustrator plugin,它将 SVG 转换为 html5 画布绘图命令。或者,您可以在我的演示中微调曲线 - 无需太多更改即可准确再现您的 svg 形状。或者,如果您需要即时转换,您可以查看canvg
    • 如果您只需要将一个 svg 形状转换为画布,那么我已经为您完成了 here
    • 感谢您花半个小时的时间工作。刚刚在测试环境中实现它,就像一个魅力。 :)
    猜你喜欢
    • 2021-02-20
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2012-07-07
    • 2011-10-20
    • 2016-07-07
    • 2011-06-27
    • 2017-02-10
    相关资源
    最近更新 更多