Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Универсальный GrayScale с плавной работой (затухание и проявление), принцип работы? (https://javascript.ru/forum/jquery/35765-universalnyjj-grayscale-s-plavnojj-rabotojj-zatukhanie-i-proyavlenie-princip-raboty.html)

master_alf 25.02.2013 11:02

Учебный вариант заработал во всех нужных браузерах IE 7+ (6го нет что бы проверить, но и там должно работать), FF, Opera, Chrome, Safari. Посмотреть можно здесь, а скачать здесь (не нашел как файл к сообщению прикрепить).

Господа спецы, прошу, по-возможности, глянуть как оно работает. Если есть какие-то кривости в коде, опасные места - подскажите, пожалуйста. Если можно - с общими советами как это исправить (работать вместо меня не прошу, но полезные советы - это хорошо).
Я бы хотел выложить данный плагин для свободного использования, но для этого его нужно довести до совершенства. А в JS я весьма слаб... потому рассчитываю на вашу помощь :)

danik.js 25.02.2013 12:01

Давай сюды код тогда.

master_alf 25.02.2013 12:35

Вызов плагина, параметром передается селектор, для которого нужно применить grayScale.
$(document).ready(function() {
            makeGray('body div img');
        });


Подключаемый файл, где собственно описана вся логика работы.
var grayTryCount = 0;
var timerID = false;
function makeGray(selector) {
    if (grayTryCount <= 3) {
        grayTryCount +=1;
        $(selector).each(function(){
            if ((this.complete) && (!$(this).hasClass('makeGrayDone')) && (!$(this).hasClass('gray'))){
                makeCopy(this);
            } else {
                if (!timerID) {
                    timerID = setTimeout(function() {makeGray('body div img')}, 1000);
                }
            }
        });
    }
}
        
        function makeCopy(img) {
            var canvas2DSupported = !!window.CanvasRenderingContext2D;
            if (canvas2DSupported) {
                var newImg = makeCanvasCopy(img);
            } else { 
                var newImg = makeIMGCopy(img); 
            }
            var offset = $(img).offset();
            $(img).parent().append(newImg);
            $(img).addClass('makeGrayDone');
            $(newImg).offset(offset);
            $(newImg).hover(hoverIn, hoverOut);
        }
        
        function makeIMGCopy(imgObj) {
                var newImg = document.createElement('img');
                newImg.src = $(imgObj).attr('src');
                $(newImg).attr('class', 'gray');
                newImg.style.filter ='progid:DXImageTransform.Microsoft.BasicImage(grayScale=1)';
                
                return newImg;
        }
        
        function makeCanvasCopy(imgObj) {
            var newImg = document.createElement('img');

            var canvas = document.createElement('canvas');
            var canvasContext = canvas.getContext('2d');
            var imgW = imgObj.width;
            var imgH = imgObj.height;
            canvas.width = imgW;
            canvas.height = imgH;
            canvasContext.drawImage(imgObj, 0, 0);
            var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
            
            for(var y = 0; y < imgPixels.height; y++){
                for(var x = 0; x < imgPixels.width; x++){
                    var i = (y * 4) * imgPixels.width + x * 4;
                    var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
                    imgPixels.data[i] = avg;
                    imgPixels.data[i + 1] = avg;
                    imgPixels.data[i + 2] = avg;
                }
            }

            canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
            newImg.src = canvas.toDataURL();
            
            $(newImg).attr('class', 'gray');
            return newImg;
        }

        function createCanvas(imgObj) {
            var canvas = document.createElement('canvas');
            var canvasContext = canvas.getContext('2d');

            var imgW = imgObj.width;
            var imgH = imgObj.height;
            canvas.width = imgW;
            canvas.height = imgH;

            canvasContext.drawImage(imgObj, 0, 0);
            var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);

            for(var y = 0; y < imgPixels.height; y++){
                for(var x = 0; x < imgPixels.width; x++){
                    var i = (y * 4) * imgPixels.width + x * 4;
                    var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
                    imgPixels.data[i] = avg;
                    imgPixels.data[i + 1] = avg;
                    imgPixels.data[i + 2] = avg;
                }
            }

            canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
            imgObj.src = canvas.toDataURL();
            //return canvas.toDataURL();
        }
        
        function hoverIn(obj) {
         $(this).animate({
                opacity: 0
                }, 
                {duration: 500, step: function(now, fx) {
                    // Every step of the opacity animation we'll get the current 
                    // opacity as the 'now' argument.
                    var opacity = Math.round(now * 100);
                    $(fx.elem).css('-ms-filter', 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' + opacity + ')');
                    }
                  });
        }
        function hoverOut() {
            $(this).animate({
                opacity: 1
                }, 
                {duration: 500, step: function(now, fx) {
                    var opacity = Math.round(now * 100);
                    $(fx.elem).css('-ms-filter', 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' + opacity + ')');
                    }
                  });
        }

Deff 25.02.2013 12:52

master_alf,
А картинка пока только с того же домена ?

master_alf 25.02.2013 12:57

Да, только с этого же домена.
Я, если честно, слабо представляю зачем нужно грузить картинки с других доменов и обрабатывать их подобным образом... но может это дело в слабой фантазии? :D
В принципе, если в готовом плагине лучше, что бы оно было - погуглю как делается. Встречал рецепты.

Deff 25.02.2013 12:59

master_alf,
На большинстве халявных сайтах и форумов, нет загрузки изо на текущий домен
Пример Укоз, mybb.ru

Deff 25.02.2013 13:01

Цитата:

Сообщение от master_alf
В принципе, если в готовом плагине лучше, что бы оно было - погуглю как делается. Встречал рецепты.

Лучше имхо отдельным расширением, связанным плагином
На хабре видал статейку, как реализуемо для свежих версий браузеров => http://habrahabr.ru/post/120917/

danik.js 25.02.2013 13:05

Цитата:

Сообщение от master_alf
makeGray('body div img');

1) body в селекторе ни к селу ни к городу. Бывают картинки вне body чтоли?
2) Раз jQuery, то и оформи как плагин к jQuery. Чтобы вызов был через $('div img').makeGray()

Цитата:

Сообщение от master_alf
var grayTryCount = 0;
var timerID = false;

Срём в глобал? Не канает для публичного плагина. Срочно обернуть в анонимную функцию.
Цитата:

Сообщение от master_alf
$(selector)

А что если у юзера был вызван jQuery.noConflict() ?
Передать в анонимную функцию - обертку ссылку на jQuery, а внутри уже использовать знак доллара. Смотри как это сделано в других плагинах. Вообще, раз ты делаешь плагин, хоть бы не поленился и изучил как их делают другие.

Цитата:

Сообщение от master_alf
setTimeout(

Это самый последний вариант решения, когда подругому - ну никак. В данном же случае можно просто навесить обработчик onload на картинки и ждать их загрузки.
Цитата:

Сообщение от master_alf
$(imgObj).attr('src');

Может просто imgObj.src ?
Цитата:

Сообщение от master_alf
$(newImg).attr('class', 'gray');

Цитата:

Сообщение от master_alf
$(img).addClass('makeGrayDone');

Как будто два разных человека писали код. addClass предпочтительней.

Где используется функция createCanvas ?

Цитата:

Сообщение от master_alf
$(fx.elem).css('-ms-filter', 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' + opacity + ')');

Зачем это? jQuery сама фиксит opacity в старых ишаках.

Перед .animate() нужно делать .stop() чтоб не образовывалось очереди.

danik.js 25.02.2013 13:09

В WebKit и вроде 10м ишаке (не уверен) есть поддержка css mask, нужно проверять поддержку и по возможности использовать. Это в тыщу раз быстрее чем работа с пикселями.

$(newImg).attr('class', 'gray')

Слишком общий css-класс. Он может быть определен у юзера. Вообще, зачем тут css-классы назначать?

master_alf 25.02.2013 13:58

Цитата:

Сообщение от danik.js (Сообщение 236989)
1) body в селекторе ни к селу ни к городу. Бывают картинки вне body чтоли?

Согласен, fail.
Цитата:

Сообщение от danik.js (Сообщение 236989)
2) Раз jQuery, то и оформи как плагин к jQuery. Чтобы вызов был через $('div img').makeGray()

Погляжу как такое делается.
Цитата:

Сообщение от danik.js (Сообщение 236989)
Срём в глобал? Не канает для публичного плагина. Срочно обернуть в анонимную функцию.

Как только прочту, что такое анонимная функция - поправлю как рекомендвано. с JS сталкиваюсь постольку-поскольку...
Цитата:

Сообщение от danik.js (Сообщение 236989)
А что если у юзера был вызван jQuery.noConflict() ?
Передать в анонимную функцию - обертку ссылку на jQuery, а внутри уже использовать знак доллара. Смотри как это сделано в других плагинах. Вообще, раз ты делаешь плагин, хоть бы не поленился и изучил как их делают другие.

Как сказал выше - в JS слаб, jQuery умею использовать, но не писать под него плагины... погляжу ну другие обязательно.

Цитата:

Сообщение от danik.js (Сообщение 236989)
Это самый последний вариант решения, когда подругому - ну никак. В данном же случае можно просто навесить обработчик onload на картинки и ждать их загрузки.

Согласен, такой вариант в голову не приходил. Перепишу.

Цитата:

Сообщение от danik.js (Сообщение 236989)
Как будто два разных человека писали код. addClass предпочтительней.

За исключением пересчета цвета для канваса - всё писал я. А разные методы т.к. по-разному думал в эти моменты. Что вспомнил, то и использовал...
Цитата:

Сообщение от danik.js (Сообщение 236989)
Где используется функция createCanvas ?

Fail :( осталась не вычещенной с момента сборки всего воедино.
Цитата:

Сообщение от danik.js (Сообщение 236989)
Зачем это? jQuery сама фиксит opacity в старых ишаках.

Это не фикс прозрачности, а её динамическое изменение. Этим и достигатся плавность перехода в IE.
Цитата:

Сообщение от danik.js (Сообщение 236989)
Перед .animate() нужно делать .stop() чтоб не образовывалось очереди.

Забыл :( добавлю.
Цитата:

Сообщение от Deff (Сообщение 236985)
На большинстве халявных сайтах и форумов, нет загрузки изо на текущий домен
Пример Укоз, mybb.ru

Не подумал - добавлю.
Цитата:

Сообщение от danik.js (Сообщение 236990)
В WebKit и вроде 10м ишаке (не уверен) есть поддержка css mask, нужно проверять поддержку и по возможности использовать.

Почитаю что такое css mask. Пока я не понял о чем ты сказал.
Цитата:

Сообщение от danik.js (Сообщение 236990)
$(newImg).attr('class', 'gray')

Слишком общий css-класс. Он может быть определен у юзера. Вообще, зачем тут css-классы назначать?

С названием класса согласен. Хотел изменить на уникальные... но, опять же, забыл. А классы назначал как признак того, что данное изображение - серое. Что бы с него не делать копий. Т.к. при моем способе вызова функции grayScale() - были возможны дубликаты и уже серых картинок. Но с img.onload - проблема уйдет.


Часовой пояс GMT +3, время: 18:49.