Home > Back-end >  Using onclick event, how to match name with multiple status by drawing lines in Vuejs?
Using onclick event, how to match name with multiple status by drawing lines in Vuejs?

Time:12-11

new Vue({
  el: "#app",
  
  data: {
    getQuestionAnswers: [
        {
        name: 'foo',
        checked: false,
        status: 'ok'
      },
      {
        name: 'bar',
        checked: false,
        status: 'notok'
      },
      {
        name: 'baz',
        checked: false,
        status: 'medium'
      },
            {
        name: 'oo',
        checked: false,
        status: 'medium'
      }
    ]
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
  width:100%
}

.red {
  color: red;
}
.bcom {
   width: 100%;
   display: flex;
}
.container1 {
   width: 50px;
 }
 .container2 {
   width: calc(100% - 105px);
   padding: 8px 0;
   height: 30px;
   box-sizing: border-box;
  }
 .h-line {
  height: 1px;
  margin-bottom: 18px;
  width: 100%;
  background-color: black;
 }
.container3{
  margin-left: 5px;
  width: 50px;
}


.point:hover {
  width: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
 <div 
    v-for="(group, index) in getQuestionAnswers"
    :key="index   group.name"
    :group="group"
  >
  <div>
   <input type="checkbox" v-model="group.checked"/>
    {{ group.name }}
  </div>
  <div >
   <div  v-if="group.checked"></div>
  </div>
  <div>
  <input type="checkbox"/> 
    {{ group.status }}
  </div>
  </div>
</div>

Onclick of checkbox, how to add multiple lines from one point in Vuejs?

As seen in the image, On click of the checkbox, Based on the status, I need to match from one point to three multiple status. like "ok, notok, medium"

i have taken v-model in the checkbox,to check and perfome two way data binding But not sure....what to do further. Do I need to take computed property and write condition to check and draw three multiple lines???

CodePudding user response:

there are som positioning issues here, but this sample should be enough for you to get it working:

template

  <div id="demo" :ref="'plane'">
    <canvas :ref="'canvas'"></canvas>
    <div
      
      v-for="(group, index) in getQuestionAnswers"
      :key="index   group.name"
      :group="group"
    >
      <div>
        <input
          type="checkbox"
          v-on:click="() => onToggleCheckbox(group)"
          v-model="group.checked"
          :ref="'checkbox_'   group.name"
        />
        <span>{{ group.name }}</span>
      </div>
      <div>
        <span>{{ group.status }}</span>
        <input type="checkbox" :ref="'status_'   group.name" />
      </div>
    </div>
  </div>

script:

export default {
  name: 'App',
  data: () => ({
    ctx: undefined,
    draw(begin, end, stroke = 'black', width = 1) {
      if (!this.ctx) {
        const canvas = this.$refs['canvas'];
        if (!canvas?.getContext) return;

        canvas.width = canvas.offsetWidth;
        canvas.height = canvas.offsetHeight;

        this.ctx = canvas.getContext('2d');
      }

      if (stroke) {
        this.ctx.strokeStyle = stroke;
      }

      if (width) {
        this.ctx.lineWidth = width;
      }

      this.ctx.beginPath();
      this.ctx.moveTo(...begin);
      this.ctx.lineTo(...end);
      this.ctx.stroke();
    },
    onToggleCheckbox(group) {
      const planeEl = this.$refs['plane'];
      const planeRect = planeEl.getBoundingClientRect();

      const fromEl = this.$refs['checkbox_'   group.name];
      const fromRect = fromEl.getBoundingClientRect();
      const from = {
        x: fromRect.right - planeRect.left,
        y: fromRect.top   fromRect.height / 2 - planeRect.top,
      };

      const toEl = this.$refs['status_'   group.name];
      const toRect = toEl.getBoundingClientRect();
      const to = {
        x: toRect.left - planeRect.left,
        y: toRect.top   toRect.height / 2 - planeRect.top,
      };

      console.log(planeRect, from, to);

      this.draw(
        Object.values(from),
        Object.values(to),
        group.checked ? 'white' : 'black',
        group.checked ? 3 : 2
      );
    },
    getQuestionAnswers: [
      {
        name: 'foo',
        checked: false,
        status: 'ok',
      },
      {
        name: 'bar',
        checked: false,
        status: 'notok',
      },
      {
        name: 'baz',
        checked: false,
        status: 'medium',
      },
      {
        name: 'oo',
        checked: false,
        status: 'medium',
      },
    ],
  }),
};

style

body {
  background: #20262e;
  padding: 20px;
  font-family: Helvetica;
}

#demo {
  position: relative;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

canvas {
  position: absolute;
  background: red;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  background: #fff;
  z-index: -1;
}

.bcom {
  width: 100%;
  display: flex;
  justify-content: space-between;
  z-index: 2;
}

this only draws one line but you could easily add the others. I figured you might change your data schema to something like:

getQuestions() {
      {
        name: string,
        checked: boolean,
        statuses: [string...],
      },
getStatuses() {
      {
        name: string
      }

but not knowing about your requirements here, I decided to post the above before making further changes. (here is the sort of refactor I was referring to: https://stackblitz.com/edit/vue-yuvsxa )

addressing first comment:

in app.vue only there is one data called[((questions))], inside question we are looping and setting the status.

this is easy to address with a bit of preprocessing:

questionsAndStatusesMixed: // such as [{...question, ...statuses}],
questions: [],
statuses: [],
mounted() {
  const statusesSet = new Set()
  this.questions.forEach(item => {
    const question = {
        name: item.name,
        checked: item.checked,
        answer: item.status // is this the answer or .. these never made sense to me,
        statuses: this.statuses // assuming each question should admit all statuses/that is, draw a line to each
    }
    const status = {
      name: item.name
    }
    this.questions.push(question)
    statusesSet.add(status)
  })
  Array.from(statusesSet).forEach(item => this.statuses.push(item))
}
  • Related