这很难解释,所以让我们来看看这张图片:
正如您所看到的,图像中心有一个渐进的规则。我正在尝试使用HTML / CSS找到制作它的方法。
我的问题是:
我的猜测是不可能使用HTML / CSS。我想知道是否有人知道使用JS和Canvas(或任何前端技术)实现这一目标的方法?
编辑:我的不好,我忘了提及必须使用IE9及以上版本。
答案 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;
<强>更新强>
动画演示。这是一个快速的黑客,而不是解决动画的最佳方式。就像设置补间动画和使用requestAnimationFrame进行渲染一样。
添加了属性
data-ticks-animate = 'true'
data-ticks-start-in = '2000'
data-ticks-run-for = '4000'
data-ticks-end... animated attributes. see code for list
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;
答案 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
”
根据需要调整线条和颜色(尽管只有渐变的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()
的图像源而不是该步骤。