PHP: Рисуем SVG

Один из вариантов генерации картинок svg «на лету». Капля, внутри буква, окруженная полукругами.

<?php

$blob_status=5; 
$pies=[1,2,3,4,5,6];

function GetColorPieByState($state){    
    switch ($state) {
        case 1:$color="#2afc24";break;  
        case 2:$color="#2afc24";break;  
        case 3:$color="#fc2424";break;  
        case 4:$color="#fc2424";break;  
        case 5:$color="#fc2424";break;  
        case 6:$color="#cccccc";break;  
        default:$color="#7DD8B5";break; 
    }
    return $color;
};

function String2Array($st){
    $st=mb_substr($st, 0, -1);
    return explode(",", $st);
};

function GetColorBlobByState($state){    
    $station_fill="#D1FFB4";
    if ($state==1) $station_fill="#2afc24";
    if ($state==2) $station_fill="#fc2424";
    if ($state==3) $station_fill="#fc2424";
    if ($state==4) $station_fill="#fc2424";
    if ($state==5) $station_fill="#cccccc";
    return $station_fill;
};

function SaveSvgBlobIco($blob_status,$pies,$filename){
    
}

Draw($blob_status,$pies);

function Draw($blob_status,$pies){
    
    $station_fill=GetColorBlobByState($blob_status);

    $svg="";
    $svg=$svg.'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="264">';
    $svg=$svg."<defs>";
    $svg=$svg."    <style>";
    $svg=$svg."        .blob_fill {fill:$station_fill;}"; /*Цвет капли*/       
    $svg=$svg.'    </style>';
    $svg=$svg.'</defs>';
    //Рисунок капли
    $svg=$svg.'   <path class="blob_fill" d="m199.10001,101.02451c0,90.53423 -99.52251,161.55548 -99.52251,161.55548s-99.5775,-76.21059 -99.5775,-161.55548a99.55,101.0245 0 0 1 199.10001,0z" id="svg_1"/>';
    //Буква й
    $svg=$svg.'   <text transform="matrix(7.0814, 0, 0, 6.46509, -382.002, -470.036)" xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="24" id="svg_3" y="94.56099" x="61.67799" stroke-opacity="null" stroke-width="0" stroke="null" fill="#EDFFFF">й</text>';

    $svg=$svg.'<g style="stroke:black;stroke-width:1">';

    function pt($x,$y,$rad,$gap,$r,$ang,$mns=-1){ 
      //global $x,$y,$rad,$gap;      
      $a=($ang-90)*$rad-$mns*asin($gap/$r); 
      return sprintf('%0.2f,%0.2f',$x+$r*cos($a),$y+$r*sin($a));
    }

    $x=100;
    $y=100;
    $r=60;  // внутренний радиус
    $rc=90; // внешний радиус
    $gap=20; // отступ между кусками
    $a360=360/count($pies); 
    $M_PI=3.14159265358; 
    $rad=$M_PI/180.;
    $out='';
    $ang1=0;      


    foreach ($pies as $connector) {  
      $dang = 1 * $a360;       
      $laf  = $dang > 180? 1 : 0; 
      $ang2 = $ang1 + $dang;      
      $out.= '<path d="M'.pt($x,$y,$rad,$gap,$rc,$ang1).'L'.pt($x,$y,$rad,$gap,$r, $ang1)."A $r,$r, 0,$laf,1 "  .pt($x,$y,$rad,$gap,$r,$ang2,1).
                      'L'.pt($x,$y,$rad,$gap,$rc,$ang2,1)."A $rc,$rc, 0,$laf,0, ".pt($x,$y,$rad,$gap,$rc,$ang1).'" style="fill:'.GetColorPieByState($connector).'" />'."\n";
      $ang1=$ang2;
    }
    $svg=$svg.$out;
    $svg=$svg.'</g></svg>';
    echo $svg;
};
?>

PostgreeSQL: добавление функций

Часто чтобы не плодить логику в приложении, проще часть функционала по вычислению чего-либо возложить на сервер БД. Для этого и нужны функции. Причем в Postgree мне они понравились много больше чем в MySQL в плане простоты и удобства.

Любая функция в PostgreeSQL начинается с объявления функции, перечисления используемых переменных, тела функции и в конце возврат результата выполнения функции.

Объявление функции:

CREATE OR REPLACE FUNCTION public.get_calculate_station_status(
	station_id integer) -- на входе параметр station_id - число  
    RETURNS integer -- возвращает число
    LANGUAGE 'plpgsql' -- язык 
plpgsql
AS $BODY$

Объявление переменных, идет после команды DECLARE. перечисляются заранее все переменные с указанием их типов, которые будут использоваться внутри функции. Например:

DECLARE
status integer; — число
st_online boolean; — true/false
stations integer[]; — массив чисел

Сама функция пишется непосредственно между BEGIN и END; Доступны элементарные условия:


 IF aa=bb THEN 
      bb:=1;
    ELSE 
      cc:=2;
END IF;

Поместить результат запроса в переменную или в массив:

select zz from xx into aa where vv=1;

Перебор массива:

FOREACH st_id IN ARRAY stations
    LOOP
       connectors_free:=connectors_free+get_count_connectors_free(st_id);
	   stations_online:=stations_online+1;
    END LOOP;

Результирующий пример готовой функции:

DECLARE
 status integer;
 stations integer[];
 connectors_free integer;
 stations_online integer;
 st_id integer;
BEGIN    		
  status:=get_ezs_status(ezs_id);
  if status=1 THEN
    connectors_free:=0;
	stations_online:=0;
  	stations:=ARRAY (select station from stations_online inner join stations on stations.id=station where stations.ezs=ezs_id  and stations.status=1 and deleted=false);
	FOREACH st_id IN ARRAY stations
    LOOP
       connectors_free:=connectors_free+get_count_connectors_free(st_id);
	   stations_online:=stations_online+1;
    END LOOP;
	IF stations_online>0 THEN
		if connectors_free>0 THEN
			status:=1;
		ELSE
			status:=4;
		END IF;
		
	ELSE
	  	status:=5;
	END IF;
  END IF;
  return status;
END;

JqGrid-Free: в модальных окнах Bootstrap 4 не активны поля Input

Неожиданно обнаружилось, что в модальных окнах использование jqgrid черевато тем, что в вызываемых диалогах add / edit не работают поля select и input.

Купирование проблемы (не решение): в модальном окне заменить tabindex=»-1″ на style=»overflow:hidden;»

<div class="modal hide fade" id="DialogWindowModal" style="overflow:hidden;" role="dialog" aria-labelledby="DialogWindowModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="DialogWindowModalName">Диалоговое окно</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body" id="DialogWindowModalDiv">
                                                         
      </div>   
    </div>
  </div>
</div>

RouterOs: как на Mikrotick добавить еще одну WiFi сеть (без изоляции)

Задача: добавить еще одну wifi сеть с доступом в интернет, с устройствами не изолированными друг от друга

Решение:

1) Добавим виртуальный интерфейс:

Добавим SSID и профиль безопасности:

Добавим адрес для интерфейса (IP->Adresses), и добавим в интерфейс wlan2 в мост (Brige):

Android: startActivityForResult deprecated

С очередным обновлением Android Studio опять прилетели новые deprecated. На этот раз для startActivityForResult. У меня сия конструкция используется для обработки выбора файла в компоненте WebView. Соответственно изменим:

ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
                    new ActivityResultContracts.StartActivityForResult(),
                    new ActivityResultCallback<ActivityResult>() {
                        @Override
                        public void onActivityResult(ActivityResult result) {

                            Intent data = result.getData();
                            Uri uri = data.getData();

                            if (result.getResultCode() == REQUEST_SELECT_FILE) {
                                if (uploadMessage == null) return;
                                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), data));
                                uploadMessage = null;
                            };
                            if (result.getResultCode() == FILECHOOSER_RESULTCODE) {
                                if (null == mUploadMessage) return;
                                Uri result2 = data == null || result.getResultCode() != MainActivity.RESULT_OK ? null : data.getData();
                                mUploadMessage.onReceiveValue(result2);
                                mUploadMessage = null;
                            }
                        }
                    });

            // For Lollipop 5.0+ Devices
            public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                if (uploadMessage != null) {
                    uploadMessage.onReceiveValue(null);
                    uploadMessage = null;
                }
                uploadMessage = filePathCallback;
                Intent intent = null;
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                    intent = fileChooserParams.createIntent();
                }
                try {
                    someActivityResultLauncher.launch(intent);
                   // startActivityForResult(intent, REQUEST_SELECT_FILE);
                } catch (ActivityNotFoundException e) {
                    uploadMessage = null;
                    return false;
                }
                return true;
            }



            protected void openFileChooser(ValueCallback<Uri> uploadMsg) {
                mUploadMessage = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");

              //  startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);


                someActivityResultLauncher.launch(Intent.createChooser(i, "File Chooser"));

            }

        });
1 80 81 82 83 84 310