- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对 Javascript 非常有经验,但没有深入研究它的高级图形功能(canvas、webGL、three.js 等)。我想创建一种类似于 this one 的失真效果, 除了我想将它应用于文本而不是图像。基本上我想要一些乍一看看起来像纯 HTML 的文本,但是当用户将鼠标悬停在它上面时,文本应该弯曲/扭曲/涂抹作为响应。
到目前为止,我发现了两个类似但不完全是我想要的 SO 帖子:first太简单了,因为我想扭曲和弯曲文本,而不仅仅是将它向下移动页面。 second更有趣,因为我有一种预感,我需要使用像 Three.js 这样的库来实现这种效果,但我想要 2d,而不是 3d,我想实际扭曲文本的“形状”,而不是只需围绕一个轴旋转它即可。
我想知道如何创建这种效果,是否有我想要的特定效果的名称(在网上很难找到好的例子),任何好的例子,建议,任何东西。提前致谢!
最佳答案
多种可能性。
这是在标准 2D Canvas 上绘制的简单 WEBGL 2D 纹理示例。鼠标、 Canvas 、webGL 有一些样板文件,因此您必须自己将其拆开。
FX 在片段着色器中。我没有移动纹理坐标,而是在图像上映射了一个 2D 向量场(几乎是随机制作的)向量从纹理中偏移了像素查找。鼠标上下控制的数量
控制FX的数量,鼠标从左到右移动Phase
设置。
将鼠标移动到图像的顶部会减少效果量。右下角最大。
.
底部的函数 webGLRender
设置片段着色器值并渲染 webGl,然后渲染 2D 上下文 drawImage
以渲染显示 Canvas 。片段着色器在其之上。
由于 webGL 图像是通过 ctx.draw2D 渲染的,因此很容易调整大小,使 webGL 渲染总显示分辨率独立。如果您遇到性能问题(百万像素 * 4 + 范围内的图像),您可以减小输入图像的大小
与 2D canvas 不同,WebGL 无法渲染来自不同域(污染)的图像 WebGL 需要访问像素数据来绘制纹理,因此污染图像会引发安全错误。我使用了 2d Canvas 而不是图像,因为我找不到不会污染 Canvas 的图像。
// boiler plate
const U = undefined;const RESIZE_DEBOUNCE_TIME = 100;
var w,h,cw,ch,canvas,ctx,mouse,createCanvas,resizeCanvas,setGlobals,globalTime=0,resizeCount = 0;
var L = typeof log === "function" ? log : function(d){ console.log(d); }
createCanvas = function () { var c,cs; cs = (c = document.createElement("canvas")).style; cs.position = "absolute"; cs.top = cs.left = "0px"; cs.zIndex = 1000; document.body.appendChild(c); return c;}
resizeCanvas = function () {
if (canvas === U) { canvas = createCanvas(); } canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") { setGlobals(); } if (typeof onResize === "function"){ resizeCount += 1; setTimeout(debounceResize,RESIZE_DEBOUNCE_TIME);}
}
function debounceResize(){ resizeCount -= 1; if(resizeCount <= 0){ onResize();}}
setGlobals = function(){ cw = (w = canvas.width) / 2; ch = (h = canvas.height) / 2; mouse.updateBounds(); }
mouse = (function(){
function preventDefault(e) { e.preventDefault(); }
var mouse = {
x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false, buttonRaw : 0, over : false, bm : [1, 2, 4, 6, 5, 3],
active : false,bounds : null, crashRecover : null, mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
var m = mouse;
function mouseMove(e) {
var t = e.type;
m.x = e.clientX - m.bounds.left; m.y = e.clientY - m.bounds.top;
m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1]; }
else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2]; }
else if (t === "mouseout") { m.buttonRaw = 0; m.over = false; }
else if (t === "mouseover") { m.over = true; }
else if (t === "mousewheel") { m.w = e.wheelDelta; }
else if (t === "DOMMouseScroll") { m.w = -e.detail; }
if (m.callbacks) { m.callbacks.forEach(c => c(e)); }
if((m.buttonRaw & 2) && m.crashRecover !== null){ if(typeof m.crashRecover === "function"){ setTimeout(m.crashRecover,0);}}
e.preventDefault();
}
m.updateBounds = function(){
if(m.active){
m.bounds = m.element.getBoundingClientRect();
}
}
m.addCallback = function (callback) {
if (typeof callback === "function") {
if (m.callbacks === U) { m.callbacks = [callback]; }
else { m.callbacks.push(callback); }
} else { throw new TypeError("mouse.addCallback argument must be a function"); }
}
m.start = function (element, blockContextMenu) {
if (m.element !== U) { m.removeMouse(); }
m.element = element === U ? document : element;
m.blockContextMenu = blockContextMenu === U ? false : blockContextMenu;
m.mouseEvents.forEach( n => { m.element.addEventListener(n, mouseMove); } );
if (m.blockContextMenu === true) { m.element.addEventListener("contextmenu", preventDefault, false); }
m.active = true;
m.updateBounds();
}
m.remove = function () {
if (m.element !== U) {
m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); } );
if (m.contextMenuBlocked === true) { m.element.removeEventListener("contextmenu", preventDefault);}
m.element = m.callbacks = m.contextMenuBlocked = U;
m.active = false;
}
}
return mouse;
})();
resizeCanvas();
mouse.start(canvas,true);
window.addEventListener("resize",resizeCanvas);
function display(){
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.clearRect(0,0,w,h);
if(webGL !== undefined){
webGLRender();
}
}
function update(timer){ // Main update loop
globalTime = timer;
display(); // call demo code
requestAnimationFrame(update);
}
requestAnimationFrame(update);
var globalTime = new Date().valueOf(); // global to this
// creates vertex and fragment shaders
function createProgramFromScripts( gl, ids) {
var shaders = [];
for (var i = 0; i < ids.length; i += 1) {
var script = shadersSource[ids[i]];
if (script !== undefined) {
var shader = gl.createShader(gl[script.type]);
gl.shaderSource(shader, script.source);
gl.compileShader(shader);
shaders.push(shader);
}else{
throw new ReferenceError("*** Error: unknown script ID : " + ids[i]);
}
}
var program = gl.createProgram();
shaders.forEach((shader) => { gl.attachShader(program, shader); });
gl.linkProgram(program);
return program;
}
// setup simple 2D webGL image processor
var webGL;
function startWebGL(image) {
// Get A WebGL context
webGL = document.createElement("canvas");
webGL.width = image.width;
webGL.height = image.height;
webGL.gl = webGL.getContext("webgl");
var gl = webGL.gl;
var program = createProgramFromScripts(gl, ["VertexShader", "FragmentShader"]);
gl.useProgram(program);
var positionLocation = gl.getAttribLocation(program, "a_position");
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.0, 0.0,1.0, 0.0,0.0, 1.0,0.0, 1.0,1.0, 0.0,1.0, 1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
// lookup uniforms for frag shader
var locs = {}
locs.timer = gl.getUniformLocation(program, "time"); // the time used to control waves
locs.phase = gl.getUniformLocation(program, "phase"); // Sort of phase, moves to attractors around
locs.amount = gl.getUniformLocation(program, "amount"); // Mix amount of effect and flat image
webGL.locs = locs;
gl.uniform2f(resolutionLocation, webGL.width, webGL.height);
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
setRectangle(gl, 0, 0, image.width, image.height);
}
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2]), gl.STATIC_DRAW);
}
function randomInt(range) {
return Math.floor(Math.random() * range);
}
var shadersSource = {
VertexShader : {
type : "VERTEX_SHADER",
source : `
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
vec2 zeroToOne = a_position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_texCoord = a_texCoord;
}`
},
FragmentShader : {
type : "FRAGMENT_SHADER",
source : `
precision mediump float;
uniform sampler2D u_image;
uniform float time;
uniform float phase;
uniform float amount;
varying vec2 v_texCoord;
vec2 offset;
float dist;
float edge;
float v;
vec2 pos1 = vec2(0.5 + sin(phase * 0.03)*1.3, 0.5 + cos(phase * 0.032)*1.3);
vec2 pos2 = vec2(0.5 + cos(phase * 0.013)*1.3,0.5 + cos(phase*0.012)*1.3);
void main() {
dist = distance(pos1,v_texCoord) * distance(pos2,v_texCoord);
edge = 1. - distance(vec2(0.5,0.5),v_texCoord) / 0.707;
v = time * dist * 0.0001 * edge * phase;
offset = vec2(
v_texCoord.x + sin(v+time) * 0.1 * edge * amount,
v_texCoord.y + cos(v+time) * 0.1 * edge * amount
);
//offset = smoothstep(v_texCoord.x,offset.x,abs(0.5-v_textCoord.x) );
gl_FragColor = texture2D(u_image, offset);
}`
}
}
var md = 0;
var mr = 0;
var mdy = 0;
var mry = 0;
function webGLRender(){
var gl = webGL.gl;
md += (mouse.x / canvas.width - mr) * 0.16;
md *= 0.18;
mr += md;
mdy += (mouse.y - mry) * 0.16;
mdy *= 0.18;
mry += mdy;
gl.uniform1f(webGL.locs.timer, globalTime/100);
gl.uniform1f(webGL.locs.phase, mr * 400);
gl.uniform1f(webGL.locs.amount, ((mry/canvas.height)) * 9);
gl.drawArrays(gl.TRIANGLES, 0, 6);
ctx.drawImage(webGL,0,0, canvas.width, canvas.height);
}
var image = document.createElement("canvas");
image.width = 1024;
image.height = 512;
image.ctx = image.getContext("2d");
image.ctx.font = "192px Arial";
image.ctx.textAlign = "center";
image.ctx.textBaseline = "middle";
image.ctx.lineJoin = "round";
image.ctx.lineWidth = 32;
image.ctx.strokeStyle = "red";
image.ctx.fillStyle = "black";
image.ctx.strokeText("WOBBLE",512,256);
image.ctx.lineWidth = 16;
image.ctx.strokeStyle = "white";
image.ctx.strokeText("WOBBLE",512,256);
image.ctx.fillText("WOBBLE",512,256);
image.ctx.font = "32px Arial";
image.ctx.fillText("Mouse position on image controls wobble",512,32);
image.ctx.fillText("Using WebGL and 2D Canvas",512,512-32);
startWebGL(image);
/*var image = new Image(); // load image
image.src = "/image/C7qq2.png?s=328&g=1"; // MUST BE SAME DOMAIN!!!
image.onload = function() {
startWebGL(image);
}*/
关于javascript - JavaScript 中的文本涂抹效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38960486/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!