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

26 мая 2011 г.

Выбор цвета как в photoshop на javascript

Всем, здравствуйте!
Сегодня мы напишем скрипт, который позволит нам выбирать цвет, если не как в photoshop, то близкое к тому. Ведь самое главное суть!
Для этого нам понадобятся следующие изображения.













Последнее изображение я делал php-скриптом. Как это реализовано, я писал в предыдущей статье. Выглядеть все это будет следующим образом


Итак, приступим!

<form action="" method="POST">
<table style="margin:auto; border:1px solid #000; position:relative;">
<tr><td>Введите свой цвет или выберите из набора.
 <div class="ppic" id="surname_pic" style="height:20px; width:20px;position:relative;top:0;right:0;margin:0;float:right;padding:0;border:1px solid #000000;z-index:5"></div>
 <div class="all_for_clr" id="surname_main" style="background:#aaaaaa;height:0; width:0;position:relative;top:0;right:0;margin:0;padding:0;overflow:hidden;float:right;border:1px solid #000000;filter:alpha(opacity=0);opacity:0;z-index:0">
 <div class="preview" id="surname_pre" style="height:50px;width:50px;position:relative;float:right;z-index:0;background:#ffffff;border:1px solid #000000;"></div>
 <div class="brightness" id="surname_br" style="height:128px;width:20px;position:relative;float:right;z-index:0;background:url(nasyschen.png);overflow:hidden;border:1px solid #000000;margin:0 5px 0 0;padding:0;"><div id="surname_line" style="height:1px;width:20px;position:absolute;top:0;left:0;background:#ff0000;margin:0;padding:0;border:0"></div></div>
 <div class="gradus" id="surname" style="height:128px;width:128px;background:url(spec.png) no-repeat 0 0;overflow:hidden;position:relative;float:right;z-index:0;margin:0 5px 0 0;padding:0;border:1px solid #000000;"><div id="surname_krest" style="height:15px;width:15px;position:absolute;top:0;left:0;background:url(krest.png);margin:0;padding:0;border:0"></div></div></div></td>
 <td><input type="text" name="surname" /></td>
</tr>
</table>
</form>
это у нас непосредственно сама форма.
div с class="ppic" - это у нас квадратик, в котором будет показан ткущий цвет.
div с классом "all_for_color" - здесь мы разместим спектр, где у нас будет бегать крестик и где мы будем выбирать цвет, а так же полосу, в которой будем выбирать яркость. Здесь же у нас будет окошко, в котором будет отображаться выбираемый цвет.
В этом диве у нас будет:
div с классом "preview" - т.е. предпросмотр цвета
div с классом "gradus" - не знаю почему я его так назвал, здесь у нас спектр, по которому будем кликать, чтобы выбрать цвет
div с классом "drightness" - здесь черно-белый градиент, выбор яркости.
div с ID="surname_line" - это линия, которая будет держать нас в курсе, где мы кликнули последний раз по яркости
и div с ID="surname_krest" - это крестик, который показывает, где мы кликнули последний раз по спектру.

Ну, а теперь самое страшное :)
Только не забудьте подключить библиотеку jQuery!

<script type="text/javascript">
open_color=false;
function findX(el){
 var curX=0;
 if(el.offsetParent){
  while(el.offsetParent){
   curX+=el.offsetLeft;
   el=el.offsetParent;
  }
 }
 else if(el.x) curX+=el.x;
 return curX;
}
function findY(el){
 var curY=0;
 if(el.offsetParent){
  while(el.offsetParent){
   curY+=el.offsetTop;
   el=el.offsetParent;
  }
 }
 else if(el.y) curY+=el.y;
 return curY;
}
function getColor(x,y){
 var dec_r;
 var dec_g;
 var dec_b;
 if(y<22){
  dec_g=(256-y*12)/128;
  dec_r=0;
  dec_b=2;
 }
 else if(y>21&&y<43){
  dec_g=0;
  dec_r=(y*12-256)/128;
  dec_b=2;
 }
 else if(y>42&&y<65){
  dec_r=2;
  dec_b=(768-y*12)/128;
  dec_g=0;
 }
 else if(y>64&&y<86){
  dec_b=0;
  dec_g=(y*12-768)/128;
  dec_r=2;
 }
 else if(y>85&&y<107){
  dec_g=2;
  dec_r=(1280-y*12)/128;
  dec_b=0;
 }
 else if(y>106){
  dec_r=0;
  dec_b=(y*12-1280)/128;
  dec_g=2;
 }
 red=Number(Math.abs(Math.round(255-x*dec_r))).toString(16);
 green=Number(Math.abs(Math.round(255-x*dec_g))).toString(16);
 blue=Number(Math.abs(Math.round(255-x*dec_b))).toString(16);
 if(red.length<2) red="0"+red;
 if(green.length<2) green="0"+green;
 if(blue.length<2) blue="0"+blue;
 return '#'+red+green+blue;
}
function chColor(x,y,k){
 var dec_r;
 var dec_g;
 var dec_b;
 if(y<22){
  dec_g=(256-y*12)/128;
  dec_r=0;
  dec_b=2;
 }
 else if(y>21&&y<43){
  dec_g=0;
  dec_r=(y*12-256)/128;
  dec_b=2;
 }
 else if(y>42&&y<65){
  dec_r=2;
  dec_b=(768-y*12)/128;
  dec_g=0;
 }
 else if(y>64&&y<86){
  dec_b=0;
  dec_g=(y*12-768)/128;
  dec_r=2;
 }
 else if(y>85&&y<107){
  dec_g=2;
  dec_r=(1280-y*12)/128;
  dec_b=0;
 }
 else if(y>106){
  dec_r=0;
  dec_b=(y*12-1280)/128;
  dec_g=2;
 }
 red=Number(Math.abs(Math.round((255-x*dec_r)*k))).toString(16);
 green=Number(Math.abs(Math.round((255-x*dec_g)*k))).toString(16);
 blue=Number(Math.abs(Math.round((255-x*dec_b)*k))).toString(16);
 if(red.length<2) red="0"+red;
 if(green.length<2) green="0"+green;
 if(blue.length<2) blue="0"+blue;
 return '#'+red+green+blue;
}
mmousedown=false;
bmousedown=false;
$(document).ready(function(){
 $(".gradus").mousedown(function(){
  mmousedown=true;
 });
 $(".gradus").mouseup(function(){
  mmousedown=false;
 });
 $(".gradus").mousemove(function(e){
  if(!mmousedown) return;
  var x=e.pageX-findX(this);
  var y=e.pageY-findY(this);
  if(x>127 || x<0 || y>127 || y<0){
   mmousedown=false;
   return;
  }
  var color=getColor(x,y);
  var field=$(this).attr("id");
  $("#"+field+"_krest").css("top",y-7);
  $("#"+field+"_krest").css("left",x-7);
  $("[name="+field+"]").val(color);
  $("#"+field+"_pre").css("background",color);
  $("#"+field+"_pic").css("background",color);
  $("#"+field+"_line").css("top",0);  
 });
 $(".gradus").click(function(e){
  var x=e.pageX-findX(this);
  var y=e.pageY-findY(this);
  if(x>127 || x<0 || y>127 || y<0){
   mmousedown=false;
   return;
  }
  var color=getColor(x,y);
  var field=$(this).attr("id");
  $("#"+field+"_krest").animate({top:y-7, left:x-7},"fast");
  $("[name="+field+"]").val(color);
  $("#"+field+"_pre").css("background",color);
  $("#"+field+"_pic").css("background",color);
  $("#"+field+"_line").css("top",0);  
 });
 $(".ppic").mouseenter(function(e){
  if(open_color) return;
  open_color=true;
  var len=$(this).attr("id");
  len=len.length-4;
  var id=$(this).attr("id").substr(0,len);
  $(this).css("z-index","-1");
  $("#"+id+"_main").css("position","absolute");
  $("#"+id+"_main").css("left",e.pageX-100);
  $("#"+id+"_main").css("width","215px");
  $("#"+id+"_main").css("height","130px");
  $("#"+id+"_main").css("padding","5px");
  $("#"+id+"_main").css("z-index","0");
  $("#"+id+"_main").animate({opacity:1},"slow");
  open_color=false;
 });
 $(".all_for_clr").mouseleave(function(){
  if(open_color) return;
  open_color=true;
  $(this).animate({opacity:0},"slow",function(){
   $(this).css("position","relative");
   $(this).css("left","0");
   $(this).css("width","0");
   $(this).css("height","0");
   $(this).css("padding","0");
   $(this).css("z-index","-1");
   $(".ppic").css("z-index","5");
   open_color=false;
  });
 });
 $(".brightness").mousedown(function(){
  bmousedown=true;
 });
 $(".brightness").mouseup(function(){
  bmousedown=false;
 });
 $(".brightness").mousemove(function(e){
  if(!bmousedown) return;
  var y=e.pageY-findY(this);
  var x=e.pageX-findX(this);
  if(x>19 || x<0 || y>127 || y<0){
   bmousedown=false;
   return;
  }
  var k=(127-y)/127;
  var len=$(this).attr("id");
  len=len.length-3;
  var id=$(this).attr("id").substr(0,len);
  var spec=document.getElementById(id);
  var krest=document.getElementById(id+"_krest");
  var x_color=findX(krest)+7-findX(spec);
  var y_color=findY(krest)+7-findY(spec);
  var color=chColor(x_color,y_color,k);
  $("#"+id+"_line").css("top",y);
  $("[name="+id+"]").val(color);
  $("#"+id+"_pre").css("background",color);
  $("#"+id+"_pic").css("background",color);
 });
 $(".brightness").click(function(e){
  var y=e.pageY-findY(this);
  var x=e.pageX-findX(this);
  if(x>19 || x<0 || y>127 || y<0){
   bmousedown=false;
   return;
  }
  var k=(127-y)/127;
  var len=$(this).attr("id");
  len=len.length-3;
  var id=$(this).attr("id").substr(0,len);
  var spec=document.getElementById(id);
  var krest=document.getElementById(id+"_krest");
  var x_color=findX(krest)+7-findX(spec);
  var y_color=findY(krest)+7-findY(spec);
  var color=chColor(x_color,y_color,k);
  $("#"+id+"_line").animate({top:y},"fast");
  $("[name="+id+"]").val(color);
  $("#"+id+"_pre").css("background",color);
  $("#"+id+"_pic").css("background",color);
 });
});
</script>

Первая переменная нам необходима, чтобы контролировать панель выбора цвета. В начале она у нас содержит значение false. Т.е. панель не отображается.
Функция findX() и findY() возвращают значение X и Y от верхнего левого угла страницы.
getColor() возвращает значение цвета в формате #xxxxxx. Функция работает по той же логике, что и php-скрипт, которым мы нарисовали спектр.
chColor() возвращает измененный цвет, т.е. меняет яркость выбранного цвета. k это коэффициент.
mmousedown - переменная, которая требуется нам для отслеживания, где нажата кнопка мыши. Она принимает значение true, если кнопка мыши была нажата на спектре. Когда пользователь отпускает кнопку, она принимает значение false. Также ведет себя переменная bmousedown по нажатию/отпусканию кнопки мыши на яркости. Это нам необходимо, чтобы при нажатой кнопке, цвет изменялся при каждом смещении мыши.
Дальше мы прикрепляем обработчики событий на каждое важное для нас поле. Т.е. если курсор попадает на маленький квадрат с текущим цветом, то мы отображаем панель выбора цвета. Если курсов покидает панель, она скрывается. Такие же действия мы поделываем и со всем остальным.
Думаю остальное понятно. Если будут вопросы, задавайте, буду рад ответить!
А пока до скорых встреч!

24 мая 2011 г.

Рисуем градиент на PHP

Как-то мне поступил заказ, чтобы я сделал выбор цвета как в Photoshop. Конечно, один в один я его не сделал, ну, этого и не требовалось, но суть не в этом. Для того, чтобы осуществить нечто подобное, необходимо знать по какому цвету ты щелкаешь. Для этого оказалось проще самому программным образом нарисовать такой квадратик, тогда я буду на 100% уверен какой пиксель, какой цвет содержит. Т.е. его шестнадцатеричный код.
Вот, что у меня получилось.

Теперь я продемонстрирую сам код:
<?php
$im = imagecreatetruecolor(128,128);
$dec_r = 0;
$dec_g = 2;
$dec_b = 2;
for($y = 0; $y < 128; $y++){
 $red = 255;
 $green = 255;
 $blue = 255;
 if($y < 22) $dec_g = (256 - $y * 12) / 128;
 else if($y > 21 && $y < 43){
  $dec_g = 0;
  $dec_r = ($y * 12 - 256) / 128;
 }
 else if($y > 42 && $y < 65){
  $dec_r = 2;
  $dec_b = (768 - $y * 12) / 128;
 }
 else if($y > 64 && $y < 86){
  $dec_b = 0;
  $dec_g = ($y * 12 - 768) / 128;
 }
 else if($y > 85 && $y < 107){
  $dec_g = 2;
  $dec_r = (1280 - $y * 12) / 128;
 }
 else if($y > 106){
  $dec_r = 0;
  $dec_b = ($y * 12 - 1280) / 128;
 }
 for($x = 0; $x < 128; $x++){
  $color_now = imagecolorallocate($im, round($red - $x * $dec_r), round($green - $x * $dec_g),round($blue - $x * $dec_b));
  imagesetpixel($im, $x, $y, $color_now);
 }
}

header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
?>

Тут логика проста. Создаем изображение размером 128х128. Потом для каждой строчки определяем правило, по которому будут происходить изменения цвета каждого следующего пикселя.
Переменные $dec_r, $dec_g, $dec_b отвечают за шаг каждого цвета. Т.е. сначала у нас $dec_r = 0, $dec_g = 2 и $dec_b = 2. Это означает, что красный цвет изменятся не будет. А зеленый и синий будут уменьшаться на 2. Так будет только в первой строчке. Во второй правило изменится для шага зеленого цвета. Его шаг замедлится и не достигнет нуля. Таким образом, в конце второй строчки у нас уже будет не чистый красный цвет, а начнет приближаться к желтому. На 21-й строчке значение зеленого цвета практический перестает изменятся и, начиная с 22-й строчке оно будет равно 255. Но теперь начинает увеличиваться шаг красного цвета, когда он достигнет 2, начинает уменьшаться шаг синего цвета и т.д. Таким образом, мы пройдем по всей цветовой гамме. Конечно, частота дискретизации не позволит нам сделать это более плавно уместившись в такой маленький участок экрана, но наш глаз скачков цвета не заметит.

Дорогие читатели. В следующей статье я хочу вам рассказать о том, как осуществить выбор цвета как в photoshop на javascript. Если же вас интересуют другие темы, то пишите, обсудим.
До новых встреч!

23 мая 2011 г.

Парсер BBcode на PHP для нашего редактора (заключительная статья)

Здравствуйте! Сегодня я продолжу написание редактора, вернее скрипт, который будет переводить bb-код в нужный вид. В прошлой статье мы дописали наш редактор на javascript. Мы научили его вставлять необходимые теги в необходимое место. Теперь нам нужен скрипт на стороне сервера, который это будет сохранять в файл или базу данных, и еще один скрипт который все это будет переводить в надлежащий вид.
Я решил поступить следующим образом. Данные будут храниться в bbcode и парситься при выдаче. Чтобы при редактировании не надо было переводить из html опять в bbcode. Кто с этим не согласен, давайте поспорим. :)
Итак, я создаю файл save.php

<?php
$txt = htmlspecialchars($_POST['text']);
file_put_contents('for_pars.txt', $txt);
?>
<a href="pars.php">посмотреть результат</a>

Все данные я предварительно обрабатываю функцией htmlspecialchars(), и просто помещаю в текстовый файл for_parse.txt. После этих незамысловатых действий я предоставляю пользователю возможность просмотреть результат в том виде, в котором все это будет отображаться на сайте.
Теперь создаем следующий файл pars.php

<?php
$txt = file_get_contents('for_pars.txt');
 
function pars_bb($txt){
 $txt = str_replace('[b]', "<b>", $txt);
 $txt = str_replace('[/b]', "</b>", $txt);
 $txt = str_replace('[u]', "<u>", $txt);
 $txt = str_replace('[/u]', "</u>", $txt);
 $txt = str_replace('[i]', "<i>", $txt);
 $txt = str_replace('[/i]', "</i>", $txt);
 $txt = str_replace('[s]', "<span style=\"text-decoration: line-through;\">", $txt);
 $txt = str_replace('[/s]', "</span>", $txt);
 $txt = str_replace('[left]', "<div align=\"left\">", $txt);
 $txt = str_replace('[/left]', "</div>", $txt);
 $txt = str_replace('[center]', "<div align=\"center\">", $txt);
 $txt = str_replace('[/center]', "</div>", $txt);
 $txt = str_replace('[right]', "<div align=\"right\">", $txt);
 $txt = str_replace('[/right]', "</div>", $txt);
 
 preg_match_all('/\[link href=([^]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt = str_replace('[link href=' . $val . ']', '<a href="' . $val . '">', $txt);
  $i++;
 }
 
 preg_match_all('/\[image]([^[]*)\[\/image]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = str_replace('[image]'.$val.'[/image]', "<img src=\"$val\" />", $txt);
  $i++;
 }
 
 preg_match_all('/\[video]([^[]*)\[\/video]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = get_ifrm_src($val) ? str_replace('[video]'.$val.'[/video]', get_ifrm_src($val), $txt) : str_replace('[video]'.$val.'[/video]', "<a href=\"" . $val . "\">Ссылка на видео</a>", $txt);
  $i++;
 }
 
 preg_match_all('/\[email=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt = str_replace('[email='.$val.']', "<a href=\"mailto:$val\">", $txt);
  $i++;
 }
 
 preg_match_all('/\[media]([^[]*)\[\/media]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = str_replace('[media]'.$val.'[/media]', "<a href=\"$val\">media</a>", $txt);
  $i++;
 }
 
 preg_match_all('/\[font=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt =str_replace('[font='.$val.']', "<span style=\"font-family: $val;\">", $txt);
  $i++;
 }
 
 preg_match_all('/\[size=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt =str_replace('[size='.$val.']', "<font size=\"$val\">", $txt);
  $i++;
 }
 
 preg_match_all('/\[color=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt =str_replace('[color='.$val.']', "<font color=\"$val\">", $txt);
  $i++;
 }
 
 $txt =str_replace('[/color]', "</font>", $txt);
 $txt =str_replace('[/size]', "</font>", $txt);
 $txt =str_replace('[/font]', "</span>", $txt);
 $txt =str_replace('[/code]', "</pre>", $txt);
 $txt =str_replace('[code]', "<pre>", $txt);
 $txt = str_replace('[quote]', "<div class=\"quote\">", $txt);
 $txt = str_replace('[/quote]', "</div>", $txt);
 $txt = str_replace('[/email]', "</a>", $txt);
 $txt = str_replace('[/link]', "</a>", $txt);
 $txt = str_replace('[indent]', "<div style=\"padding:20px\">", $txt);
 $txt = str_replace('[/indent]', "</div>", $txt);
 
 preg_match_all('/:(\w*):/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = file_exists("./images/$val.gif") ? str_replace(":$val:", "<img class=\"smile\" src=\"./images/$val.gif\" />", $txt) : $txt;
  $i++;
 }
 
 
 else $txt = find_video($txt);
 
 return $txt;
}
 
function get_ifrm_src($url){
 include('config.php');
 preg_match('/http:\/\/([^\/]*)\/(.*)/i', $url, $match);
 if(count($match[1]) == 0) return false;
 $pat = $pat_ar[$match[1]];
 $str = $pat['tpl'];
 $player = $pat['player'];
 if($str){
  preg_match($pat['pat'], $match[2], $s_match);
  if(count($s_match)){
   foreach($s_match as $key => $s_val)
    if($key) $str = str_replace('['.$key.']', "$s_val", $str);
   $str = str_replace("[url]", $str, $player);
  }
 }
 return $str == $pat['tpl'] ? false : $str;
}
 
function find_video($txt){
 include('config.php');
 if(count($pat_ar) == 0) return $txt;
 foreach($pat_ar as $val){
  if(preg_match_all($val['url_pat'], $txt, $match)){
   foreach($match[0] as $val)
    $txt = str_replace($val, (get_ifrm_src($val) ? get_ifrm_src($val) : $val), $txt);
  }
 }
 return $txt;
}
 
 
echo pars_bb($txt);
?>

И получился вот такой файл. Теперь настала пора его разобрать. Сначала мы считываем данные из файла, который содержит данные введенные пользователем в виде bbcode. И отображаем результат вызова функции pars_bb(), которой для парсинга мы передали данные пользователя.
Что же делает данная функция? Она по регулярным выражениям ищет находит то, что надо заменить и заменяет. Некоторые теги теги мы меняем, применяя простую функцию str_replace() без preg_match_all().
Дальше мы видим, что тег [video] у нас преобразуется не как все. А дело в том, что если видео вставлено с youtube, то оно заменяется фреймом с видео-плеером. В расчете на то, что подобные замены могут быть довольно-таки разные, я некоторые параметры вынес в отдельный файл config.php

<?php
$pat_ar = array();
$pat_ar['www.youtube.com'] = array('url_pat' => '/http:\/\/www.youtube.com[^\s]+/i', 'pat' => '/\?v=([^&]*)/i', 'tpl' => 'http://www.youtube.com/embed/[1]', 'player' => '<iframe width="425" height="349" src="[url]" frameborder="0" allowfullscreen></iframe>');
?>

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

До новых встреч!