• We just launched and are currently in beta. Join us as we build and grow the community.

Advertise Here

Advertise Here

Advertise Here

Dynamically Map an Area of an Image using JavaScript/jQuery Tutorial

hexag_on

Side Gig Pro
H Rep
0
0
0
Rep
0
H Vouches
0
0
0
Vouches
0
Posts
41
Likes
145
Bits
2 MONTHS
2 2 MONTHS OF SERVICE
LEVEL 1 100 XP
In this tutorial, you will learn how to Dynamically Map an Area of an Image using JavaScript/jQuery. This will help you to understand also on how to put a detection link on a specific part or area of the image. With the use of HTML Canvas, we can dynamically locate the specific position and size of the area we want to detect on the image.

Below, I have provided a simple source code of a simple web application. The application displays an image and allows users to add details on a specific area of an image. The user can simply click the "Map Area" button to start to draw in the image that will identify the area on the image, Next, the user will click the "Save Mapped Area" button to open a form modal where he/she will put the area details. Then, after saving the details the page will be reloaded and the mapped area will become a clickable area. When the area has been clicked, a modal will show on the window that displays the area details. Users can also update the area details and delete the mapped area.

Getting Started

The source code I created below, I used Bootstrap version 5 as the CSS Framework and jQuery Library. Please download the said framework and library in or display and run the application properly. The following are the links of the framework and library website to download.


After downloading the framework and library, compile them inside a single directory that will serve as your source code folder. Also, add an image file in the directory because the application does not have an upload feature.

Creating the Interface

The below code is a HTML Script that contains the user interfaces codes of the application. This holds the image, canvas, map, area, and modal HTML tag. Open a text editor and copy the script below and paste in into a new html file. Next, change the image source according to the image file location you desired to use. Save the file as index.html.

  1. <!DOCTYPE html>
  2. <html

    lang

    =

    "en"

    >

  3. <head

    >
  4. <meta

    charset

    =

    "UTF-8"

    >
  5. <meta

    http-equiv

    =

    "X-UA-Compatible"

    content

    =

    "IE=edge"

    >
  6. <meta

    name

    =

    "viewport"

    content

    =

    "width=device-width, initial-scale=1.0"

    >
  7. <title

    >

    Mapping</

    title

    >
  8. <link

    rel

    =

    "stylesheet"

    href

    =

    "./css/bootstrap.min.css"

    >
  9. <script

    src

    =

    "./js/jquery-3.6.0.min.js"

    ></

    script

    >
  10. <script

    src

    =

    "./js/bootstrap.min.js"

    ></

    script

    >
  11. <script

    src

    =

    "./js/script.js"

    ></

    script

    >
  12. <!-- Custom CSS -->
  13. <style

    >
  14. :root {
  15. --bs-success-rgb: 71, 222, 152 !important;
  16. }

  17. html,
  18. body {
  19. height: 100%;
  20. width: 100%;
  21. font-family: Apple Chancery, cursive;
  22. }

  23. #fp-canvas-container {
  24. height: 65vh;
  25. width: calc(100%);
  26. position: relative;
  27. }

  28. .fp-img,
  29. .fp-canvas,
  30. .fp-canvas-2 {
  31. position: absolute;
  32. width: calc(100%);
  33. height: calc(100%);
  34. top: 0;
  35. left: 0;
  36. z-index: 1;
  37. }

  38. #fp-map {
  39. position: absolute;
  40. width: calc(100%);
  41. height: calc(100%);
  42. top: 0;
  43. left: 0;
  44. z-index: 1;
  45. }

  46. .fp-canvas {
  47. z-index: 2;
  48. background: #0000000d;
  49. cursor: crosshair;
  50. }

  51. #fp-map {
  52. z-index: 2;
  53. }

  54. area {
  55. position: absolute;
  56. }

  57. area:hover {
  58. background: #cbcbcb0f;
  59. }

  60. #save,
  61. #cancel {
  62. display: none;
  63. }
  64. </

    style

    >
  65. <!-- End of Custom Css -->
  66. </

    head

    >

  67. <body

    class

    =

    "bg-light"

    >
  68. <nav class

    =

    "navbar navbar-expand-lg navbar-dark bg-primary bg-gradient"

    id

    =

    "topNavBar"

    >
  69. <div

    class

    =

    "container"

    >
  70. <a

    class

    =

    "navbar-brand"

    href

    =

    "https://sourcecodester.com"

    >
  71. Sourcecodester
  72. </

    a

    >
  73. </

    div

    >
  74. </

    nav>
  75. <div

    class

    =

    "container py-3"

    id

    =

    "page-container"

    >
  76. <h3

    >

    Dynamically Map Area on an Image</

    h3

    >
  77. <hr

    >
  78. <div

    class

    =

    "content"

    >
  79. <div

    class

    =

    "row my-2"

    >
  80. <!-- Action Buttons -->
  81. <div

    class

    =

    "col-md-12"

    >
  82. <button

    class

    =

    "btn btn-primary rounded-0"

    type

    =

    "button"

    id

    =

    "map_area"

    >

    Map Area</

    button

    >
  83. <button

    class

    =

    "btn btn-primary rounded-0"

    type

    =

    "button"

    id

    =

    "save"

    >

    Save Mapped Area</

    button

    >
  84. <button

    class

    =

    "btn btn-secondary rounded-0"

    type

    =

    "button"

    id

    =

    "cancel"

    >

    Cancel</

    button

    >
  85. </

    div

    >
  86. <!-- End ofAction Buttons -->
  87. </

    div

    >
  88. <!-- Image/Canvas/Map Container -->
  89. <div

    id

    =

    "fp-canvas-container"

    >
  90. <map

    name

    =

    "fp-map"

    id

    =

    "fp-map"

    >
  91. </

    map

    >
  92. <img

    src

    =

    "./devices.jpg"

    alt

    =

    "Floor Plan"

    class

    =

    'fp-img'

    id

    =

    "fp-img"

    usemap

    =

    "#fp-map"

    >
  93. <canvas class

    =

    "fp-canvas d-none"

    id

    =

    "fp-canvas"

    ></

    canvas>
  94. </

    div

    >
  95. </

    div

    >
  96. <!-- End of Image/Canvas/Map Container -->
  97. </

    div

    >
  98. </

    div

    >
  99. <!-- Mapped Area Add/Edit Details Form Modal -->
  100. <div

    class

    =

    "modal fade"

    id

    =

    "form_modal"

    role=

    'dialog'

    data-bs-backdrop=

    "static"

    data-bs-keyboard=

    "true"

    >
  101. <div

    class

    =

    "modal-dialog modal-md modal-dialog-centered"

    role=

    "document"

    >
  102. <div

    class

    =

    "modal-content"

    >
  103. <div

    class

    =

    "modal-header"

    >
  104. <h5

    class

    =

    "modal-title"

    >

    Mapped Area Details</

    h5

    >
  105. </

    div

    >
  106. <div

    class

    =

    "modal-body"

    >
  107. <form

    action

    =

    ""

    id

    =

    "mapped-form"

    >
  108. <input

    type

    =

    "hidden"

    name

    =

    "id"

    value

    =

    ""

    >
  109. <input

    type

    =

    "hidden"

    name

    =

    "coord_perc"

    value

    =

    ""

    >
  110. <div

    class

    =

    "form-group"

    >
  111. <label

    for

    =

    "description"

    class

    =

    "control-label text-primary"

    >

    Description</

    label

    >
  112. <textarea

    name

    =

    "description"

    id

    =

    "description"

    cols

    =

    "30"

    rows

    =

    "4"

    class

    =

    "form-control rounded-0"

    ></

    textarea

    >
  113. </

    div

    >
  114. </

    form

    >
  115. </

    div

    >
  116. <div

    class

    =

    "modal-footer py-1"

    >
  117. <button

    type

    =

    "submit"

    class

    =

    "btn btn-sm rounded-0 btn-primary"

    form=

    "mapped-form"

    >

    Save</

    button

    >
  118. <button

    type

    =

    "button"

    class

    =

    "btn btn-sm rounded-0 btn-secondary"

    data-bs-dismiss=

    "modal"

    >

    Close</

    button

    >
  119. </

    div

    >
  120. </

    div

    >
  121. </

    div

    >
  122. </

    div

    >
  123. <!--End of Mapped Area Add/Edit Details Form Modal -->

  124. <!--Mapped Area View Details Modal -->
  125. <div

    class

    =

    "modal fade"

    id

    =

    "view_modal"

    role=

    'dialog'

    data-bs-backdrop=

    "static"

    data-bs-keyboard=

    "true"

    >
  126. <div

    class

    =

    "modal-dialog modal-md modal-dialog-centered"

    role=

    "document"

    >
  127. <div

    class

    =

    "modal-content"

    >
  128. <div

    class

    =

    "modal-header"

    >
  129. <h5

    class

    =

    "modal-title"

    >

    Area Details</

    h5

    >
  130. </

    div

    >
  131. <div

    class

    =

    "modal-body"

    >

  132. </

    div

    >
  133. <div

    class

    =

    "modal-footer py-1"

    >
  134. <button

    type

    =

    "button"

    class

    =

    "btn btn-sm rounded-0 btn-primary"

    data-id

    =

    ''

    id

    =

    "edit-area"

    >

    Edit</

    button

    >
  135. <button

    type

    =

    "button"

    class

    =

    "btn btn-sm rounded-0 btn-danger"

    data-id

    =

    ''

    id

    =

    "delete-area"

    >

    Delete</

    button

    >
  136. <button

    type

    =

    "button"

    class

    =

    "btn btn-sm rounded-0 btn-secondary"

    data-bs-dismiss=

    "modal"

    >

    Close</

    button

    >
  137. </

    div

    >
  138. </

    div

    >
  139. </

    div

    >
  140. </

    div

    >
  141. <!--End of Mapped Area View Details Modal -->
  142. </

    body

    >

  143. </

    html

    >

Creating the Main Script

The below script is a JavaScript codes that contains the drawing, map area creation, buttons actions, and modal triggers codes. Save the following file as script.js.

  1. // Canvas Position Variables
  2. var

    cposX =

    0

    ,
  3. cposY =

    0

    ;
  4. // Mouse Down Position Variables
  5. var

    posX =

    0

    ,
  6. posY =

    0

    ;
  7. // Mouse Moving Position Variables
  8. var

    nposX =

    0

    ,
  9. nposY =

    0

    ;
  10. // Coordinate Position in Percentage Variables
  11. var

    px1_perc =

    0

    ,
  12. py1_perc =

    0

    ,
  13. px2_perc =

    0

    ,
  14. py2_perc =

    0

    ;
  15. // Canvas Variable
  16. var

    ctx;
  17. // Variable for checking if the mouse has started to draw or not
  18. var

    isDraw =

    false

    ;
  19. // Auto Increment sequence for the Store Data Identification [id]
  20. var

    AI_seq =

    $.parseJSON

    (

    localStorage.getItem

    (

    'seq'

    )

    )

    ||

    0

    ;
  21. // Stored Data [Mapped Area Details]
  22. var

    stored =

    $.parseJSON

    (

    localStorage.getItem

    (

    'mapped'

    )

    )

    ||

    {

    }

    ;


  23. // Function that creates the Area tag and appends to the Map Tag
  24. function

    mapped_area(

    )

    {
  25. if

    (

    Object

    .keys

    (

    stored)

    .length

    >

    0

    )

    {
  26. // Empty Map Tag First
  27. $(

    '#fp-map'

    )

    .html

    (

    ''

    )

  28. // Looping Data
  29. Object

    .keys

    (

    stored)

    .map

    (

    k =>

    {
  30. // Loop Current Data
  31. var

    data =

    stored[

    k]
  32. // Creating New Area Tag
  33. var

    area =

    $(

    "<area shape='rect'>"

    )
  34. area.attr

    (

    'href'

    ,

    "javascript:void(0)"

    )
  35. // Coordinate Percentage
  36. var

    perc =

    data.coord_perc
  37. perc =

    perc.replace

    (

    " "

    ,

    ''

    )
  38. perc =

    perc.split

    (

    ","

    )

  39. // Configuring Area Position, Height, and Width
  40. var

    x =

    $(

    '#fp-img'

    )

    .width

    (

    )

    *

    perc[

    0

    ]

    ;
  41. var

    y =

    $(

    '#fp-img'

    )

    .height

    (

    )

    *

    perc[

    1

    ]

    ;
  42. var

    width =

    Math

    .abs

    (

    (

    $(

    '#fp-img'

    )

    .width

    (

    )

    *

    Math

    .abs

    (

    perc[

    2

    ]

    )

    )

    -

    x)

    ;
  43. var

    height =

    Math

    .abs

    (

    (

    $(

    '#fp-img'

    )

    .height

    (

    )

    *

    Math

    .abs

    (

    perc[

    3

    ]

    )

    )

    -

    y)

    ;
  44. if

    (

    (

    $(

    '#fp-img'

    )

    .width

    (

    )

    *

    perc[

    2

    ]

    )

    -

    x <

    0

    )
  45. x =

    x -

    width
  46. if

    (

    (

    $(

    '#fp-img'

    )

    .height

    (

    )

    *

    perc[

    3

    ]

    )

    -

    y <

    0

    )
  47. y =

    y -

    height
  48. area.attr

    (

    'coords'

    ,

    x +

    ", "

    +

    y +

    ", "

    +

    width +

    ", "

    +

    height)
  49. area.addClass

    (

    'fw-bolder text-muted'

    )
  50. area.css

    (

    {
  51. 'height'

    :

    height +

    'px'

    ,
  52. 'width'

    :

    width +

    'px'

    ,
  53. 'top'

    :

    y +

    'px'

    ,
  54. 'left'

    :

    x +

    'px'

    ,
  55. }

    )

  56. $(

    '#fp-map'

    )

    .append

    (

    area)

  57. // Action to make if the Area Tag has been clicked
  58. area.click

    (

    function

    (

    )

    {
  59. $(

    '#view_modal'

    )

    .find

    (

    '#edit-area,#delete-area'

    )

    .attr

    (

    'data-id'

    ,

    data.id

    )
  60. data.description

    =

    data.description

    .replace

    (

    /\n/gi

    ,

    "<br>"

    )
  61. $(

    '#view_modal'

    )

    .find

    (

    '.modal-body'

    )

    .html

    (

    data.description

    )
  62. $(

    '#view_modal'

    )

    .modal

    (

    'show'

    )
  63. }

    )
  64. }

    )
  65. }
  66. }

  67. $(

    function

    (

    )

    {
  68. cposX =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .getBoundingClientRect

    (

    )

    .x
  69. cposY =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .getBoundingClientRect

    (

    )

    .y
  70. ctx =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .getContext

    (

    '2d'

    )

    ;

  71. // Creates the Map Area on the Image
  72. mapped_area(

    )

  73. // Re-initialize Map Area Creation when the window has been resized
  74. $(

    window)

    .on

    (

    'resize'

    ,

    function

    (

    )

    {
  75. mapped_area(

    )
  76. }

    )

  77. // Event Listener when the mouse is clicked on the canvas area
  78. $(

    '.fp-canvas'

    )

    .on

    (

    'mousedown'

    ,

    function

    (

    e)

    {
  79. px1_perc =

    (

    e.clientX

    -

    cposX)

    /

    $(

    '#fp-canvas'

    )

    .width

    (

    )
  80. py1_perc =

    (

    e.clientY

    -

    cposY)

    /

    $(

    '#fp-canvas'

    )

    .height

    (

    )
  81. posX =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .width

    *

    (

    (

    e.clientX

    -

    cposX)

    /

    $(

    '#fp-canvas'

    )

    .width

    (

    )

    )

    ;
  82. posY =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .height

    *

    (

    (

    e.clientY

    -

    cposY)

    /

    $(

    '#fp-canvas'

    )

    .height

    (

    )

    )

    ;
  83. isDraw =

    true
  84. }

    )

  85. // Event Listener when the mouse is moving on the canvas area. For drawing the rectangular Area
  86. $(

    '.fp-canvas'

    )

    .on

    (

    'mousemove'

    ,

    function

    (

    e)

    {
  87. if

    (

    isDraw ==

    false

    )
  88. return

    false

    ;
  89. nposX =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .width

    *

    (

    (

    e.clientX

    -

    cposX)

    /

    $(

    '#fp-canvas'

    )

    .width

    (

    )

    )

    ;
  90. nposY =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .height

    *

    (

    (

    e.clientY

    -

    cposY)

    /

    $(

    '#fp-canvas'

    )

    .height

    (

    )

    )

    ;
  91. var

    height =

    nposY -

    posY;
  92. var

    width =

    nposX -

    posX;
  93. ctx.clearRect

    (

    0

    ,

    0

    ,

    $(

    '.fp-canvas'

    )

    [

    0

    ]

    .width

    ,

    $(

    '.fp-canvas'

    )

    [

    0

    ]

    .height

    )

    ;
  94. ctx.beginPath

    (

    )

    ;
  95. ctx.lineWidth

    =

    ".3"

    ;
  96. ctx.strokeStyle

    =

    "pink"

    ;
  97. ctx.rect

    (

    posX,

    posY,

    width,

    height)

    ;
  98. ctx.stroke

    (

    )

    ;
  99. }

    )
  100. // Event Listener when the mouse is up on the canvas area. End of Drawing
  101. $(

    '.fp-canvas'

    )

    .on

    (

    'mouseup'

    ,

    function

    (

    e)

    {
  102. px2_perc =

    (

    e.clientX

    -

    cposX)

    /

    $(

    '#fp-canvas'

    )

    .width

    (

    )
  103. py2_perc =

    (

    e.clientY

    -

    cposY)

    /

    $(

    '#fp-canvas'

    )

    .height

    (

    )
  104. nposX =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .width

    *

    (

    (

    e.clientX

    -

    cposX)

    /

    $(

    '#fp-canvas'

    )

    .width

    (

    )

    )

    ;
  105. nposY =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .height

    *

    (

    (

    e.clientY

    -

    cposY)

    /

    $(

    '#fp-canvas'

    )

    .height

    (

    )

    )

    ;
  106. var

    height =

    nposY -

    posY;
  107. var

    width =

    nposX -

    posX;

  108. ctx.clearRect

    (

    0

    ,

    0

    ,

    $(

    '.fp-canvas'

    )

    [

    0

    ]

    .width

    ,

    $(

    '.fp-canvas'

    )

    [

    0

    ]

    .height

    )

    ;
  109. ctx.beginPath

    (

    )

    ;
  110. ctx.lineWidth

    =

    ".3"

    ;
  111. ctx.strokeStyle

    =

    "pink"

    ;
  112. ctx.rect

    (

    posX,

    posY,

    width,

    height)

    ;
  113. ctx.stroke

    (

    )

    ;
  114. isDraw =

    false
  115. }

    )


  116. // Action when Map Are button is clicked
  117. $(

    '#map_area'

    )

    .click

    (

    function

    (

    )

    {
  118. $(

    this

    )

    .hide

    (

    'slow'

    )
  119. $(

    '#save,#cancel'

    )

    .show

    (

    'slow'

    )
  120. $(

    '#fp-canvas'

    )

    .removeClass

    (

    'd-none'

    )
  121. cposX =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .getBoundingClientRect

    (

    )

    .x
  122. cposY =

    $(

    '#fp-canvas'

    )

    [

    0

    ]

    .getBoundingClientRect

    (

    )

    .y
  123. }

    )
  124. // Action when Map Are cancel is clicked
  125. $(

    '#cancel'

    )

    .click

    (

    function

    (

    )

    {
  126. $(

    '#save,#cancel'

    )

    .hide

    (

    'slow'

    )
  127. $(

    '#map_area'

    )

    .show

    (

    'slow'

    )
  128. $(

    '#fp-canvas'

    )

    .addClass

    (

    'd-none'

    )
  129. }

    )
  130. // Action when Map Are save is clicked
  131. $(

    '#save'

    )

    .click

    (

    function

    (

    )

    {
  132. var

    cP =

    px1_perc +

    ", "

    +

    py1_perc +

    ", "

    +

    px2_perc +

    ", "

    +

    py2_perc
  133. $(

    '#form_modal'

    )

    .find

    (

    'input[name="coord_perc"]'

    )

    .val

    (

    cP)
  134. $(

    '#form_modal'

    )

    .modal

    (

    'show'

    )
  135. }

    )

  136. // Saving the Mapped Area Details on local Storage
  137. $(

    '#mapped-form'

    )

    .submit

    (

    function

    (

    e)

    {
  138. e.preventDefault

    (

    )

    ;
  139. var

    data;
  140. var

    id =

    $(

    this

    )

    .find

    (

    '[name="id"]'

    )

    .val

    (

    )
  141. var

    coord_perc =

    $(

    this

    )

    .find

    (

    '[name="coord_perc"]'

    )

    .val

    (

    )
  142. var

    description =

    $(

    this

    )

    .find

    (

    '[name="description"]'

    )

    .val

    (

    )

  143. if

    (

    id ==

    ''

    )

    {
  144. id =

    AI_seq +

    1

    ;
  145. localStorage.setItem

    (

    'seq'

    ,

    id)
  146. }
  147. data =

    {

    id:

    id,

    description:

    description,

    coord_perc:

    coord_perc }
  148. stored[

    id]

    =

    data;
  149. localStorage.setItem

    (

    'mapped'

    ,

    JSON.stringify

    (

    stored)

    )
  150. alert(

    "Mapped Area Successfully saved."

    )
  151. location.reload

    (

    )
  152. }

    )
  153. // Edit Mapped Area Details
  154. $(

    '#edit-area'

    )

    .click

    (

    function

    (

    )

    {
  155. $(

    '.modal'

    )

    .modal

    (

    'hide'

    )
  156. id =

    $(

    this

    )

    .attr

    (

    'data-id'

    )
  157. data =

    stored[

    id]

    ||

    {

    }
  158. $(

    '#mapped-form'

    )

    .find

    (

    '[name="id"]'

    )

    .val

    (

    data.id

    )
  159. $(

    '#mapped-form'

    )

    .find

    (

    '[name="coord_perc"]'

    )

    .val

    (

    data.coord_perc

    )
  160. $(

    '#mapped-form'

    )

    .find

    (

    '[name="description"]'

    )

    .val

    (

    data.description

    )
  161. $(

    '#form_modal'

    )

    .modal

    (

    'show'

    )
  162. }

    )
  163. // Delete Mapped Area
  164. $(

    '#delete-area'

    )

    .click

    (

    function

    (

    )

    {
  165. $(

    '.modal'

    )

    .modal

    (

    'hide'

    )
  166. id =

    $(

    this

    )

    .attr

    (

    'data-id'

    )
  167. data =

    stored[

    id]

    ||

    {

    }
  168. var

    _conf =

    confirm(

    "Are you sure to delete the selected mapped area?"

    )
  169. if

    (

    _conf ===

    true

    )

    {
  170. if

    (

    !!

    stored[

    id]

    )
  171. delete

    stored[

    id]

    ;
  172. }
  173. localStorage.setItem

    (

    'mapped'

    ,

    JSON.stringify

    (

    stored)

    )
  174. alert(

    "Selected Mapped Area Successfully Deleted."

    )
  175. location.reload

    (

    )
  176. }

    )
  177. }

    )

That's it. You can now try to run the application in your browser and see if it works as it was planned to. If you found any errors, kindly review the source code on your end. You can also download the working source code I created for this tutorial. The download button is located below this article.

DEMO VIDEO

That is the end of this tutorial. I hope you will find this tutorial useful for your future web application projects. Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding :)


Download
You must upgrade your account or reply in the thread to view the hidden content.
 

452,496

344,877

344,885

Top