Home > Software design >  Split image into many smaller images and allow hyperlinks from each individual image (like an imagem
Split image into many smaller images and allow hyperlinks from each individual image (like an imagem

Time:12-01

Summary

I've got an image (1920px x 1080px) which I want to split up into 40px by 40px smaller images. I want to display the images on a webpage so that it appears like the original full 1920x1080 image. It will be 48 images wide (columns) by 27 rows.

For each image I want to be able to have a different hyperlink and alt text.

When the screen size is reactively changed, I want the images to scale down as well so they don't wrap around the page, or, scroll off the page.

Framework

Currently using Vue and Vuetify.

Tried

  1. I've tried using the full image without splitting it up and putting an imagemap on it. This works perfectly whilst it's full screen, however, when the page adjusts reactively to resizing, the imagemap cooridnates are broken as the underlying image size has changed. I could not work out how to get the scale of the image to adjust the imagemap accordingly.

            <template v-slot:activator="{ on, attrs }">
            <v-img ref="imageShow" usemap="" class="image" contain src="@/assets/sections/fullsize_image.jpg" v-resize="onResize">
                <!-- Loop over array of plots by row & col to generate this.
                    Eg. top: = rowId * 40... 
                        left: = colPos * 40
                -->
                <span v-for="(i, row) in listSections"
                    :key="row"
                    justify="center" align="center" class="d-flex flex-nowrap"
                >
                    <!-- i contains an object with URL, alt text etc in it -->
                    <span
                        v-for="col in Object.keys(i)"
                        :key="col"
                    >
                        <a v-bind="attrs" v-on="on" @click="info = i[col]" :style="`${ returnStyle(row,col) }`"></a>
                    </span>
                </span>
            </v-img>
            </template>
    

And the returnStyle is a computed function that calculates the image map for the sections of the picture. If the the image is adjusted due to reactive image resizing I'm not sure how to account for this in the computed function:

    computed: {
    returnStyle: function() {
        return function(row, col) {
            return "position:absolute; top: "   (row * 40)   "px; left: "   (col * 40)   "px; height:40px; width: 40px;"
        }
      }
    }
  1. I've tried Vuetify v-row's and v-col's to contain the v-img... the images weren't scaling down properly, or they were wrapping or just scrolling off the page ().

     <v-container pa-0 fluid ma-0>
         <v-row no-gutters style="maxWidth: 1920px; width: 100%;" class="d-flex flex-nowrap">
             <v-col>
                 <v-img :src="require(`../assets/section/section_0_0.jpg`)"></v-img>
             </v-col>
             <!-- ... 46 more v-col/v-img's  -->                                  
         </v-row>
         <v-row no-gutters style="maxWidth: 1920px; width: 100%;" class="d-flex flex-nowrap">
             <v-col>
                 <v-img :src="require(`../assets/section/section_2_0.jpg`)"></v-img>
             </v-col>
             <!-- ... 46 more v-col/v-img's  -->                          
         </v-row>       
         <v-row no-gutters style="maxWidth: 1920px; width: 100%;" class="d-flex flex-nowrap">
             <v-col>
                 <v-img :src="require(`../assets/section/section_2_0.jpg`)"></v-img>
             </v-col>
             <!-- ... 46 more v-col/v-img's  -->
         </v-row>             
     </v-container>
    

I've had a suggestion to look at Flex or CSS Grid for this, however, I'm slightly apprehensive I'll get to the end of experimenting with them and end up with the same sort of issue.

Any suggestions greatly appreciated. Thanks.

CodePudding user response:

You could put the image as background to a container which has viewport width (or any other size you require) and from this calculate suitable height and display as a grid.

Here is a simple purely JS/CSS example:

const numCols = 1920 / 40;
const numRows = 1080 / 40;
const container = document.querySelector('.container');
for (col = 1; col <= numCols; col  ) {
  for (row = 1; row <= numRows; row  ) {
    let a = document.createElement('a');
    a.style.gridColumn = col   ' / '   (col   1);
    a.style.gridRow = row   ' / '   (row   1);
    a.style.opacity = 0;
    a.href = 'url for cell '   row   ', '   col;
    container.appendChild(a);
  }
}
* {
  padding: 0;
  margin: 0;
}

.container {
  display: grid;
  grid-template-columns: repeat(40, 1fr);
  grid-template-rows: repeat(27, 1fr);
  width: 100vw;
  height: calc(100vw * 1080 / 1920);
  gap: 0;
  background-image: url(https://picsum.photos/id/1016/1920/1080);
  background-size: contain;
  background-repeat: no-repeat;
}
<div class="container">
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

You may want to include an actual img with a src (a transparent png) in each cell to get the alt in there as well.

  • Related