How can I make a custom line in a way that is specified by the user

Below is a snippet of code that I am working with:

sample.beginPath();
sample.moveTo(X1.x,Y1.x );
sample.lineTo(X2.x,Y2.y);
sample.stroke();

sample.beginPath();
sample.arc(X1.x, Y1.y, 4, 0, 2 * Math.PI, false);
sample.fill();
sample.lineWidth = 1;
sample.stroke();

sample.beginPath();
sample.arc(X2.x, Y2.y, 4, 0, 2 * Math.PI, false);
sample.fill();
sample.lineWidth = 1;
sample.stroke();

This code generates the following outcome:

https://i.sstatic.net/0VaVL.png

I would like to achieve this desired result:

https://i.sstatic.net/IY9SH.png

In my scenario, the assumption is that it represents a straight line and the circles are accurately rendered.

Note: The line remains connected in an infinite line.

Answer №1

Essentially, all you needed to do was run your code in two loops - one for drawing copies of the line segment in the forward direction, and another for drawing copies in the backward direction.

This adjusted version creates an infinite line by continuously drawing forwards and backwards until it reaches the edges of the canvas.

Take a look at this snapshot of the actual result:

https://i.sstatic.net/nDswK.png

Check out this live demonstration showcasing the final solution:

var canvas = document.getElementById("thecanvas");
var sample = canvas.getContext("2d");

function drawLine(x1, y1, x2, y2) {
    sample.strokeStyle = '#000000';
    
    sample.beginPath();
    sample.moveTo(x1, y1);
    sample.lineTo(x2, y2);
    sample.lineWidth = 2;
    sample.stroke();

    sample.beginPath();
    sample.arc(x1, y1, 4, 0, 2 * Math.PI, false);
    sample.fillStyle = "#FFFFFF";
    sample.fill();
    sample.lineWidth = 1;
    sample.stroke();
}

function drawInfLine(x1, y1, x2, y2) {
    var xstep = x2 - x1;
    var ystep = y2 - y1;
    
    var lastx = x1;
    var lasty = x2;
    var currx;
    var curry; // yum
    
    // Draw forwards
    while (lastx <= canvas.width && lasty <= canvas.height) {
        currx = lastx + xstep;
        curry = lasty + ystep;
        drawLine(lastx, lasty, currx, curry);
        lastx = currx;
        lasty = curry;
    }
    
    // Reset initial drawing point
    lastx = x1;
    lasty = x2;
    
    // Draw backwards
    while (lastx >= 0 && lasty >= 0) {
        currx = lastx - xstep;
        curry = lasty - ystep;
        drawLine(lastx, lasty, currx, curry);
        lastx = currx;
        lasty = curry;
    }
}

drawInfLine(50, 0, 110, 5);
<canvas id="thecanvas" width="400" height="200"></canvas>

JSFiddle Version: https://jsfiddle.net/k83153br/2/

Answer №2

Forget about using a while loop, leverage the power of Math for this task:

By following the algorithm in this particular answer, we can achieve the desired outcome:

var sample = canvas.getContext("2d");

function drawLine(x1, y1, x2, y2) {

  var segLength = Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)),
    startDist = segLength * -2,
    endDist = Math.sqrt(Math.pow((x2 - canvas.width), 2) + Math.pow((y2 - canvas.height), 2));

  var rX1 = x2 + (x2 - x1) / segLength * startDist;
  var rY1 = y2 + (y2 - y1) / segLength * startDist;

  var rX2 = x2 + (x2 - x1) / segLength * endDist;
  var rY2 = y2 + (y2 - y1) / segLength * endDist;

  sample.strokeStyle = '#000000';
  sample.beginPath();
  sample.moveTo(rX1, rY1);
  sample.lineTo(rX2, rY2);
  sample.lineWidth = 2;
  sample.stroke();

  sample.beginPath();
  sample.arc(x1, y1, 4, 0, 2 * Math.PI, false);
  sample.fillStyle = "#FFFFFF";
  sample.fill();
  sample.lineWidth = 1;
  sample.stroke();

  sample.beginPath();
  sample.arc(x2, y2, 4, 0, 2 * Math.PI, false);
  sample.fillStyle = "#FFFFFF";
  sample.fill();
  sample.lineWidth = 1;
  sample.stroke();
}

drawLine(50, 100, 110, 105);
canvas{border:1px solid;}
<canvas id="canvas" width="400" height="200"></canvas>

Answer №3

When it comes to rendering complex shapes in a canvas context, making multiple render calls can slow down the process. One effective solution is to draw the shape once and then use the drawImage() method to copy it.

Here's a basic concept of how it works: The PatternedLine object is designed to create a line using an image, canvas, or SVG by repeating the pattern along the line. You have the flexibility to define your own pattern by providing an image or a pattern callback function.

The pattern can vary from simple text to intricate images like wire or railway tracks.

This approach is notably faster than directly using canvas 2D context render calls. It can easily be customized for animating the pattern, scaling it, and much more. You could even opt to display a video as your line pattern if desired.

// PasternedLine
// width and height represent the dimensions of the repeating pattern
// Providing width and height is optional when supplying an image
// The pattern parameter can either be a function producing the pattern or an image/SVG/canvas element
// The pattern function callback takes three arguments: ctx, w, h
// ctx refers to the drawing context and w/h stand for width/height

function PatternedLine(pattern, width, height) {
    var canvas, w, h;
    if (typeof pattern !== "function") { 
        canvas = pattern;
        w = canvas.width; 
        h = canvas.height;
    } else {
        canvas = document.createElement("canvas"); 
        canvas.width = width;  
        canvas.height = height;
        w = width;
        h = height;
        var ctx = canvas.getContext("2d"); 
        pattern(ctx, w, h); 
    }
    
    this.drawLine = function(targetCtx, x1, y1, x2, y2) {
        var dist = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
        if (dist > 0) {  
            var ang = Math.acos((x2 - x1) / dist);
            if (y2 - y1 > 0) ang = -ang;
            
            targetCtx.setTransform(1, 0, 0, 1, x1, y1);
            targetCtx.rotate(-ang);   
            
            x1 = 0;  
            while (x1 <= dist - w) { 
                targetCtx.drawImage(canvas, x1, -h/2, w, h ); 
                x1 += w;  
            }
            
            if (x1 < dist) {
                var lw = dist - x1; 
                targetCtx.drawImage(canvas, 0, 0, lw, h, x1, -h/2, lw, h); 
            }
            
            targetCtx.setTransform(1, 0, 0, 1, 0, 0);
        }
    }
}

function pattern(ctx, w, h) {
    ctx.strokeStyle = "black";
    ctx.lineWidth = 3;
    ctx.setTransform(1, 0, 0, 1, 0, h/2);
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(w, 0);
    ctx.stroke();
    ctx.fillStyle = "white"
    ctx.beginPath();
    ctx.arc(w/2, 0, 10, 0, Math.PI*2);
    ctx.fill();
    ctx.stroke();
}

var line = new PatternedLine(pattern, 100, 25);
var px = Math.random() * 400 + 50;
var py = Math.random() * 400 + 50;
var px1 = Math.random() * 400 + 50;
var py1 = Math.random() * 400 + 50;
line.drawLine(ctx, px, py, px1, py1); 

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhancing Textures in Three.js: Methods for Gradually Improving Resolution

I am currently working on a Three.js chart that displays multiple images on a 2D plane. At the moment, each individual image is a 32px by 32px segment of larger 2048px by 2048px image atlas files. I intend to enlarge these individual images when users zoo ...

Unable to select date from Angular UI datepicker within accordion due to non-functional calendar button

Check out this plunker http://plnkr.co/edit/2Fs6vCciXRRc7GeUwyR2?p=preview I need some help figuring out why the calendar button isn't working. The calendar popup shows up when clicking on the textbox, but not when clicking the button. It seems that ...

Maintain the CSS style of a parent element even when hovering over its child elements

I have successfully created a navigation bar with a menu that highlights a blue line whenever you hover over a section. However, I am facing an issue with the submenu within a section. I want the parent section to still display the blue line when hovering ...

Managing multiple markers using the LayersControl.Overlay in React Leaflet

I am working on a project that involves displaying multiple public facilities in a city on a map, each represented by a marker. I want to implement a feature where users can filter these facilities based on their typology using checkboxes. Each typology wi ...

What issues can be found in this code snippet for AngularJS in the browser code editor that is interacting with Node.js

Greetings, I am currently working on developing a free in-browser code editor for high school students at the basic level to share knowledge. After extensive research, I came across this link. Following the instructions provided, I made some setups and mod ...

A computed property declared inside a Vue component definition

I'm currently diving into Vue.js 2 and I have a goal of crafting a unique custom component in the form of <bs-container fluid="true"></bs-container>. My intention is for Vue.component() to seamlessly handle the bootstrap 3 container classe ...

Ways to prevent the rise in mana and health points when the number of rebirths is equal to

In the realm of Python, I was able to effortlessly achieve this http://prntscr.com/ns14y9, but I am struggling immensely to replicate it in JavaScript. My goal is for my hp and mana to only increase after the initial rebirth purchase. I attempted an if st ...

Having trouble with proper routing using node.js, socket.io, and the __dirname variable

As a newcomer to node.js, I am struggling with creating a basic route to read a file using node.js and socket.io. The solution may be straightforward, but I feel like I'm missing some fundamental concepts here. var http = require('http' ...

Error encountered while deploying React app on Netlify due to absence of build scripts

I recently deployed a React app on Netlify from GitHub. Unfortunately, the deployment status showed as failed with the following error: Mar 27: Failed during the stage of 'building site': Build script returned a non-zero exit code: 1 I als ...

Mastering the ng-if directive in Angular can help you easily display or hide content based on boolean

Having trouble figuring out what to insert in the last span element where it mentions "I_DO_NOT_KNOW", here is the markup provided: <div class="row"> <div class="key" translate>Label</div> <div class="value form-group"> < ...

Ways to emphasize an HTML element when clicked with the mouse

Can JavaScript be used to create code that highlights the borders of the HTML element where the mouse pointer is placed or clicked, similar to Firebug, but without needing a browser extension and solely relying on JavaScript? If this is possible, how can ...

Tips on persisting dynamic form data using JavaScript and a database query

I have a unique script that generates dynamic form content with inputs named "field-1", "field-2", and so on until the last input is created. How can I effectively save this dynamically generated form to the database? Usually, I would create a form with ...

How do I design a table containing 10 elements and include buttons for navigating to the first, previous, next, and last elements?

I am currently working on creating a table that includes columns for ID, firstName, and lastName. My goal is to display only 10 elements per page and also incorporate buttons for navigating to the first, previous, next, and last pages. Is there a way to m ...

Create a Promise that guarantees to reject with an error

I am relatively new to utilizing promises, as I typically rely on traditional callbacks. The code snippet below is from an Angular Service, but the framework doesn't play a significant role in this context. What really matters is how to generate a pro ...

Sending form data using javascript without refreshing the page

I have a wall/social system similar to Facebook where users can post statuses. I want to add the functionality for users to like, dislike, and comment on a status without the page reloading. How can I achieve this with the form below? if(empty($_GET[&apos ...

Is it possible to load multiple angular applications within a master angular shell application?

I am searching for a method to integrate multiple Angular applications into a single shell Angular application. The concept involves having different teams develop separate Angular apps that can be loaded within a main shell app visible to end users. Thi ...

The jQuery function fails to retrieve data from PHP Ajax response

Currently, I am creating a registration "page". Below is the HTML code for the form: <form class="register_form" method="POST" action="insert.php"> <label class="label_register">Username*:</label> <div class="input_group"> &l ...

What is the reason for adding CSS styles to a JavaScript file without importing them?

/Navbar.js/ import './navbar.scss'; import {FaBars, FaSearch} from "react-icons/fa"; import { useState } from 'react'; function Navbar(){ const [hide,sethide] = useState(true); const barIcon = document.querySelectorAl ...

Unable to locate Ckeditor toolbar option within Vue (Laravel) framework

Currently, I am utilizing Ckeditor5 for Vue in Laravel. In accordance with the provided documentation, I have gone ahead and installed the necessary modules using the command npm install --save @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic. Fol ...

Is it possible to achieve a Column Chart output in R/Highcharts?

Looking to utilize highchart to create a chart with columns stacked within each other for different countries. https://i.sstatic.net/2p1uM.png I want the smaller column to be nested inside the larger one for each country. Any suggestions on how I can ac ...