javascript - El dibujo en lienzo lleva mucho tiempo en Safari pero no en Chrome o FF
html5 html5-canvas (3)
Con respecto a toda la optimización hecha a su código, y al hecho de que en safari todavía tiene una tasa de cuadros cercana a cero. Intenté modificar la imagen que usas, para reducir el tamaño (calidad jpg 60, 30, 10), cambiar el formato de la imagen (png24, png8), cambiar el tamaño de la imagen (250x500 en lugar de 750x1500) y todos esos cambios no cambiaron nada . Todavía se está retrasando mucho.
Luego traté de encontrar algunos puntos de referencia hechos con Safari Canvas. Encontré esta tabla que muestra que las actuaciones de Safari con lienzo no son las mejores.
Puedes ver el artículo completo de referencia here
Creo que al final, incluso después de la optimización realizada por @Jorge Fuentes González, su código sigue siendo lento en Safari, entonces tal vez haya una razón y esté en el núcleo del motor Webkit.
Estoy haciendo un caleidoscopio en mi sitio web. Todo lo que hace es tomar una imagen (ya sea a través de Arrastrar y soltar o una imagen predeterminada en la carga) y copiarla 10 veces (una para cada segmento del caleidoscopio). Al mover el mouse, la rotación y la escala de los cortes se ajustan para lograr el efecto deseado.
En Google Chrome y Firefox, funciona a la perfección, sin ningún retraso. Sin embargo, en Safari el sitio web es inutilizable ya que es demasiado lento. ¿Me estoy perdiendo de algo?
Aquí hay un JSFiddle que muestra el problema. Tenga en cuenta que ya intenté reemplazar setTimeout (update, 1000/60) con RequestAnimationFrame, sin ninguna mejora.
JSFiddle: Link
$(document).ready(function () {
//SCRIPT KALEIDOSCOPE BASE
var DragDrop, Kaleidoscope, c, dragger, gui, i, image, kaleidoscope, len, onChange, onMouseMoved, options, ref, tr, tx, ty, update,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Kaleidoscope = (function() {
Kaleidoscope.prototype.HALF_PI = Math.PI / 2;
Kaleidoscope.prototype.TWO_PI = Math.PI * 2;
var optimal_radius = window.innerHeight;
if (window.innerWidth > optimal_radius) {
optimal_radius = window.innerWidth;
}
function Kaleidoscope(options1) {
var key, ref, ref1, val;
this.options = options1 != null ? options1 : {};
this.defaults = {
offsetRotation: 0.0,
offsetScale: 1.0,
offsetX: 0.0,
offsetY: 0.0,
radius: optimal_radius / 1.4,
slices: 12,
zoom: 1.0
};
ref = this.defaults;
for (key in ref) {
val = ref[key];
this[key] = val;
}
ref1 = this.options;
for (key in ref1) {
val = ref1[key];
this[key] = val;
}
if (this.domElement == null) {
this.domElement = document.getElementById(''kaleidoscope'');
}
if (this.context == null) {
this.context = this.domElement.getContext(''2d'');
}
if (this.image == null) {
this.image = document.createElement(''img'');
}
}
Kaleidoscope.prototype.draw = function() {
var cx, i, index, ref, results, scale, step;
this.domElement.width = this.domElement.height = this.radius * 2;
this.context.fillStyle = this.context.createPattern(this.image, ''repeat'');
scale = this.zoom * (this.radius / Math.min(this.image.width, this.image.height));
step = this.TWO_PI / this.slices;
cx = this.image.width / 2;
results = [];
for (index = i = 0, ref = this.slices; 0 <= ref ? i <= ref : i >= ref; index = 0 <= ref ? ++i : --i) {
this.context.save();
this.context.translate(this.radius, this.radius);
this.context.rotate(index * step);
this.context.beginPath();
this.context.moveTo(-0.5, -0.5);
this.context.arc(0, 0, this.radius, step * -0.51, step * 0.51);
this.context.lineTo(0.5, 0.5);
this.context.closePath();
this.context.rotate(this.HALF_PI);
this.context.scale(scale, scale);
this.context.scale([-1, 1][index % 2], 1);
this.context.translate(this.offsetX - cx, this.offsetY);
this.context.rotate(this.offsetRotation);
this.context.scale(this.offsetScale, this.offsetScale);
this.context.fill();
results.push(this.context.restore());
}
return results;
};
return Kaleidoscope;
})();
DragDrop = (function() {
function DragDrop(callback, context, filter) {
var disable;
this.callback = callback;
this.context = context != null ? context : document;
this.filter = filter != null ? filter : /^image/i;
this.onDrop = bind(this.onDrop, this);
disable = function(event) {
event.stopPropagation();
return event.preventDefault();
};
this.context.addEventListener(''dragleave'', disable);
this.context.addEventListener(''dragenter'', disable);
this.context.addEventListener(''dragover'', disable);
this.context.addEventListener(''drop'', this.onDrop, false);
}
DragDrop.prototype.onDrop = function(event) {
var file, reader;
event.stopPropagation();
event.preventDefault();
file = event.dataTransfer.files[0];
if (this.filter.test(file.type)) {
reader = new FileReader;
reader.onload = (function(_this) {
return function(event) {
return typeof _this.callback === "function" ? _this.callback(event.target.result) : void 0;
};
})(this);
return reader.readAsDataURL(file);
}
};
return DragDrop;
})();
image = new Image;
image.onload = (function(_this) {
return function() {
return kaleidoscope.draw();
};
})(this);
image.src = ''img/kaleidoscope.jpg'';
kaleidoscope = new Kaleidoscope({
image: image,
slices: 10
});
kaleidoscope.domElement.style.position = ''absolute'';
kaleidoscope.domElement.style.marginLeft = -kaleidoscope.radius + ''px'';
kaleidoscope.domElement.style.marginTop = -kaleidoscope.radius + ''px'';
kaleidoscope.domElement.style.left = ''50%'';
kaleidoscope.domElement.style.top = ''50%'';
document.getElementsByTagName(''header'')[0].appendChild(kaleidoscope.domElement);
dragger = new DragDrop(function(data) {
return kaleidoscope.image.src = data;
});
tx = kaleidoscope.offsetX;
ty = kaleidoscope.offsetY;
tr = kaleidoscope.offsetRotation;
onMouseMoved = (function(_this) {
return function(event) {
var cx, cy, dx, dy, hx, hy;
cx = window.innerWidth / 10;
cy = window.innerHeight / 10;
dx = event.pageX / window.innerWidth;
dy = event.pageY / window.innerHeight;
hx = dx - 0.5;
hy = dy - 0.5;
tx = hx * kaleidoscope.radius * -2;
ty = hy * kaleidoscope.radius * 2;
return tr = Math.atan2(hy, hx);
};
})(this);
window.addEventListener(''mousemove'', onMouseMoved, false);
options = {
interactive: true,
ease: 0.1
};
(update = (function(_this) {
return function() {
var delta, theta;
if (options.interactive) {
delta = tr - kaleidoscope.offsetRotation;
theta = Math.atan2(Math.sin(delta), Math.cos(delta));
kaleidoscope.offsetX += (tx - kaleidoscope.offsetX) * options.ease;
kaleidoscope.offsetY += (ty - kaleidoscope.offsetY) * options.ease;
kaleidoscope.offsetRotation += (theta - kaleidoscope.offsetRotation) * options.ease;
kaleidoscope.draw();
}
return setTimeout(update, 1000 / 60);
};
})(this))();
onChange = (function(_this) {
return function() {
kaleidoscope.domElement.style.marginLeft = -kaleidoscope.radius + ''px'';
kaleidoscope.domElement.style.marginTop = -kaleidoscope.radius + ''px'';
options.interactive = false;
return kaleidoscope.draw();
};
})(this);
});
Por lo que vi, el problema ocurre solo cuando el lienzo está en pantalla completa. Si aparece en un espacio pequeño, funciona perfectamente. Sin embargo, en mi sitio web, será de pantalla completa.
Defecto interesante, eliminaría el estilo css en el lienzo como sugiere @Jorge, luego representaría el efecto en un lienzo fuera de pantalla y luego copiaría el marco renderizado en el lienzo visible. El procesador DOM no tendrá que preocuparse por el recorte fuera de pantalla.
Woah El principal problema que tiene es que está dibujando un lienzo ENORME. Usted está creando una forma de lienzo mayor que el tamaño de la ventana Aunque parte del lienzo no se muestra, los cálculos para dibujar en esa área se realizan de todos modos. Sólo tienes que dibujar los píxeles que se pueden ver.
Aquí puede ver el tamaño real de su lienzo: http://i.imgur.com/trOYlcV.png
Con esto y los consejos de @Kaiido he creado este violín: https://jsfiddle.net/Llorx/sd1skrj8/9/
Mi tamaño de lienzo: http://i.imgur.com/4BzmCqh.png
Simplemente creé un lienzo que llenaba la ventana gráfica y dibujaba dentro de él, aumentando el radio del arco, siendo el lienzo el que limitaba los píxeles a la "ventana gráfica", y no la ventana.
Cambiado
this.context.arc(0, 0, this.radius, step * -0.51, step * 0.51);
// [...]
kaleidoscope.domElement.style.marginLeft = -kaleidoscope.radius + ''px'';
kaleidoscope.domElement.style.marginTop = -kaleidoscope.radius + ''px'';
kaleidoscope.domElement.style.left = ''50%'';
kaleidoscope.domElement.style.top = ''50%'';
para
this.context.arc(0, 0, this.radius*1.5, step * -0.51, step * 0.51);
// [...]
kaleidoscope.domElement.style.width = "100vw";
kaleidoscope.domElement.style.height = "100vh";
kaleidoscope.domElement.style.left = 0;
kaleidoscope.domElement.style.top = 0;
Esto se puede mejorar para tener un círculo real cuando la proporción de la pantalla no es cuadrada, y así, pero tienes la idea: nunca hagas que el lienzo sea más grande de lo necesario.
PD: No tengo Safari para probar. Dime si esto mejora el rendimiento.