Webprogramozás
Horváth Győző
Egyetemi docens
1117 Budapest, Pázmány Péter sétány 1/c., 2.408-as szoba
Tel: (1) 372-2500/8469
horvath.gyozo@inf.elte.hu
window
Browser Object Model
window
function hello() {
console.log('Hello');
}
window.hello()
// Unintentional global variable
function sideEffect() {
let aVeryBigVariable
aVeryBigvariable = 12; // window.aVeryBigvariable
}
sideEffect()
console.log(aVeryBigvariable);
console.log(window.aVeryBigvariable);
// strict mode
function sideEffectStrict() {
"use strict"
let anotherVeryBigVariable
anotherVeryBigvariable = 12;
}
sideEffectStrict()
console.log(anotherVeryBigvariable);
window.open()
, window.close()
opener
window
objektumvar w = window.open('http://www.elte.hu', 'ELTEablak', 'width=800,height=600,scrollbars=yes')
w.document.querySelector(p) // Cross-origin policy!
w.resizeTo(400, 200)
w.opener
w.close()
window.location
– betöltött oldal URL-je
hash
, host
, hostname
, href
, origin
, pathname
, port
, protocol
, search
, username
, password
// http://webprogramozas.inf.elte.hu:8080/webfejl2.html?alma=piros#valami
const l = window.location;
l.host; //"webprogramozas.inf.elte.hu:8080"
l.hostname; //"webprogramozas.inf.elte.hu"
l.href; //az egész URL
l.origin; //"http://webprogramozas.inf.elte.hu:8080"
l.pathname; //"/webfejl2.html"
l.port; //"8080"
l.protocol; //"http:"
l.search; //"?alma=piros"
l.hash; //"#valami"
assign(url)
replace(url)
reload()
hashchange
window.location = "http://www.elte.hu";
window.location.href = "http://www.elte.hu";
window.location.assign("http://www.elte.hu");
window.location.replace("http://www.elte.hu");
window.location.reload();
Közlekedés
window.history
back()
forward()
go(n)
window.history.back();
window.history.forward();
window.history.go(-3);
Módosítás
window.history.pushState(stateObj, name, url)
window.history.replaceState(stateObj, name, url)
window.onpopstate
eseménywindow.onpopstate = function(e) {
console.log("location: " + document.location + ", state: " + JSON.stringify(e.state));
};
history.pushState({page: 1}, "title 1", "?page=1");
history.pushState({page: 2}, "title 2", "?page=2");
history.replaceState({page: 3}, "title 3", "?page=3");
history.back(); // logs "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // logs "location: http://example.com/example.html, state: null"
history.go(2); // logs "location: http://example.com/example.html?page=3, state: {"page":3}"
window.parent
iframe.contentWindow
iframe.contentWindow.document
/ iframe.contentDocument
postMessage()
, message
esemény<iframe src="http://localhost:8081/window.postmessage.iframe.html"></iframe>
// parent window
window.addEventListener('load', function () {
const iframe = document.querySelector('iframe')
iframe.contentWindow.postMessage("message", "http://localhost:8081")
})
window.addEventListener('message', function (e) {
console.log(e.origin, e.data)
})
// iframe
window.addEventListener('message', function (e) {
if (e.origin === "http://localhost:8080") {
console.log(e.data)
window.parent.postMessage('message back', 'http://localhost:8080')
}
})
setTimeout
, clearTimeout
setInterval
, clearInterval
requestAnimationFrame
, cancelAnimationFrame
requestIdleCallback
, cancelIdleCallback
name
fullscreen
load
, unload
abort
, close
contextmenu
resize
, scroll
, select
storage
copy
, cut
, paste
alert
, confirm
, prompt
atob
, btoa
(base64 kódolás)matchMedia
print
postMessage
stop
fetch
<canvas width="200" height="200"></canvas>
// 2D rajzolói környezet
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
fillRect(x,y,width,height)
strokeRect(x,y,width,height)
clearRect(x,y,width,height)
moveTo(x, y)
lineTo(x, y)
beginPath()
closePath()
stroke()
fill()
arc(x, y, radius, startAngle, endAngle, anticlockwise)
quadraticCurveTo(cp1x, cp1y, x, y)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
ctx.fillRect(5, 5, 20, 100)
ctx.strokeRect(30, 5, 20, 100)
ctx.beginPath()
ctx.rect(110, 5, 20, 100)
ctx.moveTo(130, 5)
ctx.lineTo(160, 35)
ctx.lineTo(130, 65)
ctx.stroke()
ctx.beginPath()
ctx.arc(200, 50, 30, 0, 2 * Math.PI)
ctx.fill()
ctx.beginPath()
ctx.moveTo(5, 200)
ctx.quadraticCurveTo(55, 100, 105, 200)
ctx.closePath()
ctx.stroke()
ctx.beginPath()
ctx.moveTo(105, 200)
ctx.bezierCurveTo(105, 130, 200, 150, 200, 90)
ctx.lineTo(190, 90)
ctx.lineTo(200, 80)
ctx.lineTo(210, 90)
ctx.lineTo(200, 90)
ctx.stroke()
<img>
const img=document.createElement('img');
drawImage(image, x, y)
drawImage(image, x, y, width, height)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
fillText(str, x, y)
strokeText(str, x, y)
fillStyle=color
strokeStyle=color
globalAlpha=value
lineWidth=value
globalCompositeOperation=type
clip()
const plane = document.createElement('img')
plane.src = 'plane.png'
plane.addEventListener('load', draw)
function draw() {
const gradSky = ctx.createLinearGradient(200, 0, 200, 300)
gradSky.addColorStop(0, 'lightblue')
gradSky.addColorStop(0.5, 'orange')
gradSky.addColorStop(1, '#444444')
const gradMountain = ctx.createLinearGradient(200, 60, 200, 300)
gradMountain.addColorStop(0, 'white')
gradMountain.addColorStop(0.2, 'white')
gradMountain.addColorStop(0.7, '#5555aa')
gradMountain.addColorStop(1, 'green')
ctx.fillStyle = gradSky
ctx.fillRect(0, 0, 400, 300)
ctx.beginPath()
ctx.fillStyle = gradMountain
ctx.moveTo(0, 300)
ctx.lineTo(0, 200)
ctx.lineTo(100, 100)
ctx.lineTo(100, 100)
ctx.lineTo(220, 160)
ctx.lineTo(330, 60)
ctx.lineTo(400, 100)
ctx.lineTo(400, 300)
ctx.closePath()
ctx.fill()
ctx.drawImage(plane, 30, 40, 70, 50)
}
save()
restore()
translate(x,y)
rotate(angle)
scale(x,y)
transform(m11,m12,m21,m22,dx,dy)
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
ctx.save();
ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
ctx.translate(10 + j * 50, 10 + i * 50);
ctx.fillRect(0, 0, 25, 25);
ctx.restore();
}
}
const mainloop = function() {
window.requestAnimationFrame(mainloop);
update();
draw();
};
function update() {
// Állapottér változtatása
}
function draw() {
// Állapottér kirajzolása
}
let lastTime = performance.now()
function mainloop(now = performance.now()) {
window.requestAnimationFrame(mainloop)
const dt = (now - lastTime) / 1000
lastTime = now
update(dt)
draw()
}
mainloop()
v = s / t
ds = v * dt
a = v / t
dv = a * dt
const box = {
x: 50, y: 50,
vx: random(50, 200), vy: random(50, 200),
width: 30, height: 30,
}
function update(dt) {
box.x += box.vx * dt
box.y += box.vy * dt
if (box.x + box.width > canvas.width) {
box.x = 2 * (canvas.width - box.width) - box.x
box.vx *= -1
}
if (box.x < 0) {
box.x *= -1
box.vx *= -1
}
if (box.y + box.height > canvas.height) {
box.y = 2 * (canvas.height - box.height) - box.y
box.vy *= -1
}
if (box.y < 0) {
box.y *= -1
box.vy *= -1
}
}
function draw() {
// clear
ctx.clearRect(0, 0, canvas.width, canvas.height)
// draw box
ctx.fillRect(box.x, box.y, box.width, box.height)
}
class Entity {
constructor(canvas, ctx) {
this.canvas = canvas
this.ctx = ctx
}
update(dt) {
}
draw() {
}
}
class Box {
constructor(canvas, ctx, {x = 50, y = 50, vx = random(50, 200), vy = random(50, 200), width = 30, height = 30} = {}) {
Object.assign(this, {canvas, ctx, x, y, vx, vy, width, height})
}
update(dt) {
this.x += this.vx * dt
this.y += this.vy * dt
if (this.x + this.width > this.canvas.width) {
this.x = 2 * (this.canvas.width - this.width) - this.x
this.vx *= -1
}
if (this.x < 0) {
this.x *= -1
this.vx *= -1
}
if (this.y + this.height > this.canvas.height) {
this.y = 2 * (this.canvas.height - this.height) - this.y
this.vy *= -1
}
if (this.y < 0) {
this.y *= -1
this.vy *= -1
}
}
draw() {
// draw box
this.ctx.fillRect(this.x, this.y, this.width, this.height)
}
}
class Game {
constructor() {
this.canvas = document.querySelector('canvas')
this.ctx = this.canvas.getContext('2d')
this.lastTime = performance.now()
this.box = new Box(this.canvas, this.ctx)
}
start() {
this.mainloop()
}
mainloop = (now = performance.now()) => {
window.requestAnimationFrame(this.mainloop)
const dt = (now - this.lastTime) / 1000
this.lastTime = now
this.update(dt)
this.draw()
}
update(dt) {
this.box.update(dt)
}
draw() {
// clear
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
// box
this.box.draw()
}
}
(new Game()).start()
const sprite = {
currentFrame: 0,
image: new Image(),
frameCount: 16,
frameTime: 0.03,
elapsedTime: 0,
}
function update(dt) {
sprite.elapsedTime += dt
if (sprite.elapsedTime > sprite.frameTime) {
sprite.currentFrame = (sprite.currentFrame + 1) % sprite.frameCount
sprite.elapsedTime -= sprite.frameTime
}
}
function draw() {
// clear
ctx.clearRect(0, 0, canvas.width, canvas.height)
// draw sprite
ctx.drawImage(sprite.image,
(sprite.currentFrame % 4) * 128, Math.floor(sprite.currentFrame / 4) * 128, 127, 127,
canvas.width / 2 - 64, canvas.height / 2 - 64, 128, 128);
}
function init() {
sprite.image.src = 'spritesheet.png'
sprite.image.addEventListener('load', function () {
mainloop()
})
}
init()
const sprite = {
currentFrame: 0,
image: new Image(),
frameCount: 16,
frameTime: 0.03,
elapsedTime: 0,
x: 50,
vx: 150,
direction: 1,
}
function update(dt) {
sprite.elapsedTime += dt
sprite.x += sprite.direction * sprite.vx * dt
if (sprite.elapsedTime > sprite.frameTime) {
sprite.currentFrame = (sprite.currentFrame + 1) % sprite.frameCount
sprite.elapsedTime -= sprite.frameTime
}
if (sprite.x + 32 > canvas.width || sprite.x - 32 < 0) {
sprite.direction *= -1
}
}
function draw() {
// clear
ctx.clearRect(0, 0, canvas.width, canvas.height)
// draw sprite
ctx.save()
ctx.translate(sprite.x, canvas.height / 2 - 32)
ctx.scale(sprite.direction, 1)
ctx.drawImage(sprite.image,
(sprite.currentFrame % 4) * 128, Math.floor(sprite.currentFrame / 4) * 128, 127, 127,
-32, -32, 64, 64);
ctx.restore()
}
isPointInPath()
isPointInStroke()
addHitRegion()
removeHitRegion()
clearHitRegions()
const gl = document.getElementById("canvas").getContext("webgl");
gl.viewport(0, 0, canvas.width, canvas.height);
//...
<html>
<svg width="300px" height="300px">
<defs>
<linearGradient id="myGradient" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="5%" stop-color="red"></stop>
<stop offset="95%" stop-color="blue" stop-opacity="0.5"></stop>
</linearGradient>
</defs>
<circle id="myCircle" class="important" cx="50%" cy="50%" r="100"
fill="url(#myGradient)" onmousedown="alert('hello');"/>
</svg>
</html>
https://developer.mozilla.org/en-US/docs/Web/API
https://developer.mozilla.org/en-US/docs/Web/Media
localStorage
sessionStorage
//Tárolás
localStorage.alma = 'piros';
localStorage['bármi'] = 42;
//Elővétel (akár újratöltés után)
console.log(localStorage.alma);
console.log(localStorage['bármi']);
//Összetett adatszerkezetek tárolás
const x = [1, 3, 5, 7];
localStorage.setItem('adat', JSON.stringify(x));
const x2 = JSON.parse( localStorage.getItem('adat') );
HTMLAudioElement
play()
, pause()
, …<audio src="horn3.wav" id="audio1" controls></audio>
// meglévő elem
document.querySelector('audio').play();
// in-memory elem
const audio = document.createElement('audio');
audio.src = 'horn3.wav';
audio.play();
<video>
tagHTMLVideoElement
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const video = document.querySelector('video')
const mainloop = function() {
window.requestAnimationFrame(mainloop);
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
}
mainloop()
let deg = 0;
const mainloop = function() {
window.requestAnimationFrame(mainloop);
deg += 0.01
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.save()
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.scale(0.5, 0.5)
ctx.rotate(deg)
ctx.drawImage(video, -canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height)
ctx.restore()
}
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const image = document.querySelector('img')
const video = document.querySelector('video')
const red = document.querySelector('#red')
const green = document.querySelector('#green')
const blue = document.querySelector('#blue')
navigator.mediaDevices.getUserMedia({video: true})
.then(function(mediaStream) {
image.src = mediaStream
video.srcObject = mediaStream
video.addEventListener('loadeddata', function () {
video.play()
mainloop()
})
})
.catch(function(err) { console.log(err.name + ": " + err.message) })
const mainloop = function() {
if (video.paused || video.ended) {
return
}
window.requestAnimationFrame(mainloop);
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
processImage()
}
function processImage() {
let frame = ctx.getImageData(0, 0, canvas.width, canvas.height);
let l = frame.data.length / 4;
for (let i = 0; i < l; i++) {
let r = frame.data[i * 4 + 0];
let g = frame.data[i * 4 + 1];
let b = frame.data[i * 4 + 2];
if (g > green.valueAsNumber && r > red.valueAsNumber && b > blue.valueAsNumber)
frame.data[i * 4 + 3] = 0;
}
ctx.putImageData(frame, 0, 0);
}
//főszál
const worker = new Worker('masik.js');
worker.onmessage = function(e) {
console.log(e.data);
};
worker.postMessage('valami');
//masik.js
self.onmessage = function(e) {
self.postMessage("Kapott adat: " + e.data);
};
draggable="true"
dragstart
, dragenter
, dragover
, drop
, stb. eseményekevent.dataTransfer
setData
setDragImage
effectAllowed
dropEffect
draggable
attribútumdragstart
esemény: drag adatok tárolásadragover
esemény: dropzone kijelölésedragleave
esemény: dropzone elhagyásadrop
esemény: ejtésdragend
esemény: drag adatok alaphelyzetbewindow
this
kontextusa