Category: Developer

งานพัฒนาระบบ, เขียนโปรแกรม

  • คู่มือเทคนิคการใช้งาน Function พื้นฐานใน Itextsharp สำหรับมือใหม่ ตอนที่ 1

    หลังจากที่ผู้เขียนได้ทดลองใช้งาน Itextsharp มาเป็นระยะเวลานึง ในระหว่างที่ได้ทำการใช้งานนั้น ก็เกิดปัญหาต่างๆจากการใช้งานมากมาย ซึงมาจากความไม่รู้ของผู้เขียนเอง เลยได้ทำการรวบรวมข้อมูลวิธีใช้งานเบื้องต้น ให้กับผู้ที่สนใจใช้งาน Itextshap ได้สะดวกมากขึ้น ซึ่งจริงๆแล้วมีพี่ท่านนึงได้เขียนบทความเกี่ยวกับเรื่องนี้ไว้แล้วบ้างส่วน สำหรับผู้ที่สนใจสามารถอ่านได้จาก Link นี้ครับ สร้างเอกสาร PDF ด้วย iTextSharp ส่วนในบทความนี้จะทำการขยายรายละเอียดลงไปในแต่ละ Function ครับ โดย Function ที่จะพูดถึงในบทความนี้มีดังต่อไปนี้

    1. BaseFont และ Font คืออะไร

    ถ้าจะให้พูดถึง Function Basefont ให้เข้าใจง่ายๆแล้วละก็ หน้าที่ของมันคือเป็นการประกาศให้ตัว Itextsharp ทราบว่าเราต้องการใช้ Font อะไรในการทำงานบ้าง สามารถเทียบได้กับช่องเลือก Font ในโปรแกรม Office นั้นแหละครับ และ Function Font จะสร้างรูปแบบของ Font ได้ตามที่เราต้องการ ไม่ว่าจะเป็น ตัวหนา เอียง ขีดเส้นใต้ ขีดเส้นทับ เป็นค่าเริ่มต้นไว้ แล้วหลังจากนั้นเราก็สามารถนำไปใช้งานได้ตลอดการสร้างเอกสาร โดยอ้างอิง Font ที่ใช้งานมาจาก BaseFont อีกทีนึง

    ตอนนี้ก็มาดูรูปแบบการสร้าง BaseFont และทำ Font ต้นแบบเป็นตัวหนานะครับโดยสามารถทำได้ 2 วิธีคือ

    • กรณีที่เรามีชุดของ Font มาแล้วนะครับ(คือแยกตัวหนา ตัวเอียง ขีดเส้น)
    BaseFont bf_bold = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\THSarabunNewBold.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true);
    
    Font fnt = new Font(bf, 12);
    
    
    • กรณีที่เรามี Font แค่รูปแบบเดียว
    BaseFont bf = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\THSarabun.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true);
    
    Font fnt = new Font(bf, 12,Font.BOLD);

    จากตัวอย่างทั้ง 2 แบบ เราจะมี Font ที่มีรูปแบบของตัวหนาในชื่อของตัวแปร fnt ไว้ใช้งานได้เหมือนกันครับ โดยจะมีความแตกต่างกันคือ แบบที่ 1 นั้น จะเป็นการนำเอารูปแบบของ Font ที่ได้อ้างอิงเอาไว้มาแสดงผลบนเอกสารโดยตรง ต่างจากแบบที่ 2 จะเป็นการนำเอา Font ที่ได้ประกาศเอาไว้แบบตัวอักษรปกติมาแปลงผ่านตัว Itextsharp ให้กลายเป็นตัวหนา อีกทีโดยผ่านทาง property Font.BOLD ครับ แล้วหลายๆท่านคงสงสัยว่าทั้ง 2 แบบมีข้อดีข้อเสียอย่างไร ในแบบที่ 1 การแสดงผลของ font จะถูกต้อง สวยงามตามต้นฉบับ font ที่เราได้ทำการอ้างอิงไว้ครับ แต่ข้อเสียคือ ถ้าเราต้องการสร้าง Font ต้นแบบไว้ในหลายลักษณะ เราก็ต้องอ้างอิงตัวรูปแบบ Font ที่เราต้องการทั้งหมดไปด้วย ส่วนแบบที่ 2 นั้น เราสามารถใช้ Font อ้างอิงเพียงอันเดียว แล้วสร้างรูปแบบ Font ตามที่เราต้องการได้ไม่จำกัด แต่การแสดงผลอาจไม่สวยงามเท่ากับแบบที่ 1

    แล้วถ้าเราต้องการที่จะใส่สีให้กับ font ของเราละ จะสามารถทำได้หรือไม่ คำตอบคือ ทำได้ครับ โดยใน Function Font นั้น ถูกออกแบบมาให้เราสามารถทำรูปแบบของ font ได้หลากหลายรูปแบบครับ มาดูตัวอย่างกัน

    BaseFont bf = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\THSarabun.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true);
    Font fnt = new Font(bf, 12,Font.BOLD,BaseColor.red);
    Font fnt = new Font(bf, 16,Font.Italic,BaseColor.green);
    Font fnt = new Font(bf, 12,Font.BOLD | Font.Italic);
    Font fnt = new Font(bf, 12 Font.BOLD | Font.Underline, BaseColor.blue)

    จากตัวอย่างที่ยกให้ดูในข้างต้นนั้น เมื่อนำไปใช้จะได้ผลลัพท์ดังต่อไปนี้

    ตัวอย่างที่ 1  AAA

    ตัวอย่างที่ 2  AAA

    ตัวอย่างที่ 3  AAA

    ตัวอย่างที่ 4  AAA

    จากตัวอย่างทั้ง 4 แบบนั้น ผมได้นำวิธีการทำแบบที่ 2 มาใช้คือการอ้างอิง font จากรูปแบบเดียว แล้วมาแปลงรูปแบบจาก Function Font อีกรอบ ตามที่เราต้องการครับ ดูแล้วไม่ยากเลยใช่ไหมครับ

    ตอนนี้ก็มาถึงข้อสรุปการใช้งาน Function BaseFont และ Font คือ

    • สร้าง Basefont ขึ้นมาโดยอ้างอิงไปยัง Font หรือ ชุดรูปแบบ Font ที่เราต้องการใช้งาน
    • สร้าง Font ตามรูปแบบที่เราต้องการ โดยอ้างอิงจาก Basefont
    • รูปแบบที่สามารถกำหนดได้มี ขนาดของFont รูปแบบของ Font(สามารถผสมได้) และสีของ Font

    2. Function สำหรับสร้างเอกสารและ export ออกไปเป็น PDF

    ส่วนต่อมาที่ผู้เขียนจะพูดถึงนั้น เป็นส่วนค่อนข้างสำคัญมากเลยทีเดียว ถ้าเราไม่ทำการเรียกใช้งาน เราก็ไม่สามารถที่จะสร้างเอกสารได้เลยครับ ซึ่ง Function ที่จะพูดถึงหลักๆคือ Document และ Function สำหรับสร้างไฟล์(ขึ้นอยู่กับภาษาที่ใช้งาน) โดยเจา Function Document ทำหน้าที่เหมือนดังตัวเอกสารหรือกระดาษนั้นเอง เหมือนเราใช้งานคำสั่งนี้ เราก็จะได้หน้ากระดาษปล่าวๆพร้อมใช้งานแล้ว โดยเราสามารถกำหนดค่าต่างๆของกระดาษได้ตามที่เราต้องการ มาดูตัวอย่างกันเลยดีกว่าครับ

    Document pdfDoc = new Document(PageSize.A4, 30, 30, 20, 20);

    จากตัวอย่าง จะเห็นว่าเราทำการสร้างเอกสารขึ้นมาโดยใช้ชื่อว่า pdfDoc เป็นเอกสารขนาด A4 โดยมีการกั้นขอบกระดาษไว้ ด้านซ้าย 30 ด้านบน 30 ด้านขวา 20 และด้านล่าง 20  แล้วค่าตัวเลขนี้มาจากไหน เราจะรู้ได้ยังไงว่าโปรแกรมจะเว้นที่ว่างบนกระดาษเท่าไร ผมมีคำตอบครับ จากการค้นหามามีการกำหนดเป็นมาตรฐานของกระดาษ โดยสามารถอ้างอิงได้ตามนี้ครับ 1 in = 2.54 cm = 72 points. ซึงตัวเลข 30,30,20,20 ก็คือค่า point นั้นเอง จากตัวอย่าง 30 point เท่ากับ 0.4 นิ้ว หรือประมาณ 1 เซนติเมตรนั้นเอง แล้วถ้าเราต้องการเปลี่ยนขนาดกระดาษละ จะต้องทำอย่างไร เราสามารถเปลี่ยนขนาดของกระดาษได้จาก Property PageSize นั้นเอง ซึ่งมีรูปแบบกระดาษให้เลือกมากมายไม่ว่าจะ ซองจดหมาย A4 A3 A2 เป็นต้น ซึ่งการเลือกขนาดของกระดาษก็ขึ้นอยู่กับลักษณะงานที่เราต้องการจะแสดงว่าต้องการขนาดเท่าไร แล้วเราสามารถตั้งค่ากระดาษเป็นแนวตั้งหรือแนวนอนได้ไหม สามารถทำได้เช่นกันครับ ตามตัวอย่างนี้เลย

    Document pdfDoc = new Document(PageSize.A4.Rotate(), 20, 15, 10, 10);

    จากตัวอย่างเราสามารถทำได้ง่ายๆโดยใช้ property PageSize และกำหนดให้ทำการพลิกกระดาษ โดยคำสั่ง Rotate() ต่อท้ายขนาดกระดาษที่เราได้เลือกเอาไว้ ต่อมาเมื่อเราทำการตั้งค่ากระดาษเรียบร้อยแล้ว เราต้องทำการเปิดตัวเอกสารของเรา ให้สามารถบันทึกข้อมูลตามที่เราต้องการลงไปได้ ด้วยคำสั่ง Open() และทำการปิดเอกสารเมื่อทำการบันทึกข้อมูลเสร้จเรียบร้อย ด้วยคำสั่ง Close() มาดูตัวอย่างกัน

    Document pdfDoc = new Document(PageSize.A4, 30, 30, 20, 20);
    pdfDoc.Open();
    ...
    pdfDoc.Close();

    นี้ก็ถือว่าจบส่วนของการสร้างเอกสารและตั้งค่ากระดาษแล้วครับ ส่วนต่อมาเป็นส่วนการเขียนเอกสารจริงผ่าน Function ของภาษาที่เราใช้งานกัน โดยตัวอย่างของผู้เขียนนั้นใช้งานภาษา C# บน .Netframework ไปดูตัวอย่างการเขียนได้เลยครับ

    Document pdfDoc = new Document(PageSize.A4.Rotate(), 20, 15, 10, 10);
    PdfWriter.GetInstance(pdfDoc, System.Web.HttpContext.Current.Response.OutputStream);
    pdfDoc.Open();
    ...
    pdfDoc.Close();
    HttpContext.Current.Response.ContentType = "application/pdf";
    HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=StatSummary_" + DateTime.Now.ToString("yyyyMMdd") + ".pdf");
    System.Web.HttpContext.Current.Response.Write(pdfDoc);
    

    จากตัวอย่าง ผู้เขียนได้ทำการระบุว่าเอกสารที่เราสร้างนั้นกำหนด ContentType เป็น application/pdf เพื่อ Response เป็น Pdf ในบรรทัดที่ 6 และทำการตั้งชื่อเอกสาร ในบรรทัดที่ 7 สุดท้ายก็ทำการสร้างเอกสารและบันทึกไว้บนเครื่อง ในบรรทัดที่ 8 ก็ถือว่าจบในส่วนของการสร้างเอกสารแล้วครับผม


    ในส่วนของบทความนี้ผู้เขียนจะกล่าวถึงไว้แค่ 2 หัวข้อก่อนแล้วกันครับ ส่วนหัวข้อต่อๆไปจะมาเขียนต่อในบทความถัดไป โดยเนื้อหาส่วนไหนผิด ใช้คำไม่สุภาพไม่ถูกต้อง ก็ขออภัยไว้ ณ ที่นี้ด้วยครับ ขอบคุณครับ

  • การกำหนดรูปแบบเอกสารด้วย reStructuredText

    การสร้างเอกสารด้วย reStructuredText syntax ทำให้เอกสารที่พัฒนาง่ายในการอ่าน จัดรูปแบบได้ตามที่เห็น รูปแบบของ markup เป็น plaintext ซึ่งจะใช้ parser ในการแปลงให้อยู่ในรูปแบบเอกสารที่ต้องการเช่น html หรือ pdf เป็นต้น

    การกำหนดรูปแบบ (Text Formatting)

    1. Paragraphs

    Paragraphs คือ block พื้นฐานของ reStructuredText ซึ่งแต่ละ paragraphs จะถูกแยกด้วย blank line 1 บรรทัด หรือมากกว่าหนึ่งก็ได้ ซึ่งย่อหน้ามีผลกับ reStructuredText ดังนั้นในการกำหนดบรรทัดใน paragraph เดียวกันจะต้องมี ย่อหน้าด้สนซ้ายเท่ากันในระดับเดียวกัน.

    2. Inline markup และ special character

    เราสามารถใช้ตัวอักษรพิเศษในการกำหนดรูปแบบข้อความมีอยู่ด้วยกันหลายตัว  ตัวอักษรพิเศษ * ถูกใช้ในการกำหนดรูปแบบตัวอักษรตัวหนา และ ตัวอักษรตัวเอียง ดังตัวอย่างด้านล่าง

    • ตัวหนา **ภาษาไทย**  จะแสดงผลคือ  ภาษาไทย
    • ตัวเอียง *ภาษาไทย*   จะแสดงผลคือ  ภาษาไทย

    ตัวอักษรพิเศษ backquote  ` จะใช้ในการกำหนดตัวอย่าง  code โดยการใช้งานดังนี้

    ``code sample``

    แต่ถ้าต้องการใช้ * และ `  ในเอกสารด้วยซึ่งจะทำให้สับสนกับ inline markup ได้ ดังนั้นจึงใช้  backslash นำหน้าสำหรับ * และ ` ที่จะใช้แสดงผลของเอกสาร

    3. Lists and Quote-like blocks

    การกำหนด list สามารถทำได้โดยการใช้ * นำหน้า

    * bulleted list
    * bulleted list
    * bulleted list

    สำหรับ numbered list ก็ให้ใช้ตัวเลขนำหน้า

    1. numbered list
    2. numbered list

    ถ้าต้องการ list ที่กำหนดเลขโดยอัตโนมัติให้ใช้ # นำหน้า

    #. numbered list
    #. numbered list

    การกำหนด list ซ้อนกันหลายๆชั้นสามารถทำได้ แต่ต้องแยกแต่ละ list ออกด้วย blank line

    *. bulleted list
    *. bulleted list
        *. bulleted list
        *. bulleted list
    *. bulleted list

    4. Source code

    การกำหนด code block ทำได้โดยใช้ special marker :: ที่ตอนจบของ paragraph และจะต้องแยกจากส่วนอื่นด้วย blank line เช่นเดียวกับ paragraph ทั่วไป

    This is a normal text paragraph. The next paragraph is a code sample::
    
                public class reStructuredTest {
                        public reStructuredTest(){
                        }
                }
    

    5. Table

    การสร้างตารางทำได้ในสองรูปแบบคือแบบ grid table และ simple table โดยการสร้างตารางแบบ grid table ทำได้ด้วยการวาดตารางด้วยตัวเอง

    +------------------------+------------+----------+----------+
    | Header row, column 1   | Header 2   | Header 3 | Header 4 |
    | (header rows optional) |            |          |          |
    +========================+============+==========+==========+
    | body row 1, column 1   | column 2   | column 3 | column 4 |
    +------------------------+------------+----------+----------+
    | body row 2             | ...        | ...      |          |
    +------------------------+------------+----------+----------+
    

    สำหรับ Simple tables จะเขียนง่ายกว่ารูปแบบแรก แต่มีข้อมจำกัดคือ จะต้องมีมากกว่า 1 row และ column แรกไม่อนุญาติให้มีหลายบรรทัด

    =====  =====  =======
    A      B      A and B
    =====  =====  =======
    False  False  False
    True   False  False
    False  True   False
    True   True   True
    =====  =====  =======
    

    6. Hyperlinks

    การกำหนด hyperlink ทำได้โดยการกำหนดรูปแบบดังนี้

    `Link text <http://example.com/>`_

    section header กำหนดโดยใช้การทำ underlining โดยที่ความยาวของ underlining จะต้องเท่ากับจำนวนตัวอักษรของ header

    =================
    This is a heading
    =================
    

    การกำหนดระดับของ header จะทำได้โดย

    • # ร่วมกับ overline  สำหรับกำหนด  part header
    • * ร่วมกับ overline สำหรับกำหนด chapter header
    • = สำหรับกำหนด section header
    • - สำหรับกำหนด subsection header
    • ^ สำหรับกำหนด subsubsection header
    • ” สำหรับกำหนด paragraph header

     

    อ้างอิง

    1. http://www.sphinx-doc.org/en/1.5.1/rest.html
    2. http://thomas-cokelaer.info/tutorials/sphinx/rest_syntax.html

  • การวิเคราะห์ข้อมูล (What-if Analysis)

                ในหัวข้อนี้เราจะมาพูดถึงการวิเคราะห์ข้อมูลโดยใช้ What-if ซึ่งเป็นเครื่องมือการวิเคราะห์ที่อยู่ใน Excel การวิเคราะห์ข้อมูลแบบ What-if เป็นการเอาสูตรหรือข้อมูลที่มีมาวิเคราะห์เพื่อหาทางเลือกจากสถานการณ์ต่างๆ โดยมีการวิเคราะห์ 3 แบบ คือ สถานการณ์สมมติ(Scenario), ตารางข้อมูล(Data Table) และการค้นหาค่าเป้าหมาย(Goal Seek) สถานการณ์สมมติและตารางข้อมูลจะรับชุดของค่าข้อมูลเข้า(Input) และประเมินล่วงหน้า เพื่อหาผลลัพธ์ที่เป็นไปได้ ส่วนการค้นหาค่าเป้าหมายต่างจากสถานการณ์สมมติและตารางข้อมูลตรงที่ นำผลลัพธ์มาประเมินย้อนกลับ เพื่อหาค่าข้อมูลเข้าที่เป็นไปได้ที่ทำให้เกิดผลลัพธ์นั้นๆ

    1. การค้นหาค่าเป้าหมาย(Goal Seek)

                ปกติเวลาคำนวณเราจะคำนวณตามลำดับ เช่น ยอดขาย–ค่าใช้จ่าย = กำไร แต่ Goad Seek ใช้การระบุผลลัพธ์ที่ต้องการ(Output) แล้วคำนวณค่าข้อมูลเข้า(Input) เพื่อให้ได้ผลลัพธ์ตามที่เราต้องการ

                ตัวอย่าง1 การคำนวณเงินกู้ ปกติจะคำนวณจากเงินต้น ระยะเวลาที่กู้ และดอกเบี้ย และใส่สูตรด้วยฟังก์ชัน PMT (ดูภาพที่ 1) ซึ่งจะได้จำนวนเงินที่ต้องจ่ายในแต่ละเดือน (ดูภาพที่ 2)

    ภาพที่ 1 คำนวณอัตราผ่อนชำระต่องวด

    ภาพที่ 2 จำนวนเงินที่ต้องจ่ายในแต่ละเดือน

     

    เงื่อนไขที่ 1 : ถ้ามีต้องการผ่อนต่อเดือน 10,000 บาท ในระยะเวลา 10 ปี สามารถใช้ Goal Seek คำนวณให้ได้ว่า จะสามารถกู้เงินได้เท่าไหร่? ไปที่ Data > What-if Analysis > Goal Seek (ดูภาพที่ 3)

    ภาพที่ 3 เลือกคำสั่ง Goal Seek

    ในหน้าต่าง Goal Seek (ดูภาพที่ 4) :

    Set cell – cell ที่จะใช้ตั้งค่า โดยคลิกเลือก cell ที่เขียนสูตรเอาไว้ (ในตัวอย่างนี้คือ B5)

    To value – ระบุค่าเป้าหมายที่ต้องการ (ต้องการผ่อนเดือนละ 10,000)

    By changing cell – ระบุ cell ที่ต้องการให้เปลี่ยนแปลงค่าตามเป้าหมายที่กำหนดไว้ (จำนวนเงินที่กู้ได้)

    ภาพที่ 4 กำหนดค่าเป้าหมาย

    สรุป ถ้าต้องการผ่อนเดือนละ 10,000 เป็นระยะเวลา 10 ปี จะต้องกู้เงินจำนวน 949,363 บาท (ดูภาพที่ 5)

    ภาพที่ 5 คำตอบที่ได้ของเงื่อนไขที่ 1

    เงื่อนไขที่ 2 : ถ้าต้องการกู้เงิน 1,000,000 บาท และผ่อนชำระเดือนละ 10,000 บาท จะต้องใช้เวลาเท่าไหร่? (ดูภาพที่ 6)

    ภาพที่ 6 กำหนดค่าเป้าหมาย

    สรุป ถ้าต้องการกู้เงิน 1,000,000 บาท และผ่อนชำระเดือนละ 10,000 บาท จะต้องใช้เวลาประมาณ 129 เดือน (ดูภาพที่ 7)

    ภาพที่ 7 ระยะเวลาผ่อนชำระ(เดือน)

    2. สถานการณ์สมมติ(Scenario)

                ตัวอย่าง2 เปิดร้านขายเบเกอรี่มีเค้กขายอยู่ 12 ชนิด ในการวิเคราะห์กำไรจากการขาย (ดูภาพที่ 8) อาจแบ่งยอดขายได้หลายกรณี เช่น กรณีขายดี(Best Case), กรณีขายไม่ค่อยดี(Worst Case) และกรณีที่น่าจะเป็น(Most Likely) เป็นต้น

     ภาพที่ 8 ตัวอย่างตารางข้อมูลสำหรับคำนวณโดยใช้ Scenario

     

    ไปที่ Data > What-if Analysis > Scenario Manager (ดูภาพที่ 9) จะมีหน้าต่าง Edit Scenario ขึ้นมาให้กด Add…

    • Scenario Name ชื่อของ Scenario
    • Changing cells เป็นเซลล์ที่จะเปลี่ยนค่า ในตัวอย่างเป็นจำนวนเค้ก

    โดยให้ทำการ Add ทั้ง 3 Case – Best Case(จำนวนมากกว่า 100 ชิ้น), Worst Case(อย่างละ 50 ชิ้น), Most Likely Case(อย่างละ 100 ชิ้น)

    ภาพที่ 9 Add Scenario

    ภาพที่ 10 ตัวอย่างกำหนดค่าให้ Most Likely

    กดปุ่ม Summary เพื่อสรุปค่า Scenario จะมีหน้าต่าง Scenario Summary ขึ้นมา ให้เลือก Report type ที่จะแสดงในรายงาน ซึ่งมี 2 แบบ คือ

    • Scenario Summary เป็นตารางสรุปผล Scenario ในแต่ละกรณี (ดูภาพที่ 11)
    • Scenario PivotTable Report เป็น PivotTable แสดงรายละเอียดของ Scenraio

    ภาพที่ 11 Scenario Summary

    3. ตารางข้อมูล(Data Table)

                จากตัวอย่าง1 หากต้องการทราบว่าช่วงเงินกู้ระหว่าง 800,000-1,700,000 บาท ถ้าให้ระยะเวลาผ่อน 10 ปีด้วยกันจะต้องผ่อนเดือนละเท่าไหร่??

                ใส่ค่าช่วงของเงินกู้ที่ต้องการเปลี่ยนแปลง ส่วนจำนวนเงิน 10,533 ให้กด = แล้ว Link ไปที่ช่องผลลัพธ์ที่คำนวณไว้แล้ว ในที่นี้ = B5 ของตัวอย่างที่1 ลากคลุม cell ตามภาพที่ 12 จากนั้นไปที่ Data > What-if Analysis > Data Table… ที่นี้เราจะลองเปลี่ยนยอดเงินกู้ ซึ่งเรียงกันอยู่ในรูปแบบ Column ดังนั้นเราต้องใส่ค่า “จำนวนที่กู้” ลงใน Column Input Cell จะได้ผลลัพธ์ดังภาพที่ 13

    ภาพที่ 12 แสดงวิธีคำนวณด้วยคำสั่ง Data Table

    ภาพที่ 13 ยอดผ่อนต่อเดือนตามจำนวนเงินกู้

    สมมติเราอยากรู้ว่าถ้ายอดเงินกู้ และ ระยะเวลาเปลี่ยน จำนวนเงินที่จะต้องผ่อนต่อเดือนจะเป็นเท่าไหร่??

    ให้ Copy ช่วงเงินกู้มาตั้งไว้ในแนว Column เหมือนเดิม เพิ่มเติมคือระยะเวลาให้ใส่แนว Row(ดูภาพที่ 14) และผลลัพธ์ในภาพที่ 15

    ภาพที่ 14 แสดงการคำนวณ Data Table 2 Input

    ภาพที่ 15 ผลลัพธ์การเปลี่ยนแปลงยอดผ่อนต่อเดือน

     

     

    สามารถอ่านข้อมูลและศึกษาเพิ่มเติมได้

    https://support.office.com/en-us/article/Introduction-to-What-If-Analysis

  • Pass special characters in JavaScript function

    ในการพัฒนาโปรแกรมไม่ว่าจะพัฒนาด้วยภาษาใดก็ตาม ทุกภาษาจะมี special characters ซึ่ง special characters บางตัวอาจจะถูกระบุให้เป็นตัวแปร หรือ ใช้อักขระพิเศษเพื่อระบุอยู่ลำดับสุดท้ายของข้อความของบรรทัด เป็นต้น   ซึ่งตรงส่วนนี้จะทำให้ประสบปัญหาในการนำ special characters ไปใช้งาน นั่นคือจะทำให้เกิด Error ทำให้โปรแกรมไม่สามารถทำงานต่อได้ ซึ่งJavaScript ก็เป็นอีกหนึ่งภาษาที่ประสบปัญหานี้ เช่น การส่ง parameter ผ่าน function ของ JavaScript โดยค่าของ parameter ที่ส่งไปเป็น special characters ทำให้เกิด Error และโปรแกรมไม่สามารถทำงานต่อได้

     

    วันนี้จะขอแนะนำเทคนิคในการแก้ปัญหาดังกล่าว นั่นก็คือ การ Encoding และ Decoding ในที่นี้ผู้เขียนได้พัฒนาในรูปแบบ MVC โดยใช้ JavaScript ในการเรียก Controller จึงใช้วิธีการ Encoding กับ JavaScript และ ทางฝั่ง Controller จะใช้ C# จึงใช้ C# ในการ Decoding ค่ะ
    1.วิธีการ Encoding in JavaScript ในการจะส่ง parameter ผ่านทาง function ของ JavaScript โดยข้อความนั้นมี special characters จำเป็นที่จะต้องมีการ Encoding ในที่นี้เราจะใช้ฟังก์ชัน Escape() ของ JavaScript
    ตัวอย่าง Encoding in JavaScript

    <script>   
    
      function SaveData() {
    
            var txtDocTitle = $('#txtDocTitle').val();
    
    
            $('#pleaseWaitDialog').modal();
            $.ajax({
                type: 'POST',
                contentType: 'application/json; charset=utf-8',
                url: "@Url.Action("SaveDataToTable", "I_EXPENSE")",
                data: "{'budgetYear':'" + valueYear +
                    "' ,'docTitle':'" + escape(txtDocTitle) +
                    "'}",
                success: function (data) {
    
                },
                error: function (data) {
                    alert(data);
                }
            });
        }
          </script>

    จากตัวอย่างกรณีป้อนข้อมูลที่มี special characters เช่น “I’m *&^$ special characters” เมื่อใช้ function escape(“I’m *&^$ special characters”) จะได้ผลลัพธ์ดังนี้

     ผลลัพธ์จากการเรียกใช้ escape()

    I%u2019m%20*%26%5E%24%20special%20characters
    

    หลังจากที่มีการเรียกใช้ escape() จะทำให้สามารถส่ง parameter ที่มี special characters ไปได้โดยไม่พบ Error โปรแกรมสามารถทำงานได้ปกติ เป็นอันผ่านไปหนึ่งด่านในส่วนของการเรียกใช้งาน function ของ JavaScript แต่ทว่าการที่เราจะนำข้อความที่ผ่านการ Encoding มาใช้งานไม่ได้ เนื่องจากจะไม่ถูกต้องตามความต้องการของผู้ใช้งาน จากตัวอย่างข้างต้น ผู้ใช้งานป้อนข้อมูล “I’m *&^$ special characters” สิ่งที่โปรแกรมต้องทำการบันทึกก็ต้องเป็น “I’m *&^$ special characters” ไม่ใช่ “I%u2019m%20*%26%5E%24%20special%20characters” ดังนั้นจึงจำเป็นจะต้องมีการ Decoding เพื่อให้ได้ข้อมูลที่ถูกต้อง
    2.Decoding in C# เมื่อมีการ Encoding เราจำเป็นที่จะต้อง Decoding เพื่อให้ได้ข้อมูลที่ถูกต้องตามที่ผู้ใช้งานได้ป้อนข้อมูล
    ตัวอย่าง Decoding in C#

          var docTitle = HttpUtility.UrlDecode(docTitle, System.Text.Encoding.Default);
           //ตรงส่วนนี้ตัวแปร docTitle จะมีค่าเท่ากับ “I’m *&^$ special characters”  ค่ะ
          

    เมื่อ Decoding แล้ว ก็จะได้ข้อความที่ถูกต้องตามที่ผู้ใช้งานได้ป้อนข้อมูลและสามารถนำไปใช้งานได้อย่างถูกต้องแล้วนะคะ

     

    สำหรับบทความนี้ก็ขอจบเพียงเท่านี้และหวังว่าผู้พัฒนาคงหมดกังวลในส่วนของ Special character ที่ส่งค่า parameter ผ่านทาง JavaScript ได้อย่างไม่มี error มากวนใจผู้พัฒนากันอีกแล้วนะคะ ^_^

     

     

    แหล่งอ้างอิง :

    https://developer.mozilla.org/th/docs/Web/JavaScript/Reference/Global_Objects/escape

    http://stackoverflow.com/questions/3778165/unescape-javascripts-escape-using-c-sharp

  • การค้นหาสถานที่ด้วย Places search box และแสดงผลภาพจากข้อมูล Street View บน Google Maps

           ความเดิมจากตอนที่แล้วของบทความ “การดึงค่าละติจูดและลองจิจูดของสถานที่ด้วย Places search box บน Google Maps” เพื่อแก้ปัญหาในการดึงค่าละติจูด-ลองจิจูดจากชื่อสถานที่ที่ผู้ใช้พิมพ์ค้นหาไว้ โดยมีการนำ “Places search box” มาใส่ไว้ในแผนที่ที่เราต้องการแทนนั้น ถือเป็นตัวช่วยให้กับผู้ใช้ในระดับหนึ่ง  แต่สำหรับในบทความนี้ ผู้เขียนจะขอต่อยอดความรู้ดังกล่าว โดยได้ศึกษาและนำวิธีการแสดงผลภาพจากข้อมูล Street view มาประยุกต์ใช้ร่วมด้วย เพื่อให้ผู้ใช้สามารถมองเห็นสถานที่จริงที่เลือกได้จากแผนที่ได้ด้วย ซึ่งจะยิ่งช่วยอำนวยความสะดวกให้กับผู้ใช้ ทำให้ผู้ใช้สามารถตรวจสอบได้ว่าสถานที่ดังกล่าวเป็นสถานที่ที่ต้องการจะดึงค่าละติจูด-ลองจิจูดจริงหรือไม่ได้อีกทางหนึ่งนั่นเอง ซึ่งวิธีการบางส่วนจะขอยกยอดมาจากบทความก่อนหน้านี้ เกี่ยวกับเรื่องการดึงค่าละติจูด-ลองจิจูดจากการค้นหาโดยใช้ Places search box และจะขอเพิ่มเติมความสามารถในการแสดงผลภาพ Street View  รวมทั้งสามารถคลิกจุดพิกัดใหม่บนแผนที่ เพื่อค้นหาตำแหน่ง สถานที่ตั้ง และรายละเอียด รวมถึงภาพจาก Street View ได้อีกด้วย เพื่อให้การดึงค่าพิกัดใกล้เคียงความจริงมากที่สุด โดยมีวิธีการดังนี้

    • ส่วนของสไตล์ชีทในการแสดงผล ขึ้นกับการตกแต่งของผู้พัฒนาแต่ละท่าน
    <!—ส่วนของ Style Sheets->
    <style>
    html, body {
     height: 100%;
     margin: 0;
     padding: 0;
    }
    #map {
     width: 100%;
     height: 400px;
    }
    .controls {
     margin-top: 10px;
     border: 1px solid transparent;
     border-radius: 2px 0 0 2px;
     box-sizing: border-box;
     -moz-box-sizing: border-box;
     height: 32px;
     outline: none;
     box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    }
    #searchInput {
     background-color: #fff;
     font-family: Roboto;
     font-size: 15px;
     font-weight: 300;
     margin-left: 12px;
     padding: 0 11px 0 13px;
     text-overflow: ellipsis;
     width: 80%;
    }
    #searchInput:focus {
     border-color: #4d90fe;
    }
    
    </style>
    
    • ส่วนของการอ้างอิง libraries เพื่อใช้งาน Google API
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCRbMoDPc_mTv3D3QPqe0Ar84nSvRhA8nk&libraries=places&callback=initMap" async defer></script>
    
    • ส่วนของการประกาศค่าเริ่มต้นและตัวแปร รวมถึงการเรียกใช้งานฟังก์ชั่นเพื่อใช้ในการแสดงผล
      • ฟังก์ชั่น initMap() ซึ่งจะเรียกใช้งานตอนเริ่มต้นโหลดหน้าจอขึ้นมา
    <script>
     var panorama;
     var map;
     var markers = [];
    /***** function ในการประกาศค่าเริ่มต้นให้กับแผนที่*****/
     function initMap() {
    
    /***** ประกาศตำแหน่งพิกัดกึ่งกลางให้กับการแสดงผลแผนที่ ในที่นี้กำหนดเป็นกรุงเทพมหานคร*****/
     var center_point = { lat: 13.7563309, lng: 100.50176510000006 };
     var sv = new google.maps.StreetViewService();
    
    /***** เป็นส่วนของการแสดงผลภาพจาก Street View *****/
     panorama = new google.maps.StreetViewPanorama(document.getElementById('pano'));
    
     /***** กำหนดรายละเอียดคุณสมบัติของแผนที่*****/
     var map = new google.maps.Map(document.getElementById('map'), {
     center: {lat: center_point.lat, lng: center_point.lng},
     zoom: 13,
     streetViewControl: false // เป็นส่วนที่ Set เพิ่มเติมจากปกติ
     });
    
    sv.getPanorama({ location: center_point, radius: 50 }, processSVData);
    
    /***** กำหนด event เมื่อมีการคลิกแผนที่*****/
     map.addListener('click', function(event) {
     
    /***** ล้างข้อมูลการกำหนดจุด เพื่อให้มีการกำหนดจุดพิกัดเพียงจุดเดียว*****/
     for (i = 0; i < markers.length; i++) {
     markers[i].setMap(null);
     }
    
    /***** ดึงค่าข้อมูลจาก Street View ตามพิกัดที่คลิกบนแผนที่ *****/
     sv.getPanorama({ location: event.latLng, radius: 50 }, processSVData);
     var geocoder = new google.maps.Geocoder();
     geocoder.geocode({
     'latLng': event.latLng
     }, function(results, status) {
     if (status == google.maps.GeocoderStatus.OK) {
    
    /***** แสดงผลข้อมูลรายละเอียดสถานที่*****/
     if (results[0]) {
        var place = results[0];
         for (var i = 0; i < place.address_components.length; i++) {
           if (place.address_components[i].types[0] == 'postal_code') {
             document.getElementById('postal_code').innerHTML = place.address_components[i].long_name;
          }
     if (place.address_components[i].types[0] == 'country') {
     document.getElementById('country').innerHTML = place.address_components[i].long_name;
        }
      }
     document.getElementById('location').innerHTML = results[0].formatted_address;
     document.getElementById('lat').innerHTML = results[0].geometry.location.lat();
     document.getElementById('lon').innerHTML = results[0].geometry.location.lng();
        }
       }
     });
     });
     /***** กำหนดตำแหน่งที่ตั้งของ control ที่จะวางในแผนที่*****/
     var input = document.getElementById('searchInput');
     map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
    
     /***** เพิ่ม Feature ให้กับ textbox ให้สามารถพิมพ์ค้นหาสถานที่ได้*****/
     var autocomplete = new google.maps.places.Autocomplete(input);
     autocomplete.bindTo('bounds', map);
    
     var infowindow = new google.maps.InfoWindow();
     
     /***** กำหนดคุณสมบัติให้กับตัวพิกัดจุดหรือ marker *****/
     var marker = new google.maps.Marker({
     map: map,
     anchorPoint: new google.maps.Point(0, -29)
     });
    markers.push(marker); //เก็บค่าการกำหนดจุดพิกัดไว้ในตัวแปร markers เพื่อใช้ล้างข้อมูลการกำหนดจุดได้
    
     /***** ทำงานกับ event place_changed หรือเมื่อมีการเปลี่ยนแปลงค่าสถานที่ที่ค้นหา*****/
     autocomplete.addListener('place_changed', function() {
     infowindow.close();
     marker.setVisible(false);
     var place = autocomplete.getPlace();
     if (!place.geometry) {
     window.alert("ไม่ค้นพบพิกัดจากสถานที่ดังกล่าว");
     return;
     }
    
     /***** แสดงผลบนแผนที่เมื่อพบข้อมูลที่ต้องการค้นหา *****/
     if (place.geometry.viewport) {
     map.fitBounds(place.geometry.viewport);
     } else {
     map.setCenter(place.geometry.location);
     sv.getPanorama({ location: place.geometry.location, radius: 50 }, processSVData);
     map.setZoom(17);
     }
     marker.setIcon(({
     url: place.icon,
     size: new google.maps.Size(71, 71),
     origin: new google.maps.Point(0, 0),
     anchor: new google.maps.Point(17, 34),
     scaledSize: new google.maps.Size(35, 35)
     }));
     marker.setPosition(place.geometry.location);
     marker.setVisible(true);
     
     /***** แสดงรายละเอียดผลลัพธ์การค้นหา *****/
     var address = '';
     if (place.address_components) {
     address = [
     (place.address_components[0] && place.address_components[0].short_name || ''),
     (place.address_components[1] && place.address_components[1].short_name || ''),
     (place.address_components[2] && place.address_components[2].short_name || '')
     ].join(' ');
     }
     /***** แสดงรายละเอียดผลลัพธ์การค้นหาเป็น popup โดยมีชื่อและสถานที่ดังกล่าว *****/
     infowindow.setContent('<div><strong>' + place.name + '</strong><br>' + address);
     infowindow.open(map, marker);
    
     /***** แสดงรายละเอียดผลลัพธ์การค้นหา ซึ่งประกอบด้วย ที่อยู่ รหัสไปรษณีย์ ประเทศ ละติจูดและลองจิจูด *****/
     for (var i = 0; i < place.address_components.length; i++) {
     if(place.address_components[i].types[0] == 'postal_code'){
     document.getElementById('postal_code').innerHTML = place.address_components[i].long_name;
     }
     if(place.address_components[i].types[0] == 'country'){
     document.getElementById('country').innerHTML = place.address_components[i].long_name;
     }
     }
     document.getElementById('location').innerHTML = place.formatted_address;
     document.getElementById('lat').innerHTML = place.geometry.location.lat();
     document.getElementById('lon').innerHTML = place.geometry.location.lng();
     });
    }
    </script>
    
    • ฟังก์ชั่น processSVData() เป็นฟังก์ชั่นที่ใช้ในการนำค่าของ Street view มาแสดงผล
    <script>
    function processSVData(data, status) {
     if (status === 'OK') {
     
      marker = new google.maps.Marker({
     position: data.location.latLng,
     map: map,
     title: data.location.description
     });
     markers.push(marker);
     panorama.setPano(data.location.pano);
     panorama.setPov({
     heading: 270,
     pitch: 0
     });
     panorama.setVisible(true);
    
     marker.addListener('click', function() {
     
     var markerPanoID = data.location.pano;
     // Set the Pano to use the passed panoID.
     panorama.setPano(markerPanoID);
     panorama.setPov({
     heading: 270,
     pitch: 0
     });
     panorama.setVisible(true);
     });
     } else {
     console.error('ไม่พบข้อมูล Street view ตามสถานที่ดังกล่าว');
     }
     }
    </script>
    
    • ส่วนของการแสดงผล (ใน tag body)
    <body>
    
    <!--ส่วนของการแสดงรายละเอียดผลลัพธ์ที่ได้->
     <table style="width: 100%">
     <tr>
     <td>
    <!--ส่วนของ Element ที่ใช้ในการแสดงผล->
     <input id="searchInput" class="controls" type="text" placeholder="Enter a location">
    <div id="map" style="width: 60%;height:360px;float:left"></div>
    <div id="pano" style="width: 40%;height:360px; float:left"> </div><br />
     </td>
     
     </tr>
     <tr>
     <td>
     <div id="Div1" style="width: 100%;" >
     <ul id="geoData">
     <li>ที่อยู่: <span id="location"></span></li>
     <li>รหัสไปรษณีย์ : <span id="postal_code"></span></li>
     <li>ประเทศ: <span id="country"></span></li>
     <li>ละติจูด: <span id="lat"></span></li>
     <li>ลองจิจูด: <span id="lon"></span></li>
    </ul>
    </div>
    
     </td>
     </tr>
     
     </table>
     <!--ส่วนของการประกาศค่าเริ่มต้นและตัวแปร รวมถึงการเรียกใช้งานฟังก์ชั่นเพื่อใช้ในการแสดงผลที่กล่าวไว้ก่อนหน้านี้-> <script> /***** function ในการประกาศค่าเริ่มต้นให้กับแผนที่ และอื่นๆตามที่กล่าวไว้แล้วข้างต้น*****/ </script> <!--สิ้นสุดส่วนของการประกาศค่าเริ่มต้นและตัวแปร รวมถึงการเรียกใช้งานฟังก์ชั่นเพื่อใช้ในการแสดงผล-> </body>

    ผลลัพธ์ที่ได้

    1. เมื่อเปิดหน้าจอขึ้นมา จะแสดงพิกัดที่จังหวัดกรุงเทพมหานครเป็นค่าตั้งต้น และฝั่งขวาเป็นภาพที่ดึงข้อมูลมาได้จากพิกัดดังกล่าวจากข้อมูล Street Views

    2. พิมพ์ค้นหาชื่อสถานที่ และเลือกสถานที่ที่ต้องการ

    3. เมื่อเลือกสถานที่เรียบร้อย จะมีการกำหนดพิกัดจุดตามชื่อสถานที่ที่เลือกไว้ และแสดงผลภาพจาก Street View รวมทั้งแสดงรายละเอียดในส่วนล่างของหน้าจอ ดังภาพ

           นอกจากการค้นหาพิกัดและข้อมูลภาพจาก Street View โดยใช้วิธีการพิมพ์ค้นหาแล้วนั้น ผู้ใช้ยังสามารถค้นหาพิกัดใหม่ได้จากการคลิกบนแผนที่ได้อีกด้วย ซึ่งจะแสดงผลลัพธ์ได้เช่นกัน ดังภาพ

           ผู้เขียนหวังเป็นอย่างยิ่งว่า บทความนี้จะช่วยเพิ่มประสิทธิภาพและเป็นอีกหนึ่งทางเลือกให้กับผู้พัฒนาได้หยิบยกวิธีการดึงค่าละติจูด-ลองจิจูดและการแสดงผลข้อมูลไปประยุกต์ใช้กับงานของแต่ละท่าน และอาจถือเป็นการเพิ่มลูกเล่นให้กับเว็บไซต์ของท่านให้มีความสามารถที่หลากหลายมากขึ้นเกี่ยวกับการใช้งานร่วมกับแผนที่ Google Maps หากผู้อ่านท่านใดมีข้อเสนอแนะหรือแนะนำวิธีเพิ่มเติมเกี่ยวกับเรื่องดังกล่าว ผู้เขียนยินดีเป็นอย่างยิ่งที่จะรับฟังและร่วมแบ่งปันความรู้ร่วมกันค่ะ หากบทความนี้มีส่วนผิดพลาดประการใด ผู้เขียนขออภัยไว้ ณ ที่นี้ด้วยค่ะ ^^

    แหล่งข้อมูลอ้างอิง :  

    https://www.tutorialspoint.com/google_maps/google_maps_symbols.htm

    http://www.codexworld.com/autocomplete-places-search-box-google-maps-javascript-api/

          https://developers.google.com/maps/documentation/javascript/examples/streetview-service

  • การดึงค่าละติจูดและลองจิจูดของสถานที่ด้วย Places search box บน Google Maps

           ก่อนจะพูดถึงเนื้อหาของบทความนี้ ผู้เขียนขอท้าวความไปถึงบทความก่อนหน้าที่เป็นเนื้อหาที่เกี่ยวข้องกับการดึงค่าละติจูด-ลองจิจูดของสถานที่ เพื่อมากำหนดจุดพิกัดบนแผนที่ หรือที่เรารู้จักกันดีในนามของ Google maps (ซึ่งสามารถหาอ่านได้จากลิงค์ ทำอย่างไรให้สามารถกำหนดจุดพิกัดบนแผนที่ Google map แบบจุดเดียวและหลายจุดจากฐานข้อมูลได้ด้วย ASP.NET C# (ภาคต่อ) และหากท่านต้องการศึกษาเกี่ยวกับวิธีการกำหนดพิกัดบนแผนที่เพิ่มเติมสามารถหาอ่านได้จากลิงค์ ทำอย่างไรให้สามารถกำหนดจุดพิกัดบนแผนที่ Google map แบบจุดเดียวและหลายจุดจากฐานข้อมูลได้ด้วย ASP.NET C# เช่นกัน) แต่หลังจากที่ผู้เขียนได้นำไปทดลองใช้งานการดึงค่าพิกัดที่ค้นหา พบว่าเกิดปัญหาในการค้นหาพิกัดของสถานที่ในบางกรณี คือ ไม่สามารถค้นหาพิกัดของบางสถานที่ที่ต้องการได้ และในบางครั้งผู้ใช้เลือกสถานที่ที่จะดึงค่าพิกัดมาใช้งานผิด เนื่องจากชื่อสถานที่อาจคล้ายกัน แต่ตั้งอยู่กันคนละประเทศ หรือทวีป โดยผู้ใช้อาจไม่เห็นภาพว่าสถานที่ดังกล่าวอยู่ส่วนใดของแผนที่ จึงทำให้พิกัดที่ได้มีความผิดพลาดหรือคลาดเคลื่อนได้ ผู้เขียนจึงได้ลองศึกษาเพิ่มเติม และปรับเปลี่ยนวิธีการ เพื่อให้การดึงค่าพิกัดเป็นไปได้ง่าย และอำนวยความสะดวกต่อผู้ใช้งานมากขึ้น รวมทั้งเพิ่มช่องทางในการค้นหาข้อมูลพิกัดได้มากขึ้นและมีความถูกต้องแม่นยำขึ้น

    ตัวอย่างภาพการทำงานของการดึงค่าพิกัดที่ผู้เขียนเคยเขียนไว้ก่อนหน้านี้

    แบบที่ 1 การเรียกใช้เซอร์วิสของ Google Geocoding API โดยการส่งพารามิเตอร์เป็นที่อยู่ของสถานที่ดังกล่าว

       

    แบบที่ 2 แบบใช้ place Autocomplete ซึ่งเป็น feature ของ Google Places API ที่จะช่วยในการค้นหาที่อยู่จากชื่อสถานที่ได้และประยุกต์เพิ่มเติมเพื่อดึงค่ามาแสดงเมื่อมีการเลือกรายการสถานที่นั้นๆ

         

           จากปัญหาดังกล่าวข้างต้น ผู้เขียนได้ปรับเปลี่ยนวิธีการในการดึงค่าละติจูด-ลองจิจูดจากชื่อสถานที่ที่ผู้ใช้พิมพ์ค้นหาไว้ โดยมีการนำ “Places search box” มาใส่ไว้ในแผนที่ที่เราต้องการแทน เพื่อให้ผู้ใช้สามารถมองเห็นสถานที่จริงที่เลือกได้จากแผนที่ ซึ่งสามารถตรวจสอบได้ว่าสถานที่ดังกล่าวเป็นสถานที่ที่ต้องการจะดึงค่าละติจูด-ลองจิจูดจริงหรือไม่อีกทางหนึ่งนั่นเอง โดยมีวิธีการดังนี้

    • ส่วนของสไตล์ชีทในการแสดงผล ขึ้นกับการตกแต่งของผู้พัฒนาแต่ละท่าน
    <!—ส่วนของ Style Sheets-->
    <style>
    html, body {
     height: 100%;
     margin: 0;
     padding: 0;
    }
    #map {
     width: 100%;
     height: 400px;
    }
    .controls {
     margin-top: 10px;
     border: 1px solid transparent;
     border-radius: 2px 0 0 2px;
     box-sizing: border-box;
     -moz-box-sizing: border-box;
     height: 32px;
     outline: none;
     box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    }
    #searchInput {
     background-color: #fff;
     font-family: Roboto;
     font-size: 15px;
     font-weight: 300;
     margin-left: 12px;
     padding: 0 11px 0 13px;
     text-overflow: ellipsis;
     width: 50%;
    }
    #searchInput:focus {
     border-color: #4d90fe;
    }
    
    </style>
    
    • ส่วนของการอ้างอิง libraries เพื่อใช้งาน Google API
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCRbMoDPc_mTv3D3QPqe0Ar84nSvRhA8nk&libraries=places&callback=initMap" async defer></script>
    
    • ส่วนของการประกาศค่าเริ่มต้นและตัวแปร รวมถึงการเรียกใช้งานฟังก์ชั่นเพื่อใช้ในการแสดงผล
    <script>
    /***** function ในการประกาศค่าเริ่มต้นให้กับแผนที่*****/
     function initMap() {
     
     /***** กำหนดรายละเอียดคุณสมบัติของแผนที่*****/
     var map = new google.maps.Map(document.getElementById('map'), {
     center: {lat: -33.8688, lng: 151.2195},
     zoom: 13
     });
    
     /***** กำหนดตำแหน่งที่ตั้งของ control ที่จะวางในแผนที่*****/
     var input = document.getElementById('searchInput');
     map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
    
     /***** เพิ่ม Feature ให้กับ textbox ให้สามารถพิมพ์ค้นหาสถานที่ได้*****/
     var autocomplete = new google.maps.places.Autocomplete(input);
     autocomplete.bindTo('bounds', map);
    
     var infowindow = new google.maps.InfoWindow();
     
     /***** กำหนดคุณสมบัติให้กับตัวพิกัดจุดหรือ marker *****/
     var marker = new google.maps.Marker({
     map: map,
     anchorPoint: new google.maps.Point(0, -29)
     });
    
     /***** ทำงานกับ event place_changed หรือเมื่อมีการเปลี่ยนแปลงค่าสถานที่ที่ค้นหา*****/
     autocomplete.addListener('place_changed', function() {
     infowindow.close();
     marker.setVisible(false);
     var place = autocomplete.getPlace();
     if (!place.geometry) {
     window.alert("ไม่ค้นพบพิกัดจากสถานที่ดังกล่าว");
     return;
     }
    
     /***** แสดงผลบนแผนที่เมื่อพบข้อมูลที่ต้องการค้นหา *****/
     if (place.geometry.viewport) {
     map.fitBounds(place.geometry.viewport);
     } else {
     map.setCenter(place.geometry.location);
     map.setZoom(17);
     }
     marker.setIcon(({
     url: place.icon,
     size: new google.maps.Size(71, 71),
     origin: new google.maps.Point(0, 0),
     anchor: new google.maps.Point(17, 34),
     scaledSize: new google.maps.Size(35, 35)
     }));
     marker.setPosition(place.geometry.location);
     marker.setVisible(true);
     
     /***** แสดงรายละเอียดผลลัพธ์การค้นหา *****/
     var address = '';
     if (place.address_components) {
     address = [
     (place.address_components[0] && place.address_components[0].short_name || ''),
     (place.address_components[1] && place.address_components[1].short_name || ''),
     (place.address_components[2] && place.address_components[2].short_name || '')
     ].join(' ');
     }
     /***** แสดงรายละเอียดผลลัพธ์การค้นหาเป็น popup โดยมีชื่อและสถานที่ดังกล่าว *****/
     infowindow.setContent('<div><strong>' + place.name + '</strong><br>' + address);
     infowindow.open(map, marker);
    
     /***** แสดงรายละเอียดผลลัพธ์การค้นหา ซึ่งประกอบด้วย ที่อยู่ รหัสไปรษณีย์ ประเทศ ละติจูดและลองจิจูด *****/
     for (var i = 0; i < place.address_components.length; i++) {
     if(place.address_components[i].types[0] == 'postal_code'){
     document.getElementById('postal_code').innerHTML = place.address_components[i].long_name;
     }
     if(place.address_components[i].types[0] == 'country'){
     document.getElementById('country').innerHTML = place.address_components[i].long_name;
     }
     }
     document.getElementById('location').innerHTML = place.formatted_address;
     document.getElementById('lat').innerHTML = place.geometry.location.lat();
     document.getElementById('lon').innerHTML = place.geometry.location.lng();
     });
    }
    </script>
    • ส่วนของการแสดงผล (ใน tag body)
    <body>
    <!--ส่วนของ Element ที่ใช้ในการแสดงผล-->
    <input id="searchInput" class="controls" type="text" placeholder="Enter a location">
    <div id="map"></div>
    <!--ส่วนของการแสดงรายละเอียดผลลัพธ์ที่ได้-->
    <ul id="geoData">
     <li>ที่อยู่: <span id="location"></span></li>
     <li>รหัสไปรษณีย์: <span id="postal_code"></span></li>
     <li>ประเทศ: <span id="country"></span></li>
     <li>ละติจูด: <span id="lat"></span></li>
     <li>ลองจิจูด: <span id="lon"></span></li>
    </ul>
    
    <!--ส่วนของการประกาศค่าเริ่มต้นและตัวแปร รวมถึงการเรียกใช้งานฟังก์ชั่นเพื่อใช้ในการแสดงผลที่กล่าวไว้ก่อนหน้านี้-->
                                                                
    <script>
    /***** function ในการประกาศค่าเริ่มต้นให้กับแผนที่ และอื่นๆตามที่กล่าวไว้แล้วข้างต้น*****/
    </script>
    <!--สิ้นสุดส่วนของการประกาศค่าเริ่มต้นและตัวแปร รวมถึงการเรียกใช้งานฟังก์ชั่นเพื่อใช้ในการแสดงผล->
     </body>

    ผลลัพธ์ที่ได้

    1. เมื่อพิมพ์ชื่อสถานที่ เช่น มหาวิทยาลัยสงขลานครินทร์ จะมีรายการชื่อสถานที่ให้ผู้ใช้เลือก

    2. เมื่อเลือกชื่อสถานที่ที่ต้องการ เช่น มหาวิทยาลัยสงขลานครินทร์ จะมีการแสดงรายละเอียดของสถานที่ดังกล่าวดังภาพตามหมายเลข 1,2 และ 3 ตามลำดับ

           ผู้เขียนหวังเป็นอย่างยิ่งว่า บทความนี้จะช่วยแก้ปัญหาให้กับผู้ที่อาจจะกำลังเจอปัญหาในแบบเดียวกันกับผู้เขียนในการดึงค่าละติจูด-ลองจิจูดเพื่อนำไปกำหนดจุดพิกัดบนแผนที่อยู่ไม่มากก็น้อย หากผู้อ่านท่านใดมีข้อเสนอแนะหรือแนะนำวิธีเพิ่มเติมเกี่ยวกับเรื่องดังกล่าว ผู้เขียนยินดีเป็นอย่างยิ่งที่จะรับฟังและร่วมแบ่งปันความรู้ร่วมกันค่ะ หากบทความนี้มีส่วนผิดพลาดประการใด ผู้เขียนขออภัยไว้ ณ ที่นี้ด้วยค่ะ ^^

    แหล่งข้อมูลอ้างอิง :

    https://www.tutorialspoint.com/google_maps/google_maps_symbols.htm

    http://www.codexworld.com/autocomplete-places-search-box-google-maps-javascript-api/

  • วิธีเขียน web service ตรวจสอบไฟล์ใน url ที่ส่งมาว่ามีไฟล์หรือไม่

    เนื่องจากผู้เขียนได้มีการทำงานที่ต้องตรวจสอบไฟล์ จึงอยากจะแชร์ประสบการณ์การเขียน web service โดยยกตัวอย่างการเขียนดังนี้

    โดยจากตัวอย่างผู้เขียนได้ใช้ฟังก์ชัน client.DownloadData(url) โดยผลลัพธ์ที่ได้ มีดังนี้

    • ถ้าไม่มีไฟล์อยู่ก็จะตอบกลับมาเป็น “File not found.”
    • ถ้ามีไฟล์ระบบจะตอบกลับมาว่ามีจริง

    ซึ่งหวังว่าจะมีประโยชน์ไม่มากก็น้อยค่ะ

     

  • วิธีการ set property ของ radio button ใน Dojo

    เนื่องจากช่วงนี้ ผู้เขียนมีโอกาสได้เข้ามาอยู่ในแวดวงของ Dojo และได้ประสบกับปัญหาในการที่จะ set property ของ Dojo ซึ่งในที่นี้คือ Radio Button หลังจากที่ได้ลองผิด ลองถูก Error กันหัวหมุน  จนสุดท้ายได้เจอทางออก  เลยอยากจะบันทึกไว้สำหรับตัวเองมาดูในอนาคต และเผื่อท่านอื่นที่ประสบปัญหาเดียวกัน มาเจอจะได้ลองนำไปใช้งานกันดูค่ะ Let’s GO!!!

     

    เนื่องจาก Radio Button เป็น Control ภายใต้ dijit/form/RadioButton ดังนั้น การเขียนคำสั่งเพื่อ set property จึงได้เป็นดังนี้

    dijit.byId(‘control_id‘).set(‘control_prop‘, value);

    control_id : id ของ control นั้น ๆ

    control_prop : property ของ control ที่ต้องการกำหนดค่า

    value : ค่าที่ต้องการกำหนด

     

    ตัวอย่างเช่น ต้องการกำหนดให้ radio button ที่มี id=”rdBtn1″ ไม่สามารถใช้งานแต่ยังแสดง(disable) และ

    id=”rdBtn2″ มีค่าโดยปริยายเป็นเลือกไว้ จะเขียน Code ได้ดังนี้

    dijit.byId(‘rdBtn1’).set(‘disabled’, true); 

    dijit.byId(‘rdBtn2’).set(‘checked’, true); 

     

    ซึ่ง properties ของ control ต่าง ๆ สามารถดูเพิ่มเติมได้จากเว็ปเพจของ Dojo ตามลิงค์นี้ค่ะ Dojo Documentation

    หวังว่าบทความนี้จะเป็นประโยชน์แก่ท่านผู้อ่านไม่มาก็น้อยนะคะ แล้วพบกันใหม่ตอนหน้าค่ะ 

  • Remote Debugging ASP.NET application

    ในการพัฒนาเว็บแอพพลิเคชัน การที่จะ publish เว็บขึ้น server ผู้พัฒนาย่อมมีการทดสอบการทำงานของแต่ละฟังก์ชันแต่ละ process ผ่าน localhost ก่อนอยู่แล้ว ว่าสามารถทำงานได้ถูกต้อง ไม่พบ error หรือปัญหาใดๆ แต่ในบางครั้งพบว่า เมื่อ publish เว็บไปแล้ว กลับพบ error ในบางฟังก์ชัน ทั้งที่ฟังก์ชันนั้นผ่านการทดสอบบน localhost ว่าทำงานถูกต้องแล้ว ซึ่งอาจเกิดจาก Environment ในตอนที่เรา run ที่ localhost กับบน server ไม่เหมือนกัน หรือฐานข้อมูลที่ทดสอบกับฐานข้อมูลที่ใช้งานจริงมีข้อมูลที่ conflict กันอยู่ เป็นต้น ซึ่งบทความนี้ผู้เขียนจะมาแนะนำ Remote Debugging Tool สำหรับผู้พัฒนาเว็บด้วย ASP.NET

    Remote Debugging Tool

    คือ เครื่องมือที่ใช้ในการ remote debug สำหรับ ASP.NET แอพพลิเคชัน ซึ่งเป็นเครื่องมือขนาดเล็กที่มีชื่อว่า “Msvsmon.exe” ที่ให้เราสามารถ debug  code เพื่อหา error โดยการ remote จาก Visual Studio ไปยัง IIS server

     

    ติดตั้ง Remote Debugging Tool บน Windows Server

    download ตัวติดตั้ง Remote tools ตาม version ของ Visual Studio ที่เราใช้งาน เมื่อ download มาเรียบร้อยแล้วให้ทำการติดตั้ง โดยคลิกขวาที่ไฟล์ติดตั้ง เลือก Run as administrator จะปรากฎหน้าต่างดังรูป

     

    ให้เลือก Configure remote debugging จะเสร็จสิ้นขั้นตอนการติดตั้งและจะปรากฏหน้าต่าง Remote Debugger

    ซึ่งตอนนี้ Remote debugger ทำงานแล้ว โดยรอการเชื่อมต่อจากฝั่ง Visual Studio (ภายหลัง สามารถเรียกใช้งาน Remote Debugger ได้จาก Start menu)

    Attach Process จาก Visual Studio เครื่องพัฒนา

    1. เปิด Visual Studio ขึ้นมา และเลือก project ที่จะใช้งาน
    2. ที่แถบเมนูด้านบน เลือก Debug >> Attach to Process
    3. ปรากฎหน้าต่าง Attach to Process ดังรูป ในส่วนของ Qualifier ให้ระบุชื่อหรือ IP ของเครื่อง server ที่ web เราวางอยู่ และกดปุ่ม Refresh ด้านล่างเพื่อ connect ไปยังเครื่อง server ดังรูป

    4. เลือก process ที่ชื่อ w3wp.exe โดยสังเกตที่คอลัมน์ User Name เป็น path ของ site ที่เราต้องการทดสอบ หลังจากนั้นกดปุ่ม Attach ดังรูป

    5. เปิด browser และพิมพ์ url ไซต์ของเรา http://<remote computer name>

    6. เลือกมาร์กจุด breakpoint ที่จะ debug code ตามต้องการ เราก็จะสามารถ debug code โดยการ remote ไปยังเครื่อง server ที่เราได้ deploy เว็บของเราไปแล้วได้เหมือนการ debug บนเครื่อง localhost ที่เราพัฒนาค่ะ

     

    แหล่งข้อมูลอ้างอิงhttps://msdn.microsoft.com/en-us/library/mt621540.aspx