div逐渐淡出一边

时间:2016-05-17 13:55:22

标签: javascript jquery html css canvas

这很难解释,所以让我们来看看这张图片:

enter image description here

正如您所看到的,图像中心有一个渐进的规则。我正在尝试使用HTML / CSS找到制作它的方法。

我的问题是:

  1. 背景图片(这里,棒球比赛)可以随时更改,因此标尺在透明背景上需要为白色。
  2. 标尺每边都褪色
  3. 标尺可以设置动画(查看其标记滚动)
  4. 我的猜测是不可能使用HTML / CSS。我想知道是否有人知道使用JS和Canvas(或任何前端技术)实现这一目标的方法?

    编辑:我的不好,我忘了提及必须使用IE9及以上版本。

3 个答案:

答案 0 :(得分:2)

我发现用javascript和canvas做这样的事情很容易。

只需创建包含您要覆盖的内容的DOM元素,并将叠加设置作为数据属性。例如data-ticks-tick-width = "2"

然后在window.onload中调用具有您要覆盖的元素的ID的函数以及您可能希望覆盖的任何设置。你得到一个包含设置的对象(如果你刚刚使用了默认设置,你现在可以访问)和一个重绘画布的方法,如果你想改变任何设置,或者有悬停效果,无论如何。您可以根据需要执行任意数量的元素。您还可以在DOM中搜索具有data-ticks属性的元素,并以此方式添加画布。

演示展示了一种方法。



var addTicks = function(container, settings){
    var name, defaults, step, ctx, canvas, location, x, y, w, h, tickCount;
    function getSetting(dataName){
        var val;
        if(container.attributes["data-" + name + "-" + dataName] !== undefined){
            val =  container.attributes["data-" + name + "-" + dataName].value;
        }else
        if(settings[defaults[dataName][1]] !== undefined){
            val =  settings[defaults[dataName][1]];
        }else{
            val = defaults[dataName][0];
        }
        return settings[defaults[dataName][1]] = val;
    }    
    function easeBell(x, pow) {
      // x = x*2;
      if( x > 1){
           x = 1-(x-1);
          var xx = Math.pow(x,pow);
          return(xx/(xx+Math.pow(1-x,pow)))
      }else{
          var xx = Math.pow(x,pow);
          return(xx/(xx+Math.pow(1-x,pow)))
      }
    }
    function createCanvas(){
        canvas = document.createElement("canvas");
        canvas.style.position = "absolute";
        canvas.style.zIndex = settings.zIndex;
        container.appendChild(canvas);
    }
    function resize(){;
        if(canvas === undefined){
            createCanvas();
        }
        location  = container.getBoundingClientRect();
        y = location.top;
        x = location.left;
        w = (location.right - location.left);
        h = (location.bottom - location.top);          
        canvas.width = Math.round(w * settings.width);
        canvas.height = Math.round(h * settings.height);
        canvas.style.left = (x+Math.round((w - canvas.width)/2)) + "px";
        canvas.style.top = (y+Math.round((h - canvas.height)/2)) + "px";
        ctx = canvas.getContext("2d");
        ctx.strokeStyle = settings.color;
        ctx.lineCap = "butt";
        tickCount = Math.floor((canvas.width / settings.spacing) / 2);
        draw();
    }
    function draw(){
        var i, cx, cy, th, step;
        step = settings.spacing;
        i = 0;
        cx = canvas.width / 2;
        cy = canvas.height / 2;
        ctx.clearRect(0,0,canvas.width,canvas.height)
        ctx.lineWidth = settings.tickWidth;
        for(i = 0; i < tickCount; i ++){
            ctx.beginPath();
            if(i === 0){
                ctx.moveTo(cx, cy - settings.majorHeight / 2);
                ctx.lineTo(cx, cy + settings.majorHeight / 2);
            }else{
                if((i % settings.majorEvery) === 0){
                    th =  settings.majorHeight / 2;
                }else{
                    th =  settings.minorHeight / 2;
                }
                ctx.globalAlpha = easeBell(1- i / tickCount,settings.falloff);
                ctx.moveTo(cx + i * step, cy - th);
                ctx.lineTo(cx + i * step, cy + th);
                ctx.moveTo(cx - i * step, cy - th);
                ctx.lineTo(cx - i * step, cy + th);
            }
            ctx.stroke();
        }
    }
    name = "ticks";
    defaults = {
        width : [0.5,"width"],
        height : [0.2,"height"],
        'spacing' : [10,"spacing"],
        'major-height' : [20,"majorHeight"],
        'minor-height' : [10,"minorHeight"],
        'major-every' : [5,"majorEvery"],
        'color' : ["white","color"],
        'z-index' : [1000,"zIndex"],
        'tick-width' : [2,"tickWidth"],
        'falloff' : [2,"falloff"],
    };
    if(typeof container === "string"){
      container = document.querySelector("#" + container);
    }
    if(container === null || container === undefined){
      return undefined;
    }
    if(settings === undefined){settings = {};}
    "width,height,spacing,major-height,minor-height,major-every,color,z-index,tick-width,tick-width,falloff"
        .split(",")
        .forEach(getSetting);
  
    window.addEventListener("resize",resize);
    resize();
    return {
        canvas : canvas,
        redraw : resize,
        settings : settings,
    };
}

var ticksForImage1;
window.addEventListener("load",function(){
    ticksForImage1 = addTicks("imgContainer");
});

  
&#13;
img {
  width : 100%;
  height : 100%;
}
&#13;
<div id="imgContainer"  data-ticks-color="#EFE" data-ticks-tick-width="1" data-ticks-width='0.9')><img id= "myImage" src='https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/After_Plotting_Rice_Plant.jpg/1280px-After_Plotting_Rice_Plant.jpg' title='By Punya - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=35038411'></div>
&#13;
&#13;
&#13;

<强>更新

动画演示。这是一个快速的黑客,而不是解决动画的最佳方式。就像设置补间动画和使用requestAnimationFrame进行渲染一样。

添加了属性

data-ticks-animate = 'true'  
data-ticks-start-in = '2000' 
data-ticks-run-for = '4000'  
data-ticks-end... animated attributes. see code for list

&#13;
&#13;
var addTicks = function(container, settings){
var name, defaults, step, ctx, canvas, location, x, y, w, h, tickCount, settingsEnd,currentSettings ;
var settingsAtr = "width,height,spacing,major-height,minor-height,major-every,color,z-index,tick-width,animate,start-in,run-for".split(",");
var animSettingsAtrInt = "majorEvery".split(",");
var animSettingsAtr = "spacing,majorHeight,minorHeight,tickWidth".split(",");
function getSetting(dataName){
    var val;
    if(container.attributes["data-" + name + "-" + dataName] !== undefined){
        val =  container.attributes["data-" + name + "-" + dataName].value;
    }else
    if(settings[defaults[dataName][1]] !== undefined){
        val =  settings[defaults[dataName][1]];
    }else{
        val = defaults[dataName][0];
    }
    return settings[defaults[dataName][1]] = val;
}    
function easeInOut(x, pow) {
    var xx = Math.pow(Math.min(1, Math.max(0, x)), pow);
    return(xx / (xx + Math.pow(1 - x, pow)))
}
function createCanvas(){
    canvas = document.createElement("canvas");
    canvas.style.position = "absolute";
    canvas.style.zIndex = settings.zIndex;
    container.appendChild(canvas);
}
function resize(){

    if(canvas === undefined){
        createCanvas();
    }
    location  = container.getBoundingClientRect();
    y = location.top;
    x = location.left;
    w = (location.right - location.left);
    h = (location.bottom - location.top);          
    canvas.width = Math.round(w * settings.width);
    canvas.height = Math.round(h * settings.height);
    canvas.style.left = (x+Math.round((w - canvas.width)/2)) + "px";
    canvas.style.top = (y+Math.round((h - canvas.height)/2)) + "px";
    ctx = canvas.getContext("2d");
    if(!settings.animate ){
        draw(settings);
    }else{
        startAnim();
    }
}
function draw(settings){
    var i, cx, cy, th, step;
    step = Math.max(1,settings.spacing);
    ctx.strokeStyle = settings.color;
    ctx.lineCap = "butt";
    tickCount = Math.floor((canvas.width / step) / 2);
    i = 0;
    cx = canvas.width / 2;
    cy = canvas.height / 2;
    ctx.clearRect(0,0,canvas.width,canvas.height)
    ctx.lineWidth = settings.tickWidth;
    for(i = 0; i < tickCount; i ++){
        ctx.beginPath();
        if(i === 0){
            ctx.globalAlpha = 1;
            ctx.moveTo(cx, cy - settings.majorHeight / 2);
            ctx.lineTo(cx, cy + settings.majorHeight / 2);
        }else{
            if((i % settings.majorEvery) === 0){
                th =  settings.majorHeight / 2;
            }else{
                th =  settings.minorHeight / 2;
            }
            ctx.globalAlpha = easeInOut(1- i / tickCount,2);
            ctx.moveTo(cx + i * step, cy - th);
            ctx.lineTo(cx + i * step, cy + th);
            ctx.moveTo(cx - i * step, cy - th);
            ctx.lineTo(cx - i * step, cy + th);
        }
        ctx.stroke();
    }
}
var endTime;
var runTime;
function animate(time){
    if(endTime === undefined){
        endTime = time + Number(settings.runFor);
    }
    var progress = 1-Math.min(1,(endTime - time) / Number(settings.runFor));
    for(var i= 0; i < animSettingsAtrInt.length; i ++){
        var f = Number(settings[animSettingsAtrInt[i]]);
        var t = Number(settingsEnd[animSettingsAtrInt[i]]);
        currentSettings[animSettingsAtrInt[i]] = Math.floor((t-f) * progress + f);
    }
    for(var i= 0; i < animSettingsAtr.length; i ++){
        var f = Number(settings[animSettingsAtr[i]]);
        var t = Number(settingsEnd[animSettingsAtr[i]]);
        currentSettings[animSettingsAtr[i]] = (t-f) * progress + f;
    }


    draw(currentSettings);

    if(progress < 1){
        requestAnimationFrame(animate)
    }
}
function start(){
    requestAnimationFrame(animate);
}
function startAnim(){
    endTime = undefined;
    setTimeout(start,Number(settings.startIn));
}
name = "ticks";
defaults = {
    width : [0.5,"width"],
    height : [0.2,"height"],
    'spacing' : [10,"spacing"],
    'major-height' : [20,"majorHeight"],
    'minor-height' : [10,"minorHeight"],
    'major-every' : [5,"majorEvery"],
    'color' : ["white","color"],
    'z-index' : [1000,"zIndex"],
    'tick-width' : [5,"tickWidth"],
    'animate' : [true,"animate"],
    'start-in' : [2000, "startIn"],
    'run-for' : [5000, "runFor"]
};
if(typeof container === "string"){
  container = document.querySelector("#" + container);
}
if(container === null || container === undefined){
  return undefined;
}
if(settings === undefined){settings = {};}
settingsAtr.forEach(getSetting);
var tempSettings = settings;
settings = {};
settingsAtr.forEach(getSetting);
currentSettings = settings;
settings = tempSettings;
if(settings.animate){
    name = "ticks-end";
    var settingT = settings;
    settings = {};
    settingsAtr.forEach(getSetting);
    settingsEnd = settings;
    settings = settingT;
    name = "ticks";

}

window.addEventListener("resize",resize);
resize();
return {
    canvas : canvas,
    redraw : resize,
    settings : settings,
};
}


var ticksForImage1;
window.addEventListener("load",function(){
    ticksForImage1 = addTicks("imgContainer");
});

  
&#13;
img {
  width : 100%;
  height : 100%;
}
&#13;
<div id="imgContainer"  
data-ticks-animate='true' 
data-ticks-start-in='2000' 
data-ticks-run-for='4000' 
data-ticks-spacing='50' 
data-ticks-end-spacing='20'  
data-ticks-major-height='10' 
data-ticks-end-major-height='30'  
data-ticks-minor-height='30' 
data-ticks-end-minor-height='10'  
data-ticks-tick-width='12'  
data-ticks-end-tick-width='1'  
data-ticks-color="#FFF"><img id= "myImage" src='https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/After_Plotting_Rice_Plant.jpg/1280px-After_Plotting_Rice_Plant.jpg'></div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

你确实有一个CSS选项,但它现在的支持是相当不稳定的。我在谈论mask属性。在我写这篇文章时,它们在IE和Edge中不受支持,在Webkit和Moz浏览器中得到不同的支持,但基本上对于wbekit来说:

-webkit-mask-image: -webkit-gradient(linear, left top, right top, from(rgba(0,0,0,1)), color-stop(0.75, rgba(0,0,0,1)), to(rgba(0,0,0,0)));

对于moz,您需要将SVG图形与CSS结合使用:

mask: url(#fade_right_svg_mask);

示例来自here

答案 2 :(得分:1)

使用canvas(循环)轻松完成步骤:

  • 明确背景
  • 使用fillRect()使用模式+翻译或行+ stroke()在正确的偏移位置绘制标尺。复合模式“source-over
  • 使用具有透明边缘的线性(或径向)渐变或表示蒙版的图像在顶部绘制蒙版。复合模式“destination-in
  • 使用复合模式“destination-atop
  • 在顶部绘制背景图像

实施例

snap

根据需要调整线条和颜色(尽管只有渐变的alpha值)。这只是一个粗略的骨架 - 根据需要采用:

var ctx = c.getContext("2d"), x = 0;

// pseudo ruler for demo
ctx.globalCompositeOperation = "source-over";  // needed if in a loop
ctx.beginPath();
for(var i=30;i--;) {ctx.moveTo(i*10+0.5, 60);ctx.lineTo(i*10+0.5, 90)}
ctx.strokeStyle = "#fff";
ctx.stroke();

// mask
var gr = ctx.createLinearGradient(0,0,300,0);
gr.addColorStop(0, "rgba(0,0,0,0)");
gr.addColorStop(0.5, "#000"); 
gr.addColorStop(1, "rgba(0,0,0,0)");
ctx.fillStyle = gr;
ctx.globalCompositeOperation = "destination-in";
ctx.fillRect(0,0,300,150);

// draw background image
ctx.globalCompositeOperation = "destination-atop";
ctx.fillStyle = "#07f";
ctx.fillRect(0,0,300,150);
<canvas id=c></canvas>

提示:如果线性渐变在IE9中产生问题,请用掩模图像替换它。如果确定,我建议缓存渐变。定义它并不会花费太多但渲染它,所以将它渲染到离屏画布并将该画布用作drawImage()的图像源而不是该步骤。