ฉันจะทำให้ภาพวาดของข้อความเคลื่อนไหวบนหน้าเว็บได้อย่างไร


229

ฉันต้องการมีหน้าเว็บที่มีคำที่กึ่งกลางหนึ่งคำ

ฉันต้องการให้คำนี้วาดด้วยอนิเมชั่นเช่นที่หน้า "เขียน" คำนั้นในลักษณะเดียวกับที่เราต้องการคือมันเริ่มต้นที่จุดหนึ่งแล้วลากเส้นและเส้นโค้งเมื่อเวลาผ่านไปซึ่งผลลัพธ์สุดท้ายคือ glyph

ฉันไม่สนใจว่าสิ่งนี้จะทำด้วย<canvas>หรือ DOM และฉันไม่สนใจว่ามันจะทำกับ JavaScript หรือ CSS การขาดงานของ jQuery จะดี แต่ไม่จำเป็น

ฉันจะทำสิ่งนี้ได้อย่างไร ฉันค้นหาอย่างละเอียดโดยไม่มีโชค


2
ฉันใส่ความคิดลงไปในวิธีการ "เขียนด้วยลายมือ" ตัวละครจริงและโพสต์ความคิดของฉันที่นี่: stackoverflow.com/questions/12700731/ …
เครื่องหมาย

มีบางสิ่งที่คล้ายกันมากในบทความ codrops (ด้วยการสาธิตในไข้รากสาดใหญ่ )
Francisco Presencia

1
ย้อนกลับไปในวันนี้ฉันทำแอนิเมชั่นนี้ใน Flash โดยใช้หน้ากากสไปรท์ สิ่งที่คุณต้องทำก็คือการใช้หน้ากากเพื่อเคลื่อนไหวข้อความซึ่งหมายถึงการเปิดเผยข้อความอย่างต่อเนื่อง อนิเมชั่นจะทำจากเฟรมมาสก์
Tiberiu-Ionuț Stan

แน่นอนคุณจะได้รับประโยชน์จาก beeing ที่สามารถแบ่งข้อความเป็นเส้นโค้ง คุณจะต้องใช้วิธีนี้ก่อนใช้ตัวคัดกรอง SVG และตัวแก้ไข SVG บางตัว (Illustrator หรืออะไรก็ตามที่สามารถสร้าง SVG สำหรับข้อความของคุณ) ฉันไม่รู้ว่า SVG สนับสนุนรูปแบบการสวมหน้ากากหรือไม่ แต่ถ้าเป็นแบบนี้จะทำให้เคลื่อนไหวได้ง่ายขึ้น
Tiberiu-Ionuț Stan

ใช้ SVG และจัดการรหัส SVG ด้วย JavaScript เพื่อสร้างภาพเคลื่อนไหว
Demz

คำตอบ:


264

ฉันต้องการให้วาดคำนี้ด้วยภาพเคลื่อนไหวเช่นที่หน้า "เขียน" คำนั้นออกมาในลักษณะเดียวกับที่เราต้องการ

รุ่น Canvas

นี้จะวาดตัวอักษรเดียวมากกว่าที่คนเขียนด้วยมือ มันใช้รูปแบบเส้นประยาวที่สลับเปิด / ปิดในช่วงเวลาต่อถ่าน นอกจากนี้ยังมีพารามิเตอร์ความเร็ว

ภาพรวม
ตัวอย่างภาพเคลื่อนไหว (ดูตัวอย่างด้านล่าง)

เพื่อเพิ่มความสมจริงและความรู้สึกแบบอินทรีย์ฉันเพิ่มระยะห่างตัวอักษรแบบสุ่ม y delta offset ความโปร่งใสการหมุนที่ละเอียดมากและในที่สุดก็ใช้แบบอักษร "ลายมือ" ที่มีอยู่แล้ว สิ่งเหล่านี้สามารถสรุปเป็นพารามิเตอร์แบบไดนามิกเพื่อให้ "สไตล์การเขียน" ที่หลากหลาย

เพื่อให้ดูสมจริงยิ่งขึ้นข้อมูลเส้นทางจะต้องใช้ซึ่งไม่ใช่ค่าเริ่มต้น แต่นี่เป็นโค้ดสั้น ๆ และมีประสิทธิภาพซึ่งใกล้เคียงกับพฤติกรรมการเขียนด้วยมือและใช้งานง่าย

มันทำงานอย่างไร

โดยการกำหนดรูปแบบเส้นประเราสามารถสร้างมดเดินทัพเส้นประและอื่น ๆ การใช้ประโยชน์จากสิ่งนี้โดยการกำหนดจุดที่ยาวมากสำหรับจุด "ปิด" และค่อยๆเพิ่มจุด "เปิด" มันจะให้ภาพลวงตาของการวาดเส้นบนเมื่อลูบในขณะที่เคลื่อนไหวความยาวจุด

เนื่องจากจุดปิดยาวเกินไปรูปแบบการทำซ้ำจะไม่ปรากฏให้เห็น (ความยาวจะแตกต่างกันไปตามขนาดและลักษณะของแบบอักษรที่ใช้) เส้นทางของจดหมายจะมีความยาวดังนั้นเราต้องตรวจสอบให้แน่ใจว่าเรามีจุดแต่ละจุดอย่างน้อยครอบคลุมความยาวนี้

สำหรับตัวอักษรที่ประกอบด้วยมากกว่าหนึ่งเส้นทาง (f.ex. O, R, P ฯลฯ ) ตามที่หนึ่งสำหรับโครงร่างหนึ่งสำหรับส่วนกลวงเส้นจะปรากฏขึ้นพร้อมกัน เราไม่สามารถทำสิ่งนี้ได้มากนักด้วยเทคนิคนี้เนื่องจากต้องการการเข้าถึงแต่ละเซกเมนต์ของเส้นทางที่จะถูกแยกจากกัน

ความเข้ากันได้

สำหรับเบราว์เซอร์ที่ไม่สนับสนุนองค์ประกอบภาพวาดคุณสามารถวางวิธีอื่นในการแสดงข้อความระหว่างแท็กตัวอย่างเช่นข้อความสไตล์:

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

การสาธิต

สิ่งนี้สร้างจังหวะการเคลื่อนไหวแบบเคลื่อนไหวได้ ( ไม่มีการขึ้นต่อกัน ) -

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
ฉันเป็นคนเดียวที่คลั่งไคล้ในเรื่องนี้หรือไม่? ดูเหมือนจริงอย่างน้อยก็ดีกว่าคำตอบแรกและใกล้เคียงกับคำถามของผู้ถาม
KhopPhi

5
ฉันลงเอยด้วยการใช้คำตอบอื่นเพราะฉันต้องการแฮ็คอย่างรวดเร็วและสกปรกที่ฉันใช้ในวันถัดไปและไม่เคยแตะอีกครั้ง แต่ฉันยอมรับมันเพราะใกล้กับสิ่งที่ฉันมอง สำหรับ.
strugee

เราจะสร้างมันสำหรับหลายบรรทัดและบล็อกข้อความยาว ๆ ได้อย่างไร?
Saad Farooq

1
@ K3N ใช่มันเป็นสัมผัสที่ดีจริงๆ: p ใช้งานได้ดีมาก
keyser

1
@ AliAl-arnous คุณสามารถตั้งค่า x เป็นส่วนตรงข้ามลบความกว้างถ่านแทนการเพิ่มแปลงด้วยพื้นที่เชิงลบเมื่อตะกี้และเปลี่ยน clearRect เพื่อล้างด้านอื่น ๆ ของถ่าน

216

แก้ไข 2019


ฉันสร้างไลบรารีจาวาสคริปต์ที่สามารถสร้างภาพเคลื่อนไหวที่เหมือนจริงได้ มันใช้งานง่ายและต้องการไฟล์ JSON พิเศษที่ทำหน้าที่เป็นตัวอักษร

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>

ชำระเงินที่หน้า Githubสำหรับเอกสารและตัวอย่าง และCodepen


คำตอบก่อนหน้า

ด้านล่างนี้เป็นตัวอย่างการใช้ snap.js สร้างแบบไดนามิกองค์ประกอบแล้วเคลื่อนไหวแต่ละของพวกเขาtspanstroke-dashoffset

คำตอบก่อนหน้า


คุณสามารถทำสิ่งนี้โดยใช้ svg stroke-dasharray

หากไม่มีkeyframesภาพเคลื่อนไหวคุณสามารถทำสิ่งนี้ได้

และสำหรับการรองรับ IE คุณสามารถใช้ jquery / javascript


4
ว้าวมันน่าสนใจจริงๆ ฉันใช้ข้อมูลโค้ดต้นฉบับของคุณและปรับปรุงให้ดีขึ้นโดยการลบคุณสมบัติ CSS ที่ซ้ำกันโดยใช้เปอร์เซ็นต์ออฟเซ็ตและค่า dasharray และเปลี่ยนความกว้างของลายเส้นเพื่อให้ชัดเจนยิ่งขึ้นว่าโค้ดทำงานอย่างไร: jsfiddle.net/Ajedi32/gdc4azLn / 1อย่าลังเลที่จะแก้ไขการปรับปรุงเหล่านี้ในคำตอบของคุณหากคุณต้องการ
Ajedi32

2
นี่เป็นหนึ่งในโซลูชันที่ยิ่งใหญ่สำหรับคำถามนี้ SVG ดีกว่า canvas (+1) เท่าที่ในกรณีที่เบราว์เซอร์ไม่รองรับมันจะแสดงข้อความแทน
Jeffery ThaGintoki

3
@JefferyThaGintoki คุณสามารถทำสิ่งนี้ได้ด้วย Canvas เช่นกันเพียงแค่วางข้อความระหว่างแท็กผ้าใบหากผ้าใบไม่รองรับข้อความ (หรือ gif แบบเคลื่อนไหวเช่นเดียวกับคำตอบอื่น ๆ ที่แสดงในเนื้อความ) จะปรากฏขึ้นแทน หากเบราว์เซอร์ไม่รองรับ Canvas ก็อาจจะไม่รองรับ svg เช่นกัน
torox

1
ฉันคิดว่าการใช้ข้อความ SVG นั้นยอดเยี่ยม แต่ฉันสงสัยว่ามันเป็นไปได้หรือไม่ที่จะเพิ่มส่วนเติมลงในบางจุด? เพียงโครงร่างของตัวอักษรไม่ได้ดูดีในทุกโครงการไชโย! และแน่นอน +1 กับคำตอบนี้
randomguy04

1
@ randomguy04 ตรวจสอบตัวอย่างแรกฉันได้แก้ไขเพื่อเพิ่มเอฟเฟ็กต์การเติม มันทำโดยการเพิ่ม$(this).css('fill', 'red')เป็นการโทรกลับไปยังภาพเคลื่อนไหว
Akshay

2

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

ติดตามการทดสอบมากมายต่อไปนี้เป็นหมายเหตุบางประการ เป้าหมายคือการแสดงข้อมูลข้อความอย่างรวดเร็วในวิธีการบล็อกน้อยที่สุดบนหน้าเว็บขนาดใหญ่ของ DOM ที่ต้องการการโต้ตอบกับผู้ใช้

แน่นอนว่ามีหลายวิธีในการบรรลุสิ่งเดียวกัน ในตัวอย่างนี้ความแตกต่างอาจไม่ชัดเจนมันนำไปใช้กับอินเทอร์เฟซที่ซับซ้อนจริงๆ

ช้าที่สุด : innerHTMLและใส่สไตล์แบบอินไลน์ DOM ถูกคำนวณใหม่ในการทำซ้ำแต่ละครั้ง เบราว์เซอร์ทำงานหนักเพื่อดูแลรถไฟ มันจะล้มเหลวอย่างรวดเร็วทำให้เกิดการรั่วไหลของหน่วยความจำและค้าง:

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

วิธีที่ดีกว่า : การใช้textContent, requestAnimationFrameและ API เว็บภาพเคลื่อนไหว สิ่งนี้จะราบรื่นขึ้นอย่างเห็นได้ชัดบน DOM หนาเพจ การโต้ตอบของผู้ใช้จะไม่บล็อก repaints บาง repaints อาจถูกข้ามไปเพื่อให้อินเทอร์เฟซตอบสนองได้ดี

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>

จากตัวอย่างด้านบน DOM ยังคงถูกคำนวณใหม่สำหรับการโอเวอร์โฟลว์ข้อความ .. เราสามารถเห็นตัวดีบักกะพริบอย่างหนัก เรื่องนี้สำคัญมากสำหรับองค์ประกอบเรียงซ้อน! การทำเช่นนี้อาจทำให้ javascript และการเลื่อนผู้ใช้ช้าลง

ป้อนคำอธิบายรูปภาพที่นี่

อำนาจเต็ม : เป็นไปได้ที่จะใช้ css เพียงอย่างเดียวเพื่อรีเฟรชข้อมูลด้วยcontentกฎ css และตัวแปร css ข้อความจะไม่สามารถเลือกได้

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>

ป้อนคำอธิบายรูปภาพที่นี่

การทดสอบของฉันแสดงให้เห็นถึงการปรับปรุงที่ดีเยี่ยมเครื่องยนต์ javascript กำลังกระโดดข้ามงานอื่นอย่างรวดเร็ว บางครั้งมันอาจเริ่มช้ากว่าตัวอย่างด้านบนเล็กน้อย แต่นอกเหนือจากนั้นสิ่งนี้จะไม่บล็อกการเลื่อนของผู้ใช้และตัวดีบักก็ชื่นชอบเช่นกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.