Làm thế nào tôi có thể làm động các bản vẽ văn bản trên một trang web?


229

Tôi muốn có một trang web có một từ trung tâm.

Tôi muốn từ này được vẽ bằng một hình ảnh động, sao cho trang "viết" từ đó giống như cách chúng ta sẽ làm, tức là nó bắt đầu tại một điểm và vẽ các đường và đường cong theo thời gian sao cho kết quả cuối cùng là một glyph.

Tôi không quan tâm nếu điều này được thực hiện với <canvas>hoặc DOM và tôi không quan tâm liệu nó được thực hiện với JavaScript hay CSS. Sự vắng mặt của jQuery sẽ tốt, nhưng không bắt buộc.

Tôi có thể làm cái này như thế nào? Tôi đã tìm kiếm một cách thấu đáo mà không có may mắn.


2
Tôi đã suy nghĩ về cách thực sự "viết tay" các ký tự và đăng suy nghĩ của mình ở đây: stackoverflow.com/questions/12700731/ chủ
markE

Có một cái gì đó thực sự tương tự trong một bài viết về tiền mã hóa (với bản demo ở tympanus )
Francisco Presencia

1
Ngày trước, tôi đã thực hiện hoạt hình này trong Flash bằng mặt nạ hoạt hình. Những gì bạn cần là để làm động một mặt nạ, có nghĩa là để nó dần dần tiết lộ văn bản. Các hình ảnh động sẽ được làm bằng khung mặt nạ.
Tiberiu-Ionuț Stan

Tất nhiên, bạn sẽ có lợi ích khi nuôi ong có thể phá vỡ văn bản thành các đường cong. Bạn sẽ phải thực hiện việc này bằng cách sử dụng các SVG và một số trình soạn thảo SVG (Illustrator hoặc bất cứ thứ gì khác có thể tạo ra một SVG của văn bản của bạn). Tôi không biết nếu các SVG hỗ trợ mặt nạ, nhưng nếu có, điều này sẽ trở nên dễ dàng hơn để hoạt hình.
Tiberiu-Ionuț Stan

Sử dụng SVG và thao tác mã SVG với JavaScript để tạo hiệu ứng động.
Demz 04/05/2015

Câu trả lời:


264

Tôi muốn từ này được vẽ bằng một hình ảnh động, sao cho trang "viết" từ đó giống như cách chúng ta sẽ

Phiên bản vải

Điều này sẽ vẽ các ký tự đơn giống như người ta sẽ viết bằng tay. Nó sử dụng mô hình dấu gạch ngang dài trong đó thứ tự bật / tắt được hoán đổi theo thời gian trên mỗi char. Nó cũng có một tham số tốc độ.

Ảnh chụp nhanh
Ví dụ hoạt hình (xem bản demo bên dưới)

Để tăng tính chân thực và cảm giác hữu cơ, tôi đã thêm khoảng cách chữ ngẫu nhiên, độ lệch y delta, độ trong suốt, góc xoay rất tinh tế và cuối cùng sử dụng phông chữ "viết tay". Chúng có thể được gói thành các tham số động để cung cấp một loạt các "kiểu viết".

Đối với một cái nhìn thực tế hơn nữa, dữ liệu đường dẫn sẽ được yêu cầu theo mặc định. Nhưng đây là một đoạn mã ngắn và hiệu quả, xấp xỉ hành vi viết tay và dễ thực hiện.

Làm thế nào nó hoạt động

Bằng cách xác định một mẫu gạch ngang, chúng ta có thể tạo ra những con kiến ​​diễu hành, những đường chấm chấm v.v. Tận dụng lợi thế này bằng cách xác định một chấm rất dài cho dấu chấm "tắt" và tăng dần dấu chấm "bật", nó sẽ tạo ảo giác vẽ đường thẳng khi được vuốt trong khi tạo hiệu ứng cho chiều dài của chấm.

Vì dấu chấm quá dài nên mẫu lặp lại sẽ không hiển thị (độ dài sẽ thay đổi theo kích thước và đặc điểm của kiểu chữ được sử dụng). Đường dẫn của chữ cái sẽ có độ dài, vì vậy chúng tôi cần đảm bảo rằng chúng tôi có mỗi dấu chấm ít nhất bao phủ chiều dài này.

Đối với các chữ cái bao gồm nhiều hơn một đường dẫn (ví dụ: O, R, P, v.v.) như một dành cho phác thảo, một là cho phần rỗng, các dòng sẽ xuất hiện để được vẽ đồng thời. Chúng ta không thể làm gì nhiều với điều đó với kỹ thuật này vì nó sẽ yêu cầu quyền truy cập vào từng đoạn đường dẫn được vuốt riêng.

Khả năng tương thích

Đối với các trình duyệt không hỗ trợ phần tử canvas, một cách khác để hiển thị văn bản có thể được đặt giữa các thẻ, ví dụ: văn bản được tạo kiểu:

<canvas ...>
    <div class="txtStyle">STROKE-ON CANVAS</div>
</canvas>

Bản giới thiệu

Điều này tạo ra đột quỵ hoạt hình trực tiếp ( không phụ thuộc ) -

var ctx = document.querySelector("canvas").getContext("2d"),
    dashLen = 220, dashOffset = dashLen, speed = 5,
    txt = "STROKE-ON CANVAS", x = 30, i = 0;

ctx.font = "50px Comic Sans MS, cursive, TSCu_Comic, sans-serif"; 
ctx.lineWidth = 5; ctx.lineJoin = "round"; ctx.globalAlpha = 2/3;
ctx.strokeStyle = ctx.fillStyle = "#1f2f90";

(function loop() {
  ctx.clearRect(x, 0, 60, 150);
  ctx.setLineDash([dashLen - dashOffset, dashOffset - speed]); // create a long dash mask
  dashOffset -= speed;                                         // reduce dash length
  ctx.strokeText(txt[i], x, 90);                               // stroke letter

  if (dashOffset > 0) requestAnimationFrame(loop);             // animate
  else {
    ctx.fillText(txt[i], x, 90);                               // fill final letter
    dashOffset = dashLen;                                      // prep next char
    x += ctx.measureText(txt[i++]).width + ctx.lineWidth * Math.random();
    ctx.setTransform(1, 0, 0, 1, 0, 3 * Math.random());        // random y-delta
    ctx.rotate(Math.random() * 0.005);                         // random rotation
    if (i < txt.length) requestAnimationFrame(loop);
  }
})();
canvas {background:url(http://i.imgur.com/5RIXWIE.png)}
<canvas width=630></canvas>


21
Tôi có phải là người duy nhất phát điên vì điều này? Trông rất thật, ít nhất, tốt hơn câu trả lời đầu tiên và gần nhất với câu hỏi của người hỏi.
KhoPhi

5
Cuối cùng tôi đã sử dụng câu trả lời khác, bởi vì tôi cần nó ngay lập tức như một bản hack nhanh và bẩn mà tôi đã sử dụng vào ngày hôm sau và sau đó không bao giờ chạm vào nữa, nhưng tôi chấp nhận nó vì nó gần với những gì tôi đang tìm kiếm cho
strugee

Làm thế nào chúng ta có thể làm cho nó cho nhiều dòng và một khối văn bản dài?
Saad Farooq

1
@ K3N Vâng, đó thực sự là một liên lạc tốt đẹp: p Công việc tuyệt vời.
keyer 20/05/2015

1
@ AliAl-arnous bạn có thể đặt x ở đầu đối diện, trừ chiều rộng char thay vì thêm, biến đổi với không gian âm bị phủ định và thay đổi ClearRect để xóa ở phía bên kia của char.

216

Chỉnh sửa 2019


Tôi đã tạo một thư viện javascript có thể tạo hình ảnh động thực tế. Thật dễ sử dụng và yêu cầu một tệp JSON đặc biệt hoạt động như phông chữ.

var vara = new Vara("#container", "https://rawcdn.githack.com/akzhy/Vara/ed6ab92fdf196596266ae76867c415fa659eb348/fonts/Satisfy/SatisfySL.json", [{
  text: "Hello World!!",
  fontSize: 48,
  y:10
}, {
  text: "Realistic Animations",
  fontSize: 34,
  color:"#f44336"
}], {
  strokeWidth: 2,
  textAlign:"center"
});
#container {
  padding: 30px;
}
<script src="https://rawcdn.githack.com/akzhy/Vara/16e30acca2872212e28735cfdbaba696a355c780/src/vara.min.js"></script>
<div id="container"></div>

Kiểm tra trang Github để biết tài liệu và ví dụ. Và Codepen


Trả lời trước

Ví dụ dưới đây sử dụng snap.js để tạo động tspancác phần tử và sau đó tạo hiệu ứng cho từng phần tử của chúng stroke-dashoffset.

Trả lời trước


Bạn có thể làm một cái gì đó như thế này bằng cách sử dụng stroke-dasharray

Không có keyframeshoạt hình bạn có thể làm một cái gì đó như thế này

Và để hỗ trợ IE, bạn có thể sử dụng jquery / javascript


4
Wow, điều đó thực sự thú vị. Tôi đã lấy đoạn mã gốc của bạn và cải thiện nó bằng cách nào đó bằng cách xóa các thuộc tính CSS trùng lặp, sử dụng giá trị bù trừ dựa trên tỷ lệ phần trăm và giá trị dasharray và thay đổi độ rộng nét để làm rõ hơn cách mã hoạt động: jsfiddle.net/Ajedi32/gdc4azLn / 1 Hãy thoải mái chỉnh sửa bất kỳ cải tiến nào trong câu trả lời của bạn nếu bạn muốn.
Ajedi32

2
đây là một giải pháp tuyệt vời cho câu hỏi này, SVG tốt hơn canvas (+1) cho đến khi trong trường hợp trình duyệt không hỗ trợ thì nó sẽ hiển thị văn bản thay thế.
Jeffery ThaGintoki 04/05/2015

3
@JefferyThaGintoki bạn cũng có thể làm điều này với canvas, chỉ cần đặt văn bản giữa các thẻ canvas, nếu canvas không hỗ trợ văn bản (hoặc gif hoạt hình như trong câu trả lời khác hiển thị trong văn bản cơ thể) sẽ xuất hiện. Nếu trình duyệt không hỗ trợ canvas, có lẽ nó cũng sẽ không hỗ trợ svg.
torox

1
Tôi nghĩ rằng việc sử dụng văn bản SVG là tuyệt vời, tuy nhiên tôi đang tự hỏi, liệu có thể thêm điền vào một lúc nào đó không? chỉ là phác thảo của các chữ cái trông không đẹp trong tất cả các dự án, chúc mừng! và tất nhiên +1 cho câu trả lời này
Randomguy04

1
@ Randomguy04 Kiểm tra đoạn mã đầu tiên, tôi đã chỉnh sửa nó để thêm hiệu ứng điền. Nó được thực hiện bằng cách thêm vào $(this).css('fill', 'red')như một cuộc gọi lại cho hình ảnh động
Akshay

2

Chỉ CSS:

@keyframes fadein_left {
  from {
    left: 0;
  }
  to {
    left: 100%;
  }
}

#start:before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0%;
  opacity: 0.7;
  height: 25px;
  background: #fff;
  animation: fadein_left 3s;
}
<div id="start">
  some text some text some text some text some text
</div>


0

Sau nhiều thử nghiệm, đây là một số lưu ý. Mục tiêu là hiển thị dữ liệu văn bản nhanh theo cách ít chặn nhất, trên các trang nặng DOM yêu cầu người dùng tương tác.

Tất nhiên có nhiều cách để đạt được điều tương tự. Trong ví dụ này, sự khác biệt có thể không rõ ràng, nó thực sự áp dụng cho các giao diện phức tạp.

Chậm nhất : innerHTMLvà kiểu dáng nội tuyến. DOM được tính toán lại ở mỗi lần lặp. Trình duyệt đang làm việc chăm chỉ để giữ cho tàu. Nó sẽ thất bại nhanh chóng, gây rò rỉ bộ nhớ và đóng băng:

setInterval(function(){
  out.innerHTML = `<span style="position:fixed;top:${~~(Math.random() * 220)}px">${Math.random() * 1000}<span>`
},1)
<h1 id="out"></h1>

Cách tốt hơn : Sử dụng textContent, requestAnimationFramevà các api hoạt hình web. Điều này diễn ra suôn sẻ hơn, rõ ràng trên các trang nặng DOM. Các tương tác người dùng sẽ không chặn các bản phát lại. Một số lần sơn lại có thể được bỏ qua, để giữ cho giao diện phản hồi tốt.

let job
const paint = () => {
  job = requestAnimationFrame(paint)
  out.textContent = Math.random() * 1000
  out.animate([{top: ~~(Math.random() * 220)+"px"},{top:0}],{duration: 1,iterations: 1})
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(paint)
#out{
position: fixed}
<h1 id="out"></h1>

Trong ví dụ trên, DOM vẫn đang được tính toán lại cho lỗi tràn văn bản .. Chúng ta có thể thấy trình gỡ lỗi nhấp nháy khó khăn. Điều này thực sự quan trọng về các yếu tố xếp tầng! Điều này vẫn có thể làm chậm javascript và cuộn người dùng.

nhập mô tả hình ảnh ở đây

Toàn bộ sức mạnh : Có thể sử dụng css một mình để làm mới dữ liệu với contentquy tắc css và các biến css. Các văn bản sẽ không được lựa chọn.

let job
const paint = () => {
  job = requestAnimationFrame(paint)
  out.setAttribute('data-before', Math.random() * 1000)
  out.animate([{top: ~~(Math.random() * 220)+"px"},{top:0}],{duration: 1,iterations: 1})
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(paint)
#out{
  position: fixed
  
  }
#out:before {
   content: attr(data-before)
 }
<h1 id="out"></h1>

nhập mô tả hình ảnh ở đây

Các thử nghiệm của tôi cho thấy những cải tiến tuyệt vời, công cụ javascript đang bỏ qua nhanh chóng các tác vụ khác. Đôi khi nó có thể bắt đầu chậm hơn một chút so với ví dụ trên. Nhưng bên cạnh đó, điều này không chặn người dùng cuộn và trình gỡ lỗi cũng thích, không còn nhảy nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.