Страницы

Поиск по вопросам

Показаны сообщения с ярлыком html5-canvas. Показать все сообщения
Показаны сообщения с ярлыком html5-canvas. Показать все сообщения

воскресенье, 9 февраля 2020 г.

Анимация абстракции

#javascript #анимация #canvas #html5_canvas


Есть вот такая абстракция



знаю что через canvas такое анимируется, но не силен в данной области, может кто
видел или знает как анимировать?
    


Ответы

Ответ 1



Примерная анимация на Three.js var planeVertShader = ` #define PI 3.1415926 uniform float time; uniform float amplitude; uniform float waveLength; uniform vec3 pos; uniform float timeSpeed; uniform float planeHeight; uniform float initRotation; uniform float speedRotation; varying vec3 varPos; void main() { vec3 p = position + pos + vec3(0., .1, 0.); float wLength = 1. / waveLength; float heightNormal = position.y / planeHeight; float oneRound = heightNormal * PI * 4.; //вращение p.y += sin(p.x * wLength + time) * cos(p.z * wLength + time) * amplitude; p.x = cos(-time * speedRotation + oneRound + initRotation) * position.x; p.z = sin(-time * speedRotation + oneRound + initRotation) * position.x; //скручивание p.x += cos(-time * speedRotation + oneRound) * heightNormal * 5.; p.z += sin(-time * speedRotation + oneRound) * heightNormal * 5.; p += pos + vec3(0., .1, 0.); varPos = position; vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 ); gl_Position = projectionMatrix * mvPosition; } `; var planeFragShader = ` void main() { gl_FragColor = vec4(0.366,0.048,0.515,1.000); } `; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); camera.position.set(0, 25, 150); camera.rotation.set(0, 0, 1.57); var renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setClearColor(0x000000); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); window.addEventListener('resize', function () { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }, false); // plane var planes = []; var planeHeight = 125; var planeWidth = 15; var planeGeom = new THREE.PlaneBufferGeometry(planeWidth, planeHeight, 15, 100); planeGeom.translate(4, 0, 0); for (let i = 0; i < 2; i++) { let pos = new THREE.Vector3(0, 10, 110); let plane = new THREE.LineSegments(planeGeom, new THREE.ShaderMaterial({ uniforms: { time: { value: 0 }, amplitude: { value: 5 }, waveLength: { value: Math.PI * 5 }, pos: { value: pos }, timeSpeed: { value: THREE.Math.randFloat(Math.PI * .5, Math.PI) }, planeHeight: { value: planeHeight }, initRotation: { value: THREE.Math.randFloat(0, Math.PI) }, speedRotation: { value: THREE.Math.randFloat(Math.PI * 0.5, Math.PI) } }, vertexShader: planeVertShader, fragmentShader: planeFragShader })); scene.add(plane); planes.push(plane) } var clock = new THREE.Clock(); var t = 0; var delta = 0; render(); function render() { requestAnimationFrame(render); delta = clock.getDelta(); t += delta; planes.forEach(sw => { sw.material.uniforms.time.value = t }); renderer.render(scene, camera); } body { overflow: hidden; margin: 0; }


Ответ 2



WebGL. Поверхность задана при помощи signed distance, на нее наложен математический шум, который сдвигается со временем. Поверхность находится при помощи raymarch, все это дело вычисляется во фрагментном шейдере. let canvas = document.querySelector('canvas'); let gl = canvas.getContext('webgl'); let pid = gl.createProgram(); shader(` attribute vec2 coords; void main(void) { gl_Position = vec4(coords.xy, 0.0, 1.0); } `, gl.VERTEX_SHADER); shader(` precision highp float; uniform vec4 mr; uniform float time; #define rot(a) mat2(cos(a),-sin(a),sin(a),cos(a)) #define hash31(p) fract(sin(dot(p,vec3(127.1,311.7, 74.7)))*43758.5453123) float noise3(vec3 p) { vec3 i = floor(p); vec3 f = fract(p); f = f*f*(3.-2.*f); return mix( mix( mix(hash31(i+vec3(0,0,0)), hash31(i+vec3(1,0,0)),f.x), mix(hash31(i+vec3(0,1,0)), hash31(i+vec3(1,1,0)),f.x), f.y), mix( mix(hash31(i+vec3(0,0,1)), hash31(i+vec3(1,0,1)),f.x), mix(hash31(i+vec3(0,1,1)), hash31(i+vec3(1,1,1)),f.x), f.y), f.z); } float fbm3(vec3 p) { float v = 0., a = .5; mat2 R = rot(.37); for (int i = 0; i < 2; i++) { p *= 2.; a /= 2.; p.xy *= R; p.yz *= R; v += a * noise3(p); } return v; } float map( in vec3 pos ){ return pos.y + fbm3(vec3(pos.x+time,pos.yz)); } float rayMarch( in vec3 ro, in vec3 rd, float tmax ){ float t = 0.0; float h = (1.0-ro.y)/rd.y; for( int i=0; i<10; i++ ){ vec3 pos = ro + t*rd; float h = map( pos ); if( h<0.001 || t>tmax ) break; t += h; } return t; } vec3 render( in vec3 ro, in vec3 rd ) { vec3 col = vec3(0.); float t = rayMarch( ro, rd, 10. ); vec3 pos = ro + t*rd; vec2 scp = sin(23.*pos.xz); col += 2.0*exp(-5.0*abs(scp.x)); col += 2.0*exp(-5.0*abs(scp.y)); return col*0.5*exp(-0.1*t*t); } mat3 setCamera( in vec3 ro, in vec3 rt, in float cr ) { vec3 cw = normalize(rt-ro); vec3 cp = vec3(sin(cr), cos(cr),0.0); vec3 cu = normalize( cross(cw,cp) ); vec3 cv = normalize( cross(cu,cw) ); return mat3( cu, cv, -cw ); } void main(void) { vec2 uv = gl_FragCoord.xy/mr.zw; vec2 p = uv-0.5; float an = time*0.5 + 6.0*mr.x/mr.z; vec3 ro = vec3( 2.0*cos(an), 1.0, 2.0*sin(an) ); vec3 rt = vec3( 1.0, 0.0, 0.0 ); mat3 cam = setCamera( ro, rt, 0.35 ); vec3 rd = normalize( cam * vec3( p, -1.0) ); vec3 c = render( ro, rd )*vec3( 0.3, 0.4, 0.8 ); gl_FragColor = vec4(c, 1.0 ); } `, gl.FRAGMENT_SHADER); gl.linkProgram(pid); gl.useProgram(pid); let array = new Float32Array([-1, 3, -1, -1, 3, -1]); gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); let coords = gl.getAttribLocation(pid, "coords"); gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(coords); let mr = gl.getUniformLocation(pid, 'mr'); let time = gl.getUniformLocation(pid, 'time'); let x = 0, y = 0; let changeCenter = e => { e = e.touches ? e.touches[0] : e; let z = window.getComputedStyle(canvas).zoom || 1; let d = document.documentElement; x = (e.clientX + d.scrollLeft - canvas.offsetLeft*z) / z; y = (e.clientY + d.scrollTop - canvas.offsetTop*z) / z } window.addEventListener('mousemove', e => changeCenter(e)); window.addEventListener('touchmove', e => changeCenter(e)); window.addEventListener('resize', resize); resize(); function draw(t) { gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.clearColor(0, 0, 0, 0); gl.uniform4f(mr, x, y, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.uniform1f(time, t/1000); gl.drawArrays(gl.TRIANGLES, 0, 3); requestAnimationFrame(draw) } function shader(src, type) { let sid = gl.createShader(type); gl.shaderSource(sid, src); gl.compileShader(sid); var message = gl.getShaderInfoLog(sid); gl.attachShader(pid, sid); if (message.length > 0) { console.log(src.split('\n').map(function (str, i) { return ("" + (1 + i)).padStart(4, "0") + ": " + str }).join('\n')); throw message; } } function resize(){ canvas.width = window.innerWidth; canvas.height = window.innerHeight; draw(); }

суббота, 11 января 2020 г.

Как сделать захват момента видео с помощью JavaScript

#javascript #html #canvas #html5_canvas


Есть довольно интересный вопрос: как я могу захватить конкретный момент видео (с
помощью скриншота самого момента конечно) и нарисовать его прямо в 
не создавая отдельное изображение (которе и содержит этот скриншот) в той же папке?

Цель:

Есть окно preview в блоке .preview-section который при ховере показывает таймкод
того момента, по которому я вожу мышкой. Так вот мне надо захватить этот момент видео
и нарисовать его в canvas. 

PS. Нужно решение без jQuery.

Предупреждение: код ну ооочень длинный, так что извините за ваши глаза: 



var vid, playPauseButton, seekSlider, currentTime, vidDuration, muteButton, volumeSlider,
fullScreenToggler, loop, fullscreenHider;
var mainVideo, timeCodeContainer, frameContainer, previewBox;



function intializePlayer(){
"use strict"; 
	
// Set object references  
vid = document.getElementById("vid");
mainVideo = document.getElementsByClassName('mainVideo')[0];
playPauseButton = document.getElementById("playPauseButton");
seekSlider = document.getElementById("seekSlider");
currentTime = document.getElementById("done");
vidDuration = document.getElementById("duration");
muteButton = document.getElementById("muteUnmute");
volumeSlider = document.getElementById("volumeSlider");
fullScreenToggler = document.getElementById("toggleFullScreen");
loop = document.getElementById("loop");
fullscreenHider = document.getElementById("exitFullScreen");
previewBox = document.getElementsByClassName("preview-section")[0];	
timeCodeContainer = document.getElementById("timeCodeContainer");
frameContainer = document.getElementById("frameContainer");	
// Add event listeners
playPauseButton.addEventListener("click",playPauseVideo,false);
seekSlider.addEventListener("input",timeSlider,false);
seekSlider.addEventListener("mousemove",sliderHoverValue,false);
seekSlider.addEventListener("mouseout",previewBoxFadeOut,false);
vid.addEventListener("timeupdate",videoTimeUpdate,false);
muteButton.addEventListener("click",muteUnmute,false);
volumeSlider.addEventListener("input",volumeChange,false);
volumeSlider.addEventListener("input",toggleIcon,false);
fullScreenToggler.addEventListener("click",enterFullScreen,false);
fullscreenHider.addEventListener("click",exitFullScreen,false);
document.addEventListener('webkitfullscreenchange', exitHandler, false);
document.addEventListener('mozfullscreenchange', exitHandler, false);
document.addEventListener('fullscreenchange', exitHandler, false);
document.addEventListener('MSFullscreenChange', exitHandler, false);  
loop.addEventListener("click",loopVideo,false);
//Add some other settings
vid.controls = false;
vid.oncontextmenu = function(){return false;};
}

window.onload = intializePlayer;

//Secondary functions 
function videoFSstyling(video,videoBox){
  video.style.width = "100%"
  video.style.height = "auto";
  videoBox.style.width = "100%";
  videoBox.style.height = "auto"}
	
function videoNotFSstyling(video,videoBox){
  video.removeAttribute("style");
  videoBox.removeAttribute("style"); 	
}	

function fadeIn(el){
  el.classList.add('show');
  el.classList.remove('hide');  }

function fadeOut(el){
  el.classList.add('hide');
  el.classList.remove('show');}	
	
var valueHover = 0;
function calcSliderPos(e) {
    return (e.offsetX / e.target.clientWidth) *  parseInt(e.target.getAttribute('max'),10);
}	
	
//Video Functions
function exitHandler(){
"use strict";
  if (document.webkitIsFullScreen === false || document.mozFullScreen === false ||
document.msFullscreenElement === false){
   videoNotFSstyling(vid,mainVideo);	  
   document.getElementsByClassName("videoControls")[0].classList.remove("fullscreen");  
    fullscreenHider.style.display = "none";
  fullScreenToggler.style.display = "inline-block";}
}
	
function playPauseVideo(){
"use strict";
  if(vid.paused){
    document.title = "►" + " " + document.title;
    vid.play();
    playPauseButton.innerHTML = '';}
  else {
    vid.pause();
    playPauseButton.innerHTML = '';}
}
	
function timeSlider(){
"use strict";
  var slideTo = vid.duration * (seekSlider.value / 100);
  vid.currentTime = slideTo;
}
	
function videoTimeUpdate(){
"use strict";
  var timeInterval = vid.currentTime * (100 / vid.duration);
  seekSlider.value = timeInterval;
  var currentMinutes = Math.floor(vid.currentTime / 60);
  var currentSeconds = Math.floor(vid.currentTime - currentMinutes * 60);
  var durationMinutes = Math.floor(vid.duration / 60);
  var durationSeconds = Math.floor(vid.duration - durationMinutes * 60);
  if(currentSeconds < 10) {currentSeconds = "0"+ currentSeconds;}
  if(durationSeconds < 10) {durationSeconds = "0"+ durationSeconds;}
  if(currentMinutes < 10) {currentMinutes = "0"+ currentMinutes;}
  if(durationMinutes < 10) {durationMinutes = "0"+ durationMinutes;}
  currentTime.innerHTML = currentMinutes + ":" + currentSeconds; 
  vidDuration.innerHTML = durationMinutes + ":" + durationSeconds;
}
	
function sliderHoverValue(e){
"use strict";
	valueHover = Math.round(calcSliderPos(e));
	var currentHoverTime = vid.duration * (valueHover / 100);
	var hoverTimeMinutes, hoverTimeSeconds; 
	currentHoverTime = Math.floor(currentHoverTime);

	hoverTimeMinutes = Math.floor(currentHoverTime / 60);
	hoverTimeSeconds = Math.floor(currentHoverTime - hoverTimeMinutes * 60);
	
	if(hoverTimeMinutes < 10){hoverTimeMinutes = "0" + hoverTimeMinutes;}
	if(hoverTimeSeconds < 10){hoverTimeSeconds = "0" + hoverTimeSeconds}
	
	timeCodeContainer.innerHTML = hoverTimeMinutes + ":" + hoverTimeSeconds;
	if(currentHoverTime > Math.floor(vid.duration)){
		timeCodeContainer.innerHTML = vidDuration.innerHTML;}
	if(currentHoverTime < 0){timeCodeContainer.innerHTML = "00:00";}
	fadeIn(previewBox);
	var translateXpos = parseFloat(calcSliderPos(e).toFixed(4));
	var translateToPosition = ((translateXpos * seekSlider.clientWidth / 100).toFixed(4));
	if(translateXpos < 0){
		previewBox.setAttribute("style","transform: translate(0%, -106%) !important;");
	}
	else if(translateXpos > seekSlider.clientWidth || parseFloat(translateToPosition)
> seekSlider.clientWidth){
		previewBox.setAttribute("style","transform: translate(" + seekSlider.clientWidth
+ "px" + ", -106%) !important;");
	}
	else {
    previewBox.setAttribute("style","transform: translate(" + translateToPosition
+ "px" + ", -106%) !important;");}
}	
	
function previewBoxFadeOut(){fadeOut(previewBox);}	
	
function volumeChange(){
"use strict";
  vid.volume = volumeSlider.value / 100;
}

function enterFullScreen(){
"use strict";
  
  if(mainVideo.requestFullScreen){
    mainVideo.requestFullScreen();
    videoFSstyling(vid,mainVideo);}
  else if(mainVideo.webkitRequestFullScreen){
    mainVideo.webkitRequestFullScreen();
    videoFSstyling(vid,mainVideo);}
  else if(mainVideo.mozRequestFullScreen){
    mainVideo.mozRequestFullScreen();
    videoFSstyling(vid,mainVideo);}
  else if(mainVideo.oRequestFullScreen){
    mainVideo.oRequestFullScreen();
    videoFSstyling(vid,mainVideo);}
  else if(mainVideo.msRequestFullScreen){
    mainVideo.msRequestFullScreen();
    videoFSstyling(vid,mainVideo);}
  document.getElementsByClassName("videoControls")[0].classList.add("fullscreen");

  fullScreenToggler.style.display = "none";
  fullscreenHider.style.display = "inline-block";
}

function exitFullScreen(){
"use strict"; 
  if(document.cancelFullScreen){
    document.cancelFullScreen();
    videoNotFSstyling(vid,mainVideo);}
  else if(document.webkitCancelFullScreen){
    document.webkitCancelFullScreen();
    videoNotFSstyling(vid,mainVideo);}
  else if(document.mozCancelFullScreen){
    document.mozCancelFullScreen();
    videoNotFSstyling(vid,mainVideo);}
  else if(document.oCancelFullScreen){
    document.oCancelFullScreen();
    videoNotFSstyling(vid,mainVideo);}
  else if(document.msCancelFullScreenn){
    document.msCancelFullScreen();
    videoNotFSstyling(vid,mainVideo);}
    document.getElementsByClassName("videoControls")[0].classList.remove("fullscreen");
	
   fullscreenHider.style.display = "none";
   fullScreenToggler.style.display = "inline-block";
}

function loopVideo(){
"use strict"; 
  if(!loop.hasAttribute("style")){
    loop.setAttribute("style","opacity: 1; color: rgba(22,206,170,1.00);");
    vid.setAttribute("loop","");  
  }
  else {
    loop.removeAttribute("style");
    vid.removeAttribute("loop");
  }
}
	
function toggleIcon(){
"use strict"; 
if(vid.volume <= 0.01){
    muteButton.innerHTML = '';}
else if(vid.volume <= 0.42){
  muteButton.innerHTML = '';}  
else {
  muteButton.innerHTML = '';
}
}
	
var prev_level;

function muteUnmute(){
"use strict";
  if(vid.volume >= 0.03){
    prev_level = volumeSlider.value;
    volumeSlider.value = 0;
    vid.volume = volumeSlider.value;
    toggleIcon();
  }
    else if(vid.volume <= 0.05){
    volumeSlider.value= prev_level;
    vid.volume = volumeSlider.value / 100;
    toggleIcon();
  }
}

//KeyPress Fuctions

function pressSpaceToStart(e){
 "use strict"; 
  if(e.keyCode === 32){
     e.preventDefault();
       playPauseVideo();}
}
window.onkeypress = function(o){"use strict"; pressSpaceToStart(o);};
window.onkeydown = function(o){"use strict"; pressSpaceToStart(o);};
button:focus {outline: none !important;}	
input:focus	 {outline: none !important;} 
	  
video::-webkit-media-controls, video::-webkit-media-controls-enclosure {display:none
!important;}
section.videoSection {width: 100%; margin: auto; margin-top: 30px;}
div.mainVideo {text-align: center; width: 454px; margin: auto} 
div.mainVideo:-webkit-full-screen {background-color: transparent !important;}	  
div.mainVideo video {width: 450px; border: 2px solid black; border-bottom: 0}
div.videoControls {width: 450px; margin: -5px auto 0px; background-color: rgba(67,41,82,0.97);
padding: 10px 0px 8px 0px; border: 2px solid black; color: snow; border-bottom-left-radius:
12px; border-bottom-right-radius: 12px;}
div.videoControls button {background-color: transparent; border: 0; opacity: 0.8;}
div.videoControls span {position: relative;}
div.videoControls button:hover {opacity: 1;}
div.preview-section {position: absolute; width: 100px; height: 70px; transform: translate(0%,
-106%); margin-left: -44.5px; opacity: 0;}
div.preview-section * {cursor: default;}	  
div.preview-box {position: relative; width: 100px; height: 70px; background-image:
linear-gradient(to top, #252323, rgba(0, 0, 0, 0.86));
-webkit-background-image: linear-gradient(to top, #252323, rgba(0, 0, 0, 0.86)); 
-moz-background-image: linear-gradient(to top, #252323, rgba(0, 0, 0, 0.86)); 
-o-background-image: linear-gradient(to top, #252323, rgba(0, 0, 0, 0.86));	
-ms-background-image: linear-gradient(to top, #252323, rgba(0, 0, 0, 0.86));	
border: 1px solid rgba(0,0,0,0.84); box-sizing: border-box; border-bottom: 0; box-shadow:
inset 0 0 0 2px #363131;
-webkit-box-shadow: inset 0 0 0 2px #363131; -moz-box-shadow: inset 0 0 0 2px #363131;
-ms-box-shadow: inset 0 0 0 2px #363131;
-o-box-shadow: inset 0 0 0 2px #363131;}
div.preview-box #frameContainer {width: 96%; height: 58px; background: #E0E0E0; margin:
1px auto 0px;}
div.preview-box #timeCodeContainer {font-size: 0.70em; background-color: rgba(23,22,22,.76);
text-align: center; position: absolute; color: white; left: 50%; top: 86%; transform:
translate(-50%, -100%); overflow: hidden; display: inline-block; padding: 0px 3px}	  
	  
/* Slider Styling */  
input[type=range] {-webkit-appearance: none; margin: 5.8px 0; background-color: transparent
!important;}

input[type=range]:focus {outline: none;}

input[type=range]::-webkit-slider-runnable-track {cursor: pointer; box-shadow: 2.4px
2.4px 6.2px rgba(7, 7, 163, 0.72), 0px 0px 2.4px rgba(8, 8, 187, 0.72); background:
#ac62ff; border-radius: 21.6px; border: 1px solid rgba(163, 0, 255, 0.79);}

input[type=range]::-webkit-slider-thumb {box-shadow: 2.4px 2.4px 9.5px rgba(4, 16,
14, 0.78), 0px 0px 2.4px rgba(9, 36, 32, 0.78); border: 1.8px solid rgba(0, 0, 6, 0.77);
border-radius: 28px; background: #ffff29; cursor: pointer; -webkit-appearance: none;
margin-top: -7.8px;}

input[type=range]:focus::-webkit-slider-runnable-track {background: #b16cff;}

input[type=range]::-moz-range-track {width: 100%; cursor: pointer; box-shadow: 2.4px
2.4px 6.2px rgba(7, 7, 163, 0.72), 0px 0px 2.4px rgba(8, 8, 187, 0.72); background:
#ac62ff; border-radius: 21.6px; border: 1px solid rgba(163, 0, 255, 0.79);}

input[type=range]::-moz-range-thumb {box-shadow: 2.4px 2.4px 9.5px rgba(4, 16, 14,
0.78), 0px 0px 2.4px rgba(9, 36, 32, 0.78); border: 1.8px solid rgba(0, 0, 6, 0.77);
border-radius: 28px; background: #ffff29; cursor: pointer;}

input[type=range]::-ms-track {width: 100%; cursor: pointer; background: transparent;
border-color: transparent; color: transparent;}

input[type=range]::-ms-fill-lower {background: #a758ff; border: 1px solid rgba(163,
0, 255, 0.79); border-radius: 43.2px; box-shadow: 2.4px 2.4px 6.2px rgba(7, 7, 163,
0.72), 0px 0px 2.4px rgba(8, 8, 187, 0.72);}

input[type=range]::-ms-fill-upper {background: #ac62ff; border: 1px solid rgba(163,
0, 255, 0.79); border-radius: 43.2px; box-shadow: 2.4px 2.4px 6.2px rgba(7, 7, 163,
0.72), 0px 0px 2.4px rgba(8, 8, 187, 0.72);}

input[type=range]::-ms-thumb {box-shadow: 2.4px 2.4px 9.5px rgba(4, 16, 14, 0.78),
0px 0px 2.4px rgba(9, 36, 32, 0.78); border: 1.8px solid rgba(0, 0, 6, 0.77); border-radius:
28px; background: #ffff29; cursor: pointer;}

input[type=range]:focus::-ms-fill-lower {background: #ac62ff;}

input[type=range]:focus::-ms-fill-upper {background: #b16cff;}

/* Animationg fadeIn and fadeOut styles */	  
.show {opacity: 1 !important; transition: opacity 400ms;}

.hide {opacity: 0 !important; transition: opacity 400ms;}	 
	  
/* Non fullscreen track and thumb width and height */

/* Track */
.videoControls input[type=range]::-webkit-slider-runnable-track {height: 6.4px;}
.videoControls input[type=range]::-moz-range-track {height: 6.4px;}
.videoControls input[type=range]::-ms-track {height: 6.4px;}

/* Thumb */
.videoControls input[type=range]::-webkit-slider-thumb {height: 20px; width: 8px;}
.videoControls input[type=range]::-moz-range-thumb {height: 20px; width: 8px;}
.videoControls input[type=range]::-ms-thumb {height: 20px; width: 8px;}

/* Video Controls Buttons Styling */
#playPauseButton {float: left; margin: -3px 1px 0px 3px;}
#loop {float: left; margin: 4px 5px 25px 3px;}
#seekContainer {width: 150px; float: left;}	  
#seekSlider {width: 100%; margin: 10px 5px 0px -1px;}
div.mainVideo span {color: snow; font-size: 0.97em; display: inline-block; float:
left; margin: 2.5px 0px 0px 1px;}
#muteUnmute {margin-top: -5px; float: left;}
#volumeSlider {width: 64px; margin: 10px 0px 0px 0px; float: left;}
#toggleFullScreen {margin: 0px 0px 0px 4px;}

/* Fullscreen settings -START-*/

.fullscreen {z-index: 2789034264 !important; position: absolute !important; width:
80% !important; bottom: 5.7% !important; left: 10% !important; right: 10% !important;
height: 35px !important;}
.fullscreen button i {font-size: 2.5em !important;}
.fullscreen button#playPauseButton {margin-left: 0.2% !important; float: left !important;}
.fullscreen #seekContainer {width: 48% !important; margin-left: 2px !important;} 
.fullscreen button#muteUnmute {margin-left: 0.5%; font-size: 0.98em; margin-top: -10px;}
.fullscreen span {font-size: 1.2em !important;}
.fullscreen input#volumeSlider {width: 12%; margin-left: 1%;}
#exitFullScreen {margin-left: 0.5%; margin-top: -3px;}

/* Fullscreen track and thumb width and height */

/* Track */
.fullscreen input[type=range]::-webkit-slider-runnable-track {height: 12.8px;}
.fullscreen input[type=range]::-moz-range-track {height: 12.8px;}
.fullscreen input[type=range]::-ms-track {height: 12.8px;}

/* Thumb */
.fullscreen input[type=range]::-webkit-slider-thumb {height: 32px; width: 12px; margin-top:
-10px;}
.fullscreen input[type=range]::-moz-range-thumb {height: 32px; width: 12px; margin-top:
-10px;}
.fullscreen input[type=range]::-ms-thumb {height: 32px; width: 12px; margin-top: -10px;}



00:00 / 00:00
00:00


Ответы

Ответ 1



у канвы есть метод drawImage. Погуглите. Вот пример с первой же ссылки function grabScreenshot() { ctx.drawImage(video, 0, 0, videoWidth, videoHeight); var img = new Image(); img.src = canvas.toDataURL("image/png"); img.width = 120; ssContainer.appendChild(img); }

Ответ 2



Как вариант: это мотнуть видео на заданное время, сделать скрин и мотнуть обратно. А чтобы всё это дело не видел пользователь, мотайте на клоне video. Но всё это шляпа, по хорошему надо использовать превьюшки в спайте. var $video = $("video"); var $slider = $(".slider"); var $span = $("span"); var $canvas = $("canvas"); var context = $canvas[0].getContext('2d'); $video.on("loadedmetadata", function() { $slider.data("duration", $video[0].duration); console.log($video[0].duration); }); var last_second = 0; var save_second = 0; $slider.on("mousemove", function(e) { var max = $slider.width(); var relX = e.pageX; var time = Math.round($(this).data("duration") * e.pageX / max); if(time != last_second) { last_second = time; console.log(Math.round(relX / max * 100)); $span.css("left", Math.round(relX / max * 100) + "%"); $video[0].currentTime = time; setTimeout(function() { context.drawImage($video[0], 0, 0, 150, 100); }, 300); } }).hover(function() {}, function() { var max = $slider.width(); $video[0].currentTime = save_second; var dur_per = save_second * 100 / $(this).data("duration"); var width = dur_per * max; console.log(width); $span.css("left", width + "%"); }); .slider { position: absolute; height: 50px; background: blue; top:0; left:0; width: 100%; } span { position: absolute; width: 20px; height: 20px; background: red; top: 15px; } canvas { background: black; width: 150px; min-height: 100px; margin-top: 30px; display: none; border: 1px black solid; } .slider:hover canvas { display: block; }


воскресенье, 15 декабря 2019 г.

Поворот текста на Canvas

#javascript #html5 #canvas #html5_canvas


Есть Canvas, на котором отрисовывается изображение. 
На изображение можно накладывать текст. Можно выбирать угол наклона текста. 
Изображение можно перемещать по канвасу. 
Суть в том, что перемещение изображения работает нормально, но текст должен перемещаться
вместе с ним. Однако, так как canvas.context в момент отрисовки текста под углом повернут,
оси x и y для текста получаются смещенными. То есть, если повернуть текст на 90 градусов,
а потом потянуть картинку вниз/вверх, то текст уедет вправо/влево.

Как можно это исправить? Чтобы текст перемещался вместе с картинкой? 

Отрисовка изображения:

    ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY,
img.width, img.height);


Отрисовка текста поверх изображения:

    ctx.save();
    var offsetX = textObj.x;
    var offsetY = textObj.y;

    ctx.translate(offsetX, offsetY);
    ctx.rotate(textObj.rotation);
    ctx.translate(-offsetX, -offsetY);
    ctx.font = textObj.fontSize + 'px ' + textObj.font;
    ctx.fillStyle = textObj.color;

    ctx.fillText(textObj.text, textObj.x, textObj.y);
    textObj.x -= viewportOffsetX;
    textObj.y -= viewportOffsetY;

    ctx.restore();


Изменение viewportOffsetX/viewportOffsetY происходит при драге в mousemove. 

viewportOffsetX += deltaX; // смещение по X
viewportOffsetY += deltaY; // смещение по Y




var textInput = null;
var canvasImage = null;
var canvas = null;
var ctx = null;

var renderingInterval = null;
var textComponents = [];

var scale = 1;
var viewportOffsetX = 0;
var viewportOffsetY = 0;
var drag = false;
var img = null;

var text = null;
var font = 'arial';
var fontSize = 20;
var color = '#000';
var textRotation = 0;

var originX = 0;
var originY = 0;

$(document).ready(function(){
	img = new Image();
  img.src = "http://www.catster.com/wp-content/uploads/2018/01/Cat-flehmen-response.jpg";
  canvas = document.getElementById('canvas');
  ctx = canvas.getContext("2d");
  
  textComponents.push({text: 'Test', x: 0, y: 0, saved: true, font: 'arial', fontSize:
30, color: 'red', rotation: Math.PI / 2});
  
  canvas.addEventListener('mousemove', onMouseMove);
  canvas.addEventListener('touchmove', onMouseMove);
  canvas.addEventListener('mouseup', onMouseUp);
  canvas.addEventListener('touchend', onMouseUp);
  canvas.addEventListener('touchstart', onMouseDown);
  canvas.addEventListener('mousedown', onMouseDown);
  
  img.onload = function(){
    renderTextCanvas();
  };
});

function renderTextCanvas() {
    ctx.clearRect(0, 0, img.width, img.height);
    ctx.scale(scale, scale);
    ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY,
img.width, img.height);

    textComponents.forEach(function (textObj) {
        ctx.save();
        ctx.font = textObj.fontSize + 'px ' + textObj.font;
        ctx.fillStyle = textObj.color;
        ctx.rotate(textObj.rotation);
        if (textObj.saved) {
            ctx.fillText(textObj.text, textObj.x + viewportOffsetX, textObj.y + viewportOffsetY);
        }
        else {
            ctx.fillText(textObj.text, textObj.x, textObj.y);
            textObj.saved = true;
            textObj.x -= viewportOffsetX;
            textObj.y -= viewportOffsetY;
        }
        ctx.restore();
    });

}

    function onMouseUp(e) {
        drag = false;
    }

    function onMouseDown(event) {
        originX = event.pageX;
        originY = event.pageY;

        if (event.touches) {
            var touches = event.touches[0];
            originX = touches.pageX;
            originY = touches.pageY;
        }

        if (textInput) {
            var rect = canvas.getBoundingClientRect();
            var x = originX - rect.left;
            var y = originY - rect.top;
            registerTextComponent(textInput, x, y);
            textInput = null;
            return;
        }
        drag = true;
    }


    function onMouseMove(e) {
        if (drag) {
            var pageX = e.pageX;
            var pageY = e.pageY;

            if (e.touches) {
                var touches = e.touches[0];
                pageX = touches.pageX;
                pageY = touches.pageY;
            }

            var deltaX = pageX - originX;
            var deltaY = pageY - originY;

            if (Math.abs(viewportOffsetX) < Math.abs(img.width / 2)) {
                viewportOffsetX += deltaX;
            }
            else {
                if (viewportOffsetX < 0) {
                    viewportOffsetX += 1;
                }
                else {
                    viewportOffsetX -= 1;
                }
            }
            if (Math.abs(viewportOffsetY) < Math.abs(img.height / 2)) {
                viewportOffsetY += deltaY;
            }
            else {
                if (viewportOffsetY < 0) {
                    viewportOffsetY += 1;
                }
                else {
                    viewportOffsetY -= 1;
                }
            }
            originX = pageX;
            originY = pageY;
            renderTextCanvas();
        }
    }
#canvas{
  background: #ffe;
}






    


Ответы

Ответ 1



Здесь нужно пересчитывать координаты для текста с использованием матрицы поворота в двухмерном пространстве. var textInput = null; var canvasImage = null; var canvas = null; var ctx = null; var renderingInterval = null; var textComponents = []; var scale = 1; var viewportOffsetX = 0; var viewportOffsetY = 0; var drag = false; var img = null; var text = null; var font = 'arial'; var fontSize = 20; var color = '#000'; var textRotation = 0; var originX = 0; var originY = 0; $(document).ready(function() { img = new Image(); img.src = "http://www.catster.com/wp-content/uploads/2018/01/Cat-flehmen-response.jpg"; canvas = document.getElementById('canvas'); ctx = canvas.getContext("2d"); textComponents.push({ text: 'Test', x: 0, y: 0, saved: true, font: 'arial', fontSize: 30, color: 'red', rotation: Math.PI / 2 }); canvas.addEventListener('mousemove', onMouseMove); canvas.addEventListener('touchmove', onMouseMove); canvas.addEventListener('mouseup', onMouseUp); canvas.addEventListener('touchend', onMouseUp); canvas.addEventListener('touchstart', onMouseDown); canvas.addEventListener('mousedown', onMouseDown); img.onload = function() { renderTextCanvas(); }; }); function renderTextCanvas() { ctx.clearRect(0, 0, img.width, img.height); ctx.scale(scale, scale); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height); textComponents.forEach(function(textObj) { ctx.save(); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color; ctx.rotate(textObj.rotation); if (textObj.saved) { //!!!! var x = viewportOffsetX * Math.cos(textObj.rotation) + viewportOffsetY * Math.sin(textObj.rotation); var y = -viewportOffsetX * Math.sin(textObj.rotation) + viewportOffsetY * Math.cos(textObj.rotation); ctx.fillText(textObj.text, textObj.x + x, textObj.y + y); } else { ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.saved = true; textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY; } ctx.restore(); }); } function onMouseUp(e) { drag = false; } function onMouseDown(event) { originX = event.pageX; originY = event.pageY; if (event.touches) { var touches = event.touches[0]; originX = touches.pageX; originY = touches.pageY; } if (textInput) { var rect = canvas.getBoundingClientRect(); var x = originX - rect.left; var y = originY - rect.top; registerTextComponent(textInput, x, y); textInput = null; return; } drag = true; } function onMouseMove(e) { if (drag) { var pageX = e.pageX; var pageY = e.pageY; if (e.touches) { var touches = e.touches[0]; pageX = touches.pageX; pageY = touches.pageY; } var deltaX = pageX - originX; var deltaY = pageY - originY; if (Math.abs(viewportOffsetX) < Math.abs(img.width / 2)) { viewportOffsetX += deltaX; } else { if (viewportOffsetX < 0) { viewportOffsetX += 1; } else { viewportOffsetX -= 1; } } if (Math.abs(viewportOffsetY) < Math.abs(img.height / 2)) { viewportOffsetY += deltaY; } else { if (viewportOffsetY < 0) { viewportOffsetY += 1; } else { viewportOffsetY -= 1; } } originX = pageX; originY = pageY; renderTextCanvas(); } } #canvas { background: #ffe; }

пятница, 26 октября 2018 г.

Поворот текста на Canvas

Есть Canvas, на котором отрисовывается изображение. На изображение можно накладывать текст. Можно выбирать угол наклона текста. Изображение можно перемещать по канвасу. Суть в том, что перемещение изображения работает нормально, но текст должен перемещаться вместе с ним. Однако, так как canvas.context в момент отрисовки текста под углом повернут, оси x и y для текста получаются смещенными. То есть, если повернуть текст на 90 градусов, а потом потянуть картинку вниз/вверх, то текст уедет вправо/влево.
Как можно это исправить? Чтобы текст перемещался вместе с картинкой?
Отрисовка изображения:
ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height);
Отрисовка текста поверх изображения:
ctx.save(); var offsetX = textObj.x; var offsetY = textObj.y;
ctx.translate(offsetX, offsetY); ctx.rotate(textObj.rotation); ctx.translate(-offsetX, -offsetY); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color;
ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY;
ctx.restore();
Изменение viewportOffsetX/viewportOffsetY происходит при драге в mousemove.
viewportOffsetX += deltaX; // смещение по X viewportOffsetY += deltaY; // смещение по Y
var textInput = null; var canvasImage = null; var canvas = null; var ctx = null; var renderingInterval = null; var textComponents = []; var scale = 1; var viewportOffsetX = 0; var viewportOffsetY = 0; var drag = false; var img = null; var text = null; var font = 'arial'; var fontSize = 20; var color = '#000'; var textRotation = 0; var originX = 0; var originY = 0; $(document).ready(function(){ img = new Image(); img.src = "http://www.catster.com/wp-content/uploads/2018/01/Cat-flehmen-response.jpg"; canvas = document.getElementById('canvas'); ctx = canvas.getContext("2d"); textComponents.push({text: 'Test', x: 0, y: 0, saved: true, font: 'arial', fontSize: 30, color: 'red', rotation: Math.PI / 2}); canvas.addEventListener('mousemove', onMouseMove); canvas.addEventListener('touchmove', onMouseMove); canvas.addEventListener('mouseup', onMouseUp); canvas.addEventListener('touchend', onMouseUp); canvas.addEventListener('touchstart', onMouseDown); canvas.addEventListener('mousedown', onMouseDown); img.onload = function(){ renderTextCanvas(); }; }); function renderTextCanvas() { ctx.clearRect(0, 0, img.width, img.height); ctx.scale(scale, scale); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height); textComponents.forEach(function (textObj) { ctx.save(); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color; ctx.rotate(textObj.rotation); if (textObj.saved) { ctx.fillText(textObj.text, textObj.x + viewportOffsetX, textObj.y + viewportOffsetY); } else { ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.saved = true; textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY; } ctx.restore(); }); } function onMouseUp(e) { drag = false; } function onMouseDown(event) { originX = event.pageX; originY = event.pageY; if (event.touches) { var touches = event.touches[0]; originX = touches.pageX; originY = touches.pageY; } if (textInput) { var rect = canvas.getBoundingClientRect(); var x = originX - rect.left; var y = originY - rect.top; registerTextComponent(textInput, x, y); textInput = null; return; } drag = true; } function onMouseMove(e) { if (drag) { var pageX = e.pageX; var pageY = e.pageY; if (e.touches) { var touches = e.touches[0]; pageX = touches.pageX; pageY = touches.pageY; } var deltaX = pageX - originX; var deltaY = pageY - originY; if (Math.abs(viewportOffsetX) < Math.abs(img.width / 2)) { viewportOffsetX += deltaX; } else { if (viewportOffsetX < 0) { viewportOffsetX += 1; } else { viewportOffsetX -= 1; } } if (Math.abs(viewportOffsetY) < Math.abs(img.height / 2)) { viewportOffsetY += deltaY; } else { if (viewportOffsetY < 0) { viewportOffsetY += 1; } else { viewportOffsetY -= 1; } } originX = pageX; originY = pageY; renderTextCanvas(); } } #canvas{ background: #ffe; }


Ответ

Здесь нужно пересчитывать координаты для текста с использованием матрицы поворота в двухмерном пространстве.
var textInput = null; var canvasImage = null; var canvas = null; var ctx = null; var renderingInterval = null; var textComponents = []; var scale = 1; var viewportOffsetX = 0; var viewportOffsetY = 0; var drag = false; var img = null; var text = null; var font = 'arial'; var fontSize = 20; var color = '#000'; var textRotation = 0; var originX = 0; var originY = 0; $(document).ready(function() { img = new Image(); img.src = "http://www.catster.com/wp-content/uploads/2018/01/Cat-flehmen-response.jpg"; canvas = document.getElementById('canvas'); ctx = canvas.getContext("2d"); textComponents.push({ text: 'Test', x: 0, y: 0, saved: true, font: 'arial', fontSize: 30, color: 'red', rotation: Math.PI / 2 }); canvas.addEventListener('mousemove', onMouseMove); canvas.addEventListener('touchmove', onMouseMove); canvas.addEventListener('mouseup', onMouseUp); canvas.addEventListener('touchend', onMouseUp); canvas.addEventListener('touchstart', onMouseDown); canvas.addEventListener('mousedown', onMouseDown); img.onload = function() { renderTextCanvas(); }; }); function renderTextCanvas() { ctx.clearRect(0, 0, img.width, img.height); ctx.scale(scale, scale); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height); textComponents.forEach(function(textObj) { ctx.save(); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color; ctx.rotate(textObj.rotation); if (textObj.saved) { //!!!! var x = viewportOffsetX * Math.cos(textObj.rotation) + viewportOffsetY * Math.sin(textObj.rotation); var y = -viewportOffsetX * Math.sin(textObj.rotation) + viewportOffsetY * Math.cos(textObj.rotation); ctx.fillText(textObj.text, textObj.x + x, textObj.y + y); } else { ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.saved = true; textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY; } ctx.restore(); }); } function onMouseUp(e) { drag = false; } function onMouseDown(event) { originX = event.pageX; originY = event.pageY; if (event.touches) { var touches = event.touches[0]; originX = touches.pageX; originY = touches.pageY; } if (textInput) { var rect = canvas.getBoundingClientRect(); var x = originX - rect.left; var y = originY - rect.top; registerTextComponent(textInput, x, y); textInput = null; return; } drag = true; } function onMouseMove(e) { if (drag) { var pageX = e.pageX; var pageY = e.pageY; if (e.touches) { var touches = e.touches[0]; pageX = touches.pageX; pageY = touches.pageY; } var deltaX = pageX - originX; var deltaY = pageY - originY; if (Math.abs(viewportOffsetX) < Math.abs(img.width / 2)) { viewportOffsetX += deltaX; } else { if (viewportOffsetX < 0) { viewportOffsetX += 1; } else { viewportOffsetX -= 1; } } if (Math.abs(viewportOffsetY) < Math.abs(img.height / 2)) { viewportOffsetY += deltaY; } else { if (viewportOffsetY < 0) { viewportOffsetY += 1; } else { viewportOffsetY -= 1; } } originX = pageX; originY = pageY; renderTextCanvas(); } } #canvas { background: #ffe; }