كيفية تكوين صداقات Electron و Webix. الجزء 2. إنشاء تطبيق باستخدام طريقة العرض الخاصة بك

المقدمة


في المقال السابقلقد درسنا معك قضية دمج إطار عمل Webix في Electron وإنشاء تطبيق واجهة مستخدم رسومية بسيط يعتمد على هذه الأطر. الغرض من هذه المقالة هو زيادة تطوير مسألة التكامل في واجهة المستخدم الرسومية التي تم إنشاؤها بمساعدة Electron و Webix لأطر JavaScript الأخرى. تتميز جميع عناصر واجهة المستخدم الرسومية التي يتم تنفيذها في "Webix" بمعلمة "view". اعتمادًا على قيمة هذه المعلمة ، سيتم عرض عنصر GUI أو آخر. يتداخل عدد أنواع عناصر "العرض" التي تسمح لك بإنشاء "Webix" حول 90٪ من المهام عند تنفيذ الواجهة. النسبة المتبقية 10٪ هي فقط الحالة عندما يكون من الضروري دمج إما كود مكتوب مسبقًا أو إطار عمل (مكتبة) غير مدعوم بشكل صريح في Webix.لتنفيذ التكامل مع أطر العمل (المكتبات) التابعة لجهات خارجية ، سننشئ معًا عنصر Webix "view" الخاص بنا.

صياغة المشكلة


أنشئ تطبيق واجهة المستخدم الرسومية "Electron + Webix" ، الذي سيبني رسمًا بيانيًا لدالة من النموذج "y = a * sin (b) + c" مع القدرة على تغيير معلمات الوظيفة "a و b و c" مع إعادة رسم ديناميكي للرسم البياني.

حجز صغير


قم بالحجز على الفور بأن "Webix" توجد أدوات قياسية قوية جدًا للعمل مع الرسوم البيانية. ليس هدفي هو استكمال هذه الأدوات ، ولكن لإظهار كيف يمكنك دمج أطر عمل أو مكتبات إضافية في حزمة Electron + Webix. لقد حدث أن لدي كود جاهز لهذا الرسم البياني باستخدام "D3.js" وقررت دمجه في التطبيق.

أدوات


  1. Visual Studio Code - محرر code.visualstudio.com .
  2. Node.JS - تنزيل من هنا nodejs.org/en
  3. إلكترون - تثبيت "npm install - حفظ-إلكترون".
  4. Webix – ru.webix.com.
  5. JQuery – «npm jquery»
  6. D3.js – d3js.org
  7. (https://github.com/kapakym/electron_webix) , .


1. نظرًا لأنني شخص كسول ، لا أريد كتابة جميع الرموز من البداية للمرة الثانية. لذلك ، نأخذ الشفرة من المقالة السابقة ونملأها في المجلد الذي نحتاجه. هناك خياران. الأول هو فقط لتحميل الأرشيف من الموقع (الشكل 1) أو استنساخه إذا كان لديك عميل Git مثبتًا (الشكل 2).


تين. 1 - تنزيل كود المصدر من موقع


الشكل. 2 - استنساخ المستودع

2. لكي لا يتم الخلط بينك في المستقبل ، أعد تسمية المجلد (هذا اختياري) ، على سبيل المثال ، مثل "electron_webix_2" وافتحه في Visual Studio Code (الشكل 3).


تين. 3 - افتح المشروع

3. تثبيت العناصر اللازمة. أول شيء عليك القيام به هو التنزيل من الرابط الموجود في الأدوات أعلاه "Node.JS" وتثبيته. بدون "Node.JS" ، لا يمكنك فعل أي شيء آخر. بعد ذلك ، افتح وحدة التحكم "Ctr +" في Visual Studio Code وأدخل الأوامر التالية واحدًا تلو الآخر (الشكل 4):

  • "تثبيت Npm - حفظ الإلكترون" ؛
  • msgstr "تثبيت Npm jquery".


تين. 4 - تثبيت Node.JS و JQuery

4. بعد ذلك ، ما زلت بحاجة إلى إطار عمل "D3.js" ، كما ننزله باستخدام الرابط من الأدوات (ملف "d3.zip"). من الأرشيف الذي تم تنزيله "d3.zip" ، نستخرج الملف "d3.js" ونضعه في مجلد "libs" (الشكل 5).


تين. 5 - إضافة مكتبة D3.js

في محطة العمل هذه ، قمنا بإعدادها.

كتابة الواجهة


الآن بعد أن تم إعداد مكان العمل ، دعنا نذهب مباشرة إلى إنشاء تطبيقنا. وستتألف من عناصر "العرض" التالية:

  • - شريط الأدوات ، عنصر Webix قياسي. سيتم وضع هذا العنصر في أعلى النافذة وسيحتوي على أزرار التحكم في النافذة واسم التطبيق. لقد أنشأنا بالفعل عنصر الواجهة هذا في مواد المقالة السابقة ، وهنا لن نغير أي شيء ؛
  • - وجهة نظري ، والتي يجب أن ننشئها أنا وأنت ، إذا جاز التعبير ، "عرض" مخصص. ستكون المنطقة التي سيتم فيها إنشاء الرسم البياني لوظيفتنا باستخدام إطار عمل "D3.js". من بين أمور أخرى ، سيتم تدريس هذه المنطقة للتكيف مع حجم نافذة تطبيقنا. ضعه في منتصف نافذة التطبيق ؛
  • - شريط التمرير ، وهو عنصر قياسي في "Webix". يسمح لك هذا العنصر بتغيير قيمته باستخدام ما يسمى "شريط التمرير". سنقوم بإنشاء 3 قطع من هذه العناصر ، وسيكون كل منها مسؤولاً عن تغيير معلمة معينة من وظيفتنا "a أو b أو c". ضعهم في أسفل نافذة التطبيق.

هيا بنا نبدأ. افتح ملف “enderer.js ”وقم بتحريره أي نزيل العناصر التي لا نحتاجها من المقالة السابقة ونستبدلها بالعناصر الموضحة أعلاه.

كان ملف "enderer.js "كما يلي:

//   
const { remote } = require('electron')
//           
let WIN = remote.getCurrentWindow()
//   webix
const webix = require('./libs/webix.min.js')
//  JQuery
$ = require('jquery')
//               
webix.ui(
    {
        "id": 1587908357897,
        "rows": [
            {
                "css": "webix_dark",
                "view": "toolbar",
                "height": 0,
                "cols": [
                    { "view": "label", "label": "Elcetron +Webix its cool!", css:"head_win" },
                    { "label": "-", "view": "button", "height": 38, "width": 40, id:"min-bt" },
                    { "label": "+", "view": "button", "height": 38, "width": 40, id:"max-bt" },
                    { "label": "x", "view": "button", "height": 38, "width": 40, id:"close-bt" }
                ]
            },
            {
                "width": 0,
                "height": 0,
                "cols": [
                    { "url": "demo->5ea58f0e73f4cf00126e3769", "view": "sidebar", "width": 177 },
                    {
                        "width": 0,
                        "height": 0,
                        "rows": [
                            { "template": "Hello WORLD! ", "view": "template" },
                            {
                                "url": "demo->5ea58f0e73f4cf00126e376d",
                                "type": "bar",
                                "xAxis": "#value#",
                                "yAxis": {},
                                "view": "chart"
                            }
                        ]
                    }
                ]
            }
        ]
    }
)

//  
$$("close-bt").attachEvent("onItemClick", () => {
    const window = remote.getCurrentWindow();
    window.close();
})

//  
$$("min-bt").attachEvent("onItemClick", () => {
    const window = remote.getCurrentWindow();
    window.minimize();
})

//  
$$("max-bt").attachEvent("onItemClick", () => {
    const window = remote.getCurrentWindow();
    if (!window.isMaximized()) {
        window.maximize();
    } else {
        window.unmaximize();
    }
})

سيصبح هكذا:

//   
const { remote } = require('electron')
//           
let WIN = remote.getCurrentWindow()
//   webix
const webix = require('./libs/webix.min.js')
//  JQuery
$ = require('jquery')
//               
webix.ui(
    {
        "id": 1587908357897,
        "rows": [
            {
                // view : toolbar - 1   
                "css": "webix_dark",
                "view": "toolbar",
                "height": 0,
                "cols": [
                    //  
                    { "view": "label", "label": "Electron + Webix + D3.js", css:"head_win" },
                    //  " "
                    { "label": "-", "view": "button", "height": 38, "width": 40, id:"min-bt" },
                    //  " "
                    { "label": "+", "view": "button", "height": 38, "width": 40, id:"max-bt" },
                    //  
                    { "label": "x", "view": "button", "height": 38, "width": 40, id:"close-bt" }
                ]
            },
            // view : myview -    ,      .
            { "view": "myview", id: "d3_chart" },
            {
                "cols": [
                    // view : slider - 3 .     sin
                    {
                        "label": "Amplitude", "title": "#value#", "value": 50, "view": "slider", id: "slider_amplitude",
                    },
                    // view : slider - 4 .      sin   Y
                    {
                        "label": "Bias", "title": "#value#", "value": 0, "view": "slider", "height": 38, id: "slider_scope", min:-50, max:50, step:1,
                    },
                    // view : slider - 5 .     sin
                    {
                        "label": "Frequency", "title": "#value#", "value": 0.005, "view": "slider", "height": 38, id: "slider_freq", min:0, max:0.1, step:0.001,
                    }
                ]
            }
        ]
    }
)

//  
$$("close-bt").attachEvent("onItemClick", () => {
    const window = remote.getCurrentWindow();
    window.close();
})

//  
$$("min-bt").attachEvent("onItemClick", () => {
    const window = remote.getCurrentWindow();
    window.minimize();
})

//  
$$("max-bt").attachEvent("onItemClick", () => {
    const window = remote.getCurrentWindow();
    if (!window.isMaximized()) {
        window.maximize();
    } else {
        window.unmaximize();
    }
})

دعنا نفكر بمزيد من التفصيل في المعلمات التي تتضمن "{" view ":" myview "، id:" d3_chart "}":
- view: myview - type "view" ، في حين أنها غير موجودة ، لم ننشئها بعد ؛
- id: d3_chart - معرف "Webix" ، سنستخدمه للإشارة إلى عنصرنا.
سأشرح أيضًا معلمات عنصر "المنزلق" من أجل الاكتمال:
- عرض: المنزلق - نوع "المنظر" ، المنزلق ؛
- تسمية: "نص" - تسمية سيتم عرضها على شريط التمرير ؛
- العنوان: "#value" - القيمة المعروضة حاليًا للشريط ؛
- القيمة: "القيمة" - قيمة شريط التمرير الافتراضية ؛
- دقيقة: "القيمة" - الحد الأدنى لقيمة شريط التمرير ؛
- الحد الأقصى: "القيمة" - الحد الأقصى لقيمة شريط التمرير "؛
- الخطوة:" القيمة "- خطوة تغيير قيمة شريط التمرير.
يمكنك قراءة المزيد حول جميع معلمات عناصر Webix هنا docs.webix.com/desktop__components.html

إنشاء "myview"


الآن قم بإنشاء ملف "view_chart.js" حيث نحدد نوعنا الجديد "myview" ونفتحه في "VSC".


تين. 6 - الشروع في تحرير view_chart.js

أضف الكود التالي إليها:

webix.protoUI({
    name: "myview",
    $init: function () {
    },
    redraw: function (a, b, c) {
    },
}, webix.ui.view);

تم تصميم وظيفة webix.protoUI لإنشاء عناصر Webix مخصصة استنادًا إلى العناصر القياسية. خذ بعين الاعتبار المعلمات التي تم تمريرها إلى هذه الوظيفة:

  • الاسم - اسم العنصر الذي تم إنشاؤه ؛
  • $ init هي دالة سيتم تشغيلها عند إنشاء عنصر. وبعبارة أخرى ، هو مُنشئ.
  • redraw - وظيفتنا معك ، والتي ستكون مسؤولة عن إعادة رسم الرسم البياني للدالة. سنمرر قيم معلمات متغيراتنا "أ ، ب ، ج"
  • webix.ui.view هو العنصر الرئيسي لعنصرنا.

يمكنك قراءة المزيد عن webix.protoUI هنا
، فعندما يصبح إطار "العرض" الخاص بنا جاهزًا ، سنكتب بعض الوظائف التي ستكون مسؤولة عن رسم الرسم البياني للخطيئة.
ستبدو دالة حساب قيم دالة sin كالتالي:
function calcsin(a, b, c) {
    dataset = [];
    for (var i = 1; i < 360; i++) {
        dataset.push({ "x": i, "y": a * Math.sin(b * i) + c });
    };
};


كل شيء بسيط للغاية هنا ، نستبدل قيم المعلمات في الدالة الرياضية sin ونحفظ النتيجة في مصفوفة. قم بإضافته إلى نهاية الملف "view_chart.js".
بعد ذلك ، أضف إلى نهاية الملف "view_chart.js" دالة سترسم رسمًا بيانيًا باستخدام إطار عمل D3.js ، ستبدو كما يلي:
function drawSin() {
    $(document).ready(function () {
        width = $("#mycontent").width() - margin.left - margin.right
        height = $("#mycontent").height() - margin.top - margin.bottom;
        var xScale = d3.scaleLinear()
            .domain([0, 360]) 
            .range([0, width]); 

        var yScale = d3.scaleLinear()
            .domain([-100, 100]) 
            .range([height, 0]);  

        var line = d3.line()
            .x(function (d, i) { return xScale(d.x); }) 
            .y(function (d) { return yScale(d.y); })
            .curve(d3.curveMonotoneX)

        var svg = d3.select("#mycontent").append("svg")
            .attr("float", "center")
            .attr("class", "webix_chart")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height/2 + ")")
            .call(d3.axisBottom(xScale)); 

        svg.append("g")
            .attr("class", "y axis")
            .call(d3.axisLeft(yScale))

        svg.append("path")

            .datum(dataset) 
            .attr("class", "line") 
            .attr("d", line); 
    })

}

ترتيب الوظيفة المعطاة هو كالتالي:
- حساب حجم الرسم البياني نسبة إلى عنصر div الذي يتم تعبئته به "عرض" و "ارتفاع" ؛
- نقيس قيم الرسم البياني بـ "X" و "Y" ؛
- إنشاء عنصر "html" "svg" نرسم فيه المحور "X" والمحور "Y" والرسم البياني نفسه ؛
الآن بعد أن أصبحت وظائف حساب مخططنا وعرضه جاهزة ، سنربط بين مكتبتين ونعلن عن العديد من المتغيرات في بداية ملف "view_chart.js":
//     D3.js
const d3 = require("./libs/d3")
//   JQuery
$ = require('jquery')
//          X    Y
var dataset = [];
//         
var margin = { top: 50, right: 50, bottom: 50, left: 50 }
    , width = $("#mycontent").width() - margin.left - margin.right 
    , height = $("#mycontent").height() - margin.top - margin.bottom;

سيخزن المتغيران "العرض" و "الارتفاع" عرض الرسم البياني وارتفاعه ، مع مراعاة المسافة البادئة.
بعد ذلك ، ارجع إلى الوظيفة "webix.protoUI" واكتب وظائفها:
webix.protoUI({
    name: "myview",
    $init: function () { //  View
        //   div  id=mycontent.      
        this.$view.innerHTML = "<div id='mycontent'></div>"
        //   calcsin       data  
        calcsin(60, 0.05, 0)
        //   drawSin        data
        drawSin()
    },
    redraw: function (a, b, c) { //    
        //   
        $("#mycontent").html("")
        //       data
        calcsin(a, b, c)
        //  
        drawSin()
    },
}, webix.ui.view);

مليئة المحتوى وظيفتين. يتم تنفيذ الحرف الأول الأول مرة واحدة فقط عند إنشاء "العرض". سيتم استدعاء الثاني عندما نحتاج إلى إعادة رسم المخطط.
الآن ستبدو محتويات الملف "view_chart.js" كما يلي:
//     D3.js
const d3 = require("./libs/d3")
//   JQuery
$ = require('jquery')
//          X    Y
var dataset = [];
//         
var margin = { top: 50, right: 50, bottom: 50, left: 50 }
    , width = $("#mycontent").width() - margin.left - margin.right 
    , height = $("#mycontent").height() - margin.top - margin.bottom;

webix.protoUI({
    name: "myview",
    $init: function () { //  View
        //   div  id=mycontent.      
        this.$view.innerHTML = "<div id='mycontent'></div>"
        //   calcsin       data  
        calcsin(60, 0.05, 0)
        //   drawSin        data
        drawSin()
    },
    redraw: function (a, b, c) { //    
        //   
        $("#mycontent").html("")
        //       data
        calcsin(a, b, c)
        //  
        drawSin()
    },
}, webix.ui.view);



function drawSin() {
    $(document).ready(function () {
        width = $("#mycontent").width() - margin.left - margin.right
        height = $("#mycontent").height() - margin.top - margin.bottom;
        var xScale = d3.scaleLinear()
            .domain([0, 360]) 
            .range([0, width]); 

        var yScale = d3.scaleLinear()
            .domain([-100, 100]) 
            .range([height, 0]);  

        var line = d3.line()
            .x(function (d, i) { return xScale(d.x); }) 
            .y(function (d) { return yScale(d.y); })
            .curve(d3.curveMonotoneX)

        var svg = d3.select("#mycontent").append("svg")
            .attr("float", "center")
            .attr("class", "webix_chart")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height/2 + ")")
            .call(d3.axisBottom(xScale)); 

        svg.append("g")
            .attr("class", "y axis")
            .call(d3.axisLeft(yScale))

        svg.append("path")

            .datum(dataset) 
            .attr("class", "line") 
            .attr("d", line); 
    })

}

function calcsin(a, b, c) {
    dataset = [];
    for (var i = 1; i < 360; i++) {
        dataset.push({ "x": i, "y": a * Math.sin(b * i) + c });
    };
};


بعد ذلك ، تحتاج إلى ربط محتويات الملف "view_chart.js" في ملف "overer.js ". لماذا نحتاج إلى إضافة السطر "مطلوب (" ./ view_chart.js ") إلى أعلى ملف adver.js كما هو موضح أدناه:
//   
const { remote } = require('electron')
//           
let WIN = remote.getCurrentWindow()
//   webix
const webix = require('./libs/webix.min.js')
//  JQuery
$ = require('jquery')
//  view_chart.js
require("./view_chart.js")


تحتاج الآن إلى إضافة زوجين من الأنماط إلى ملف "styles.css" ، وفتحه وإضافة أنماط "svg path" و "#mycontent" كما هو موضح أدناه:
.head_win {
    -webkit-app-region: drag;
}

/*   */
svg path{
    /*   */
    stroke: #666;
    /*   */
    fill: none;
    /*    */
    stroke-width: 1;
}

/*   mycontent,     */
#mycontent { 
    /*     */
    text-align: center;
    /*   */
    overflow: none;
    /*   */
    border: 1px solid black;
    /*     */
    background-color: antiquewhite;
    /*   */
    height: calc(100% - 2px);
}

بعد الانتهاء من الأنماط ، يمكنك محاولة تشغيل تطبيقنا ومعرفة ما حدث. لذا ، اضغط على "F5" وبعد ذلك يجب أن تظهر نافذة على الشاشة كما هو موضح في الشكل 7.


الشكل. 7 - نافذة طلبنا

ماذا نرى به؟ الجزء العلوي هو شريط أدوات Webix القياسي. الجزء الأوسط هو الرسم البياني الذي أنشأناه في رؤيتي. الجزء السفلي هو ثلاثة منزلقات يجب علينا تعليمها لتغيير قيم معلمات وظيفتنا.

دعونا نجعل أشرطة التمرير تعمل


الآن دعنا ننتقل إلى الخطوة التي سنعيد رسم الرسم البياني في منتصف تطبيقنا ، اعتمادًا على قيم منزلقات "Amplitude" و "Bias" و "Frequency". لماذا نضيف معالج الأحداث "onChange" إلى أشرطة التمرير كما هو موضح أدناه:

// view : slider - 3 .     sin
                    {
                        "label": "Amplitude", "title": "#value#", "value": 50, "view": "slider", id: "slider_amplitude",
                        on: {
                            onChange: function () {
                                $$("d3_chart").redraw($$("slider_amplitude").getValue(), $$("slider_freq").getValue(), $$("slider_scope").getValue());
                            }
                        }
                    },
                    // view : slider - 4 .      sin   Y
                    {
                        "label": "Bias", "title": "#value#", "value": 0, "view": "slider", "height": 38, id: "slider_scope", min:-50, max:50, step:1,
                        on: {
                            onChange: function () {
                                $$("d3_chart").redraw($$("slider_amplitude").getValue(), $$("slider_freq").getValue(), $$("slider_scope").getValue());
                            }
                        }
                    },
                    // view : slider - 5 .     sin
                    {
                        "label": "Frequency", "title": "#value#", "value": 0.005, "view": "slider", "height": 38, id: "slider_freq", min:0, max:0.1, step:0.001,
                        on: {
                            onChange: function () {
                                $$("d3_chart").redraw($$("slider_amplitude").getValue(), $$("slider_freq").getValue(), $$("slider_scope").getValue());
                            }
                        }
                    }

في هذا المعالج ، سوف نصل إلى عنصرنا من خلال "معرفه" ونستدعي وظيفة "إعادة الرسم" التي أنشأناها سابقًا لإعادة رسم المخطط ، ونمرره بالقيم الحالية لأشرطة التمرير. انقر على "F5" ، وقم بتشغيل تطبيقنا وحاول تغيير القيم (الشكل 8).


تين. 8 - التحقق من وظائف المنزلق

اسحب الرسم البياني بعد النافذة


وأخيرًا ، نضيف وظيفة من شأنها تكييف مخططنا مع حجم النافذة عندما تتغير. لماذا نفتح الملف "view_chart.js" في المحرر ونضيف معالجًا في نهايته يلتقط تغييرات النافذة كما هو موضح أدناه:

window.onresize = function ( e ) {
  
    $("#mycontent").html("")
    drawSin()
}

تعمل هذه الوظيفة عند تغيير حجم النافذة. تنحصر وظيفتها في مسح محتويات كتلة "mycontent" وإعادة رسم الرسم البياني (استدعاء وظيفة "drawSin ()"). في كل مرة يتم استدعاء دالة drawSin () ، يتم تعيين متغيرات العرض والارتفاع للمعلومات الحالية حول أحجام (ارتفاع وعرض) كتلة mycontent ، وبعد ذلك سيغير الرسم البياني المقياس ليلائم أبعاد الكتلة.

استنتاج


هذا كل شئ. آمل أن تكون هذه المعلومات مفيدة لك. شكرا! يمكن تنزيل المصادر هنا .

All Articles