diff --git a/examples/custom-rendering/node.border.ts b/examples/custom-rendering/node.border.ts index 338dbe68b..e7a75009d 100644 --- a/examples/custom-rendering/node.border.ts +++ b/examples/custom-rendering/node.border.ts @@ -15,6 +15,9 @@ import { NodeDisplayData, RenderParams } from "sigma/types"; import { floatColor } from "sigma/utils"; import { NodeProgram } from "sigma/rendering/webgl/programs/common/node"; +import { checkDiscNodeCollision } from "sigma/utils/node-collisions"; +import { drawDiscNodeLabel } from "sigma/utils/node-labels"; +import { drawDiscNodeHover } from "sigma/utils/node-hover"; import VERTEX_SHADER_SOURCE from "!raw-loader!./node.border.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "!raw-loader!./node.border.frag.glsl"; @@ -23,6 +26,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_sizeRatio", "u_pixelRatio", "u_matrix"] as const; export default class NodeBorderProgram extends NodeProgram { + checkCollision = checkDiscNodeCollision; + drawLabel = drawDiscNodeLabel; + drawHover = drawDiscNodeHover; + getDefinition() { return { VERTICES: 1, diff --git a/examples/tsconfig.json b/examples/tsconfig.json index caef0a04e..fbfd51713 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -8,6 +8,9 @@ "sigma/types": ["../src/types"], "sigma/utils": ["../src/utils"], "sigma/utils/animate": ["../src/utils/animate"], + "sigma/utils/node-hover": ["../src/utils/node-hover"], + "sigma/utils/node-labels": ["../src/utils/node-labels"], + "sigma/utils/node-collisions": ["../src/utils/node-collisions"], "sigma/rendering/webgl/programs/edge.rectangle": ["../src/rendering/webgl/programs/edge.rectangle.ts"], "sigma/rendering/webgl/programs/edge.line": ["../src/rendering/webgl/programs/edge.line.ts"], "sigma/rendering/webgl/programs/node.image": ["../src/rendering/webgl/programs/node.image.ts"], diff --git a/examples/webpack.config.js b/examples/webpack.config.js index 599a4be21..ab1f2fa00 100644 --- a/examples/webpack.config.js +++ b/examples/webpack.config.js @@ -7,6 +7,9 @@ module.exports = { "sigma/types": path.resolve(__dirname, "../src/types.ts"), "sigma/utils": path.resolve(__dirname, "../src/utils/"), "sigma/utils/animate": path.resolve(__dirname, "../src/utils/animate.ts"), + "sigma/utils/node-hover": path.resolve(__dirname, "../src/utils/node-hover"), + "sigma/utils/node-labels": path.resolve(__dirname, "../src/utils/node-labels"), + "sigma/utils/node-collisions": path.resolve(__dirname, "../src/utils/node-collisions"), "sigma/rendering/webgl/programs/edge": path.resolve(__dirname, "../src/rendering/webgl/programs/edge.ts"), "sigma/rendering/webgl/programs/edge.fast": path.resolve( __dirname, diff --git a/src/rendering/webgl/programs/common/edge.ts b/src/rendering/webgl/programs/common/edge.ts index 8c2baafce..57b7e072e 100644 --- a/src/rendering/webgl/programs/common/edge.ts +++ b/src/rendering/webgl/programs/common/edge.ts @@ -7,6 +7,8 @@ import Sigma from "../../../../sigma"; import { AbstractProgram, Program } from "./program"; import { NodeDisplayData, EdgeDisplayData, RenderParams } from "../../../../types"; +import { EdgeCollisionDetectionFunction } from "../../../../utils/edge-collisions"; +import { EdgeLabelDrawingFunction } from "../../../../utils/edge-labels"; export abstract class AbstractEdgeProgram extends AbstractProgram { abstract process( @@ -15,6 +17,9 @@ export abstract class AbstractEdgeProgram extends AbstractProgram { targetData: NodeDisplayData, data: EdgeDisplayData, ): void; + + abstract checkCollision: EdgeCollisionDetectionFunction; + abstract drawLabel: EdgeLabelDrawingFunction; } export abstract class EdgeProgram @@ -33,12 +38,16 @@ export abstract class EdgeProgram return this.processVisibleItem(i, sourceData, targetData, data); } + abstract processVisibleItem( i: number, sourceData: NodeDisplayData, targetData: NodeDisplayData, data: EdgeDisplayData, ): void; + + abstract checkCollision: EdgeCollisionDetectionFunction; + abstract drawLabel: EdgeLabelDrawingFunction; } export interface EdgeProgramConstructor { @@ -74,5 +83,12 @@ export function createEdgeCompoundProgram(programClasses: Array program.render(params)); } + + checkCollision(...args: Parameters) { + return this.programs.some((program) => program.checkCollision(...args)); + } + drawLabel(...args: Parameters) { + return this.programs[0].drawLabel(...args); + } }; } diff --git a/src/rendering/webgl/programs/common/node.ts b/src/rendering/webgl/programs/common/node.ts index c85219dc7..d7bd6c43d 100644 --- a/src/rendering/webgl/programs/common/node.ts +++ b/src/rendering/webgl/programs/common/node.ts @@ -6,10 +6,16 @@ */ import Sigma from "../../../../sigma"; import { AbstractProgram, Program } from "./program"; -import { NodeDisplayData, RenderParams } from "../../../../types"; +import { NodeDisplayData, NonEmptyArray, RenderParams } from "../../../../types"; +import { NodeCollisionDetectionFunction } from "../../../../utils/node-collisions"; +import { NodeLabelDrawingFunction } from "../../../../utils/node-labels"; +import { NodeHoverDrawingFunction } from "../../../../utils/node-hover"; export abstract class AbstractNodeProgram extends AbstractProgram { abstract process(offset: number, data: NodeDisplayData): void; + abstract checkCollision: NodeCollisionDetectionFunction; + abstract drawLabel: NodeLabelDrawingFunction; + abstract drawHover: NodeHoverDrawingFunction; } export abstract class NodeProgram @@ -28,7 +34,11 @@ export abstract class NodeProgram return this.processVisibleItem(i, data); } + abstract processVisibleItem(i: number, data: NodeDisplayData): void; + abstract checkCollision: NodeCollisionDetectionFunction; + abstract drawLabel: NodeLabelDrawingFunction; + abstract drawHover: NodeHoverDrawingFunction; } export interface NodeProgramConstructor { @@ -43,14 +53,16 @@ export interface NodeProgramConstructor { * @param {array} programClasses - Program classes to combine. * @return {function} */ -export function createNodeCompoundProgram(programClasses: Array): NodeProgramConstructor { +export function createNodeCompoundProgram( + programClasses: NonEmptyArray, +): NodeProgramConstructor { return class NodeCompoundProgram implements AbstractNodeProgram { - programs: Array; + programs: NonEmptyArray; constructor(gl: WebGLRenderingContext, renderer: Sigma) { this.programs = programClasses.map((Program) => { return new Program(gl, renderer); - }); + }) as NonEmptyArray; } reallocate(capacity: number): void { @@ -64,5 +76,15 @@ export function createNodeCompoundProgram(programClasses: Array program.render(params)); } + + checkCollision(...args: Parameters): boolean { + return this.programs.some((program) => program.checkCollision(...args)); + } + drawLabel(...args: Parameters): void { + return this.programs[0].drawLabel(...args); + } + drawHover(...args: Parameters): void { + return this.programs[0].drawHover(...args); + } }; } diff --git a/src/rendering/webgl/programs/edge.arrowHead.ts b/src/rendering/webgl/programs/edge.arrowHead.ts index 9f0db549a..f21c5983a 100644 --- a/src/rendering/webgl/programs/edge.arrowHead.ts +++ b/src/rendering/webgl/programs/edge.arrowHead.ts @@ -10,12 +10,17 @@ import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; import VERTEX_SHADER_SOURCE from "../shaders/edge.arrowHead.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "../shaders/edge.arrowHead.frag.glsl"; +import { checkStraightEdgeCollision } from "../../../utils/edge-collisions"; +import { drawStraightEdgeLabel } from "../../../utils/edge-labels"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix", "u_sizeRatio", "u_correctionRatio"] as const; export default class EdgeArrowHeadProgram extends EdgeProgram { + checkCollision = checkStraightEdgeCollision; + drawLabel = drawStraightEdgeLabel; + getDefinition() { return { VERTICES: 3, diff --git a/src/rendering/webgl/programs/edge.clamped.ts b/src/rendering/webgl/programs/edge.clamped.ts index 77c5fcd02..f25c77b69 100644 --- a/src/rendering/webgl/programs/edge.clamped.ts +++ b/src/rendering/webgl/programs/edge.clamped.ts @@ -12,10 +12,15 @@ import EdgeRectangleProgram from "./edge.rectangle"; import VERTEX_SHADER_SOURCE from "../shaders/edge.clamped.vert.glsl"; import { EdgeDisplayData, NodeDisplayData } from "../../../types"; import { floatColor } from "../../../utils"; +import { checkStraightEdgeCollision } from "../../../utils/edge-collisions"; +import { drawStraightEdgeLabel } from "../../../utils/edge-labels"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; export default class EdgeClampedProgram extends EdgeRectangleProgram { + checkCollision = checkStraightEdgeCollision; + drawLabel = drawStraightEdgeLabel; + getDefinition() { return { ...super.getDefinition(), diff --git a/src/rendering/webgl/programs/edge.line.ts b/src/rendering/webgl/programs/edge.line.ts index 308d40cae..48978f80b 100644 --- a/src/rendering/webgl/programs/edge.line.ts +++ b/src/rendering/webgl/programs/edge.line.ts @@ -11,12 +11,17 @@ import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; import VERTEX_SHADER_SOURCE from "../shaders/edge.line.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "../shaders/edge.line.frag.glsl"; +import { checkStraightEdgeCollision } from "../../../utils/edge-collisions"; +import { drawStraightEdgeLabel } from "../../../utils/edge-labels"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix"] as const; export default class EdgeLineProgram extends EdgeProgram { + checkCollision = checkStraightEdgeCollision; + drawLabel = drawStraightEdgeLabel; + getDefinition() { return { VERTICES: 2, diff --git a/src/rendering/webgl/programs/edge.rectangle.ts b/src/rendering/webgl/programs/edge.rectangle.ts index 7ec4f5134..6341bd84a 100644 --- a/src/rendering/webgl/programs/edge.rectangle.ts +++ b/src/rendering/webgl/programs/edge.rectangle.ts @@ -20,12 +20,17 @@ import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; import VERTEX_SHADER_SOURCE from "../shaders/edge.rectangle.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "../shaders/edge.rectangle.frag.glsl"; +import { checkStraightEdgeCollision } from "../../../utils/edge-collisions"; +import { drawStraightEdgeLabel } from "../../../utils/edge-labels"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix", "u_zoomRatio", "u_sizeRatio", "u_correctionRatio"] as const; export default class EdgeRectangleProgram extends EdgeProgram { + checkCollision = checkStraightEdgeCollision; + drawLabel = drawStraightEdgeLabel; + getDefinition() { return { VERTICES: 4, diff --git a/src/rendering/webgl/programs/edge.triangle.ts b/src/rendering/webgl/programs/edge.triangle.ts index 57f5f11c1..bd98249a1 100644 --- a/src/rendering/webgl/programs/edge.triangle.ts +++ b/src/rendering/webgl/programs/edge.triangle.ts @@ -10,12 +10,17 @@ import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; import VERTEX_SHADER_SOURCE from "../shaders/edge.triangle.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "../shaders/edge.triangle.frag.glsl"; +import { checkStraightEdgeCollision } from "../../../utils/edge-collisions"; +import { drawStraightEdgeLabel } from "../../../utils/edge-labels"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix", "u_sizeRatio", "u_correctionRatio"] as const; export default class EdgeTriangleProgram extends EdgeProgram { + checkCollision = checkStraightEdgeCollision; + drawLabel = drawStraightEdgeLabel; + getDefinition() { return { VERTICES: 3, diff --git a/src/rendering/webgl/programs/node.circle.ts b/src/rendering/webgl/programs/node.circle.ts index d14db84a5..b80a18d50 100644 --- a/src/rendering/webgl/programs/node.circle.ts +++ b/src/rendering/webgl/programs/node.circle.ts @@ -13,6 +13,9 @@ import { floatColor } from "../../../utils"; import { NodeProgram } from "./common/node"; import VERTEX_SHADER_SOURCE from "../shaders/node.circle.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "../shaders/node.circle.frag.glsl"; +import { checkDiscNodeCollision } from "../../../utils/node-collisions"; +import { drawDiscNodeLabel } from "../../../utils/node-labels"; +import { drawDiscNodeHover } from "../../../utils/node-hover"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; @@ -23,6 +26,10 @@ export default class NodeCircleProgram extends NodeProgram { + checkCollision = checkDiscNodeCollision; + drawLabel = drawDiscNodeLabel; + drawHover = drawDiscNodeHover; + getDefinition() { return { VERTICES: 1, diff --git a/src/rendering/webgl/programs/node.point.ts b/src/rendering/webgl/programs/node.point.ts index ff9b3ff26..2f5289f93 100644 --- a/src/rendering/webgl/programs/node.point.ts +++ b/src/rendering/webgl/programs/node.point.ts @@ -12,12 +12,19 @@ import { floatColor } from "../../../utils"; import { NodeProgram } from "./common/node"; import VERTEX_SHADER_SOURCE from "../shaders/node.point.vert.glsl"; import FRAGMENT_SHADER_SOURCE from "../shaders/node.point.frag.glsl"; +import { checkDiscNodeCollision } from "../../../utils/node-collisions"; +import { drawDiscNodeLabel } from "../../../utils/node-labels"; +import { drawDiscNodeHover } from "../../../utils/node-hover"; const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_sizeRatio", "u_pixelRatio", "u_matrix"] as const; export default class NodePointProgram extends NodeProgram { + checkCollision = checkDiscNodeCollision; + drawLabel = drawDiscNodeLabel; + drawHover = drawDiscNodeHover; + getDefinition() { return { VERTICES: 1, diff --git a/src/settings.ts b/src/settings.ts index 1ae68ed23..32ee2c65c 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -8,9 +8,6 @@ import { Attributes } from "graphology-types"; import { assign } from "./utils"; -import drawLabel from "./rendering/canvas/label"; -import drawHover from "./rendering/canvas/hover"; -import drawEdgeLabel from "./rendering/canvas/edge-label"; import { EdgeDisplayData, NodeDisplayData } from "./types"; import NodePointProgram from "./rendering/webgl/programs/node.point"; import EdgeRectangleProgram from "./rendering/webgl/programs/edge.rectangle"; @@ -58,10 +55,6 @@ export interface Settings { zIndex: boolean; minCameraRatio: null | number; maxCameraRatio: null | number; - // Renderers - labelRenderer: typeof drawLabel; - hoverRenderer: typeof drawHover; - edgeLabelRenderer: typeof drawEdgeLabel; // Lifecycle allowInvalidContainer: boolean; @@ -112,11 +105,6 @@ export const DEFAULT_SETTINGS: Settings = { minCameraRatio: null, maxCameraRatio: null, - // Renderers - labelRenderer: drawLabel, - hoverRenderer: drawHover, - edgeLabelRenderer: drawEdgeLabel, - // Lifecycle allowInvalidContainer: false, diff --git a/src/sigma.ts b/src/sigma.ts index 6c56f9bab..11af249d7 100644 --- a/src/sigma.ts +++ b/src/sigma.ts @@ -41,7 +41,7 @@ import { AbstractNodeProgram } from "./rendering/webgl/programs/common/node"; import { AbstractEdgeProgram } from "./rendering/webgl/programs/common/edge"; import TouchCaptor, { FakeSigmaMouseEvent } from "./core/captors/touch"; import { identity, multiplyVec2 } from "./utils/matrices"; -import { doEdgeCollideWithPoint, isPixelColored } from "./utils/edge-collisions"; +import { isPixelColored } from "./utils/edge-collisions"; import { extend } from "./utils/array"; /** @@ -393,19 +393,6 @@ export default class Sigma extends TypedEventEm return this; } - /** - * Method that checks whether or not a node collides with a given position. - */ - private mouseIsOnNode({ x, y }: Coordinates, { x: nodeX, y: nodeY }: Coordinates, size: number): boolean { - return ( - x > nodeX - size && - x < nodeX + size && - y > nodeY - size && - y < nodeY + size && - Math.sqrt(Math.pow(x - nodeX, 2) + Math.pow(y - nodeY, 2)) < size - ); - } - /** * Method that returns all nodes in quad at a given position. */ @@ -435,7 +422,8 @@ export default class Sigma extends TypedEventEm const size = this.scaleSize(data.size); - if (!data.hidden && this.mouseIsOnNode(position, nodePosition, size)) { + const NodeProgram = this.nodePrograms[data.type]; + if (!data.hidden && NodeProgram.checkCollision(position.x, position.y, nodePosition.x, nodePosition.y, size)) { const distance = Math.sqrt(Math.pow(x - nodePosition.x, 2) + Math.pow(y - nodePosition.y, 2)); // TODO: sort by min size also for cases where center is the same @@ -491,7 +479,8 @@ export default class Sigma extends TypedEventEm const size = this.scaleSize(data.size); - if (!this.mouseIsOnNode(e, pos, size)) { + const NodeProgram = this.nodePrograms[data.type]; + if (!NodeProgram.checkCollision(e.x, e.y, pos.x, pos.y, size)) { const node = this.hoveredNode; this.hoveredNode = null; @@ -751,9 +740,12 @@ export default class Sigma extends TypedEventEm // Now we can look for matching edges: const edges = this.graph.filterEdges((key, edgeAttributes, sourceId, targetId, sourcePosition, targetPosition) => { - if (edgeDataCache[key].hidden || nodeDataCache[sourceId].hidden || nodeDataCache[targetId].hidden) return false; + const edgeData = edgeDataCache[key]; + if (edgeData.hidden || nodeDataCache[sourceId].hidden || nodeDataCache[targetId].hidden) return false; + + const EdgeProgram = this.edgePrograms[edgeData.type]; if ( - doEdgeCollideWithPoint( + EdgeProgram.checkCollision( graphX, graphY, sourcePosition.x, @@ -761,7 +753,7 @@ export default class Sigma extends TypedEventEm targetPosition.x, targetPosition.y, // Adapt the edge size to the zoom ratio: - this.scaleSize(edgeDataCache[key].size * transformationRatio), + this.scaleSize(edgeData.size * transformationRatio), ) ) { return true; @@ -988,7 +980,8 @@ export default class Sigma extends TypedEventEm // an issue once we start memoizing getLabelsToDisplay. this.displayedNodeLabels.add(node); - this.settings.labelRenderer( + const nodeProgram = this.nodePrograms[data.type]; + nodeProgram.drawLabel( context, { key: node, @@ -1044,7 +1037,8 @@ export default class Sigma extends TypedEventEm continue; } - this.settings.edgeLabelRenderer( + const edgeProgram = this.edgePrograms[edgeData.type]; + edgeProgram.drawLabel( context, { key: edge, @@ -1092,7 +1086,8 @@ export default class Sigma extends TypedEventEm const size = this.scaleSize(data.size); - this.settings.hoverRenderer( + const nodeProgram = this.nodePrograms[data.type]; + nodeProgram.drawHover( context, { key: node, @@ -1611,7 +1606,7 @@ export default class Sigma extends TypedEventEm /** * Method used to get all the sigma edge attributes. - * It's usefull for example to get values that are set by the edgeReducer. + * It's useful for example to get values that are set by the edgeReducer. * * @param {string} key - The edge's key. * @return {EdgeDisplayData | undefined} A copy of the desired edge's attribute or undefined if not found @@ -1830,7 +1825,7 @@ export default class Sigma extends TypedEventEm /** * Method used to schedule a render at the next available frame. * This method can be safely called on a same frame because it basically - * debounce refresh to the next frame. + * debounces refresh to the next frame. * * @return {Sigma} */ @@ -1848,7 +1843,7 @@ export default class Sigma extends TypedEventEm * Method used to schedule a refresh (i.e. fully reprocess graph data and render) * at the next available frame. * This method can be safely called on a same frame because it basically - * debounce refresh to the next frame. + * debounces refresh to the next frame. * * @return {Sigma} */ diff --git a/src/types.ts b/src/types.ts index 7e7bcdddf..a47f5e9ab 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,6 +21,8 @@ export type PlainObject = { [k: string]: T }; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type PartialButFor = Pick & Partial> & { [others: string]: any }; +export type NonEmptyArray = [T, ...T[]]; + export interface Coordinates { x: number; y: number; diff --git a/src/utils/edge-collisions.ts b/src/utils/edge-collisions.ts index 0bcdd95ac..d4b849901 100644 --- a/src/utils/edge-collisions.ts +++ b/src/utils/edge-collisions.ts @@ -1,3 +1,13 @@ +export type EdgeCollisionDetectionFunction = ( + pointX: number, + pointY: number, + sourceX: number, + sourceY: number, + targetX: number, + targetY: number, + thickness: number, +) => boolean; + /** * This helper returns true is the pixel at (x,y) in the given WebGL context is * colored, and false else. @@ -9,33 +19,33 @@ export function isPixelColored(gl: WebGLRenderingContext, x: number, y: number): } /** - * This helper checks whether or not a point (x, y) collides with an - * edge, connecting a source (xS, yS) to a target (xT, yT) with a thickness in - * pixels. + * This helper checks whether a point collides with a straight edge. All + * arguments must be coordinates and sizes on the stage, in pixels. */ -export function doEdgeCollideWithPoint( - x: number, - y: number, - xS: number, - yS: number, - xT: number, - yT: number, +export function checkStraightEdgeCollision( + pointX: number, + pointY: number, + sourceX: number, + sourceY: number, + targetX: number, + targetY: number, thickness: number, ): boolean { // Check first if point is out of the rectangle which opposite corners are the // source and the target, rectangle we expand by `thickness` in every - // directions: - if (x < xS - thickness && x < xT - thickness) return false; - if (y < yS - thickness && y < yT - thickness) return false; - if (x > xS + thickness && x > xT + thickness) return false; - if (y > yS + thickness && y > yT + thickness) return false; + // direction: + if (pointX < sourceX - thickness && pointX < targetX - thickness) return false; + if (pointY < sourceY - thickness && pointY < targetY - thickness) return false; + if (pointX > sourceX + thickness && pointX > targetX + thickness) return false; + if (pointY > sourceY + thickness && pointY > targetY + thickness) return false; // Check actual collision now: Since we now the point is in this big rectangle // we "just" need to check that the distance between the point and the line // connecting the source and the target is less than `thickness`: // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line const distance = - Math.abs((xT - xS) * (yS - y) - (xS - x) * (yT - yS)) / Math.sqrt(Math.pow(xT - xS, 2) + Math.pow(yT - yS, 2)); + Math.abs((targetX - sourceX) * (sourceY - pointY) - (sourceX - pointX) * (targetY - sourceY)) / + Math.sqrt(Math.pow(targetX - sourceX, 2) + Math.pow(targetY - sourceY, 2)); return distance < thickness / 2; } diff --git a/src/rendering/canvas/edge-label.ts b/src/utils/edge-labels.ts similarity index 84% rename from src/rendering/canvas/edge-label.ts rename to src/utils/edge-labels.ts index b8e5887a5..8b271b409 100644 --- a/src/rendering/canvas/edge-label.ts +++ b/src/utils/edge-labels.ts @@ -1,14 +1,15 @@ -/** - * Sigma.js Canvas Renderer Edge Label Component - * ============================================= - * - * Function used by the canvas renderer to display a single edge's label. - * @module - */ -import { Settings } from "../../settings"; -import { EdgeDisplayData, NodeDisplayData, PartialButFor } from "../../types"; - -export default function drawEdgeLabel( +import { EdgeDisplayData, NodeDisplayData, PartialButFor } from "../types"; +import { Settings } from "../settings"; + +export type EdgeLabelDrawingFunction = ( + context: CanvasRenderingContext2D, + edgeData: PartialButFor, + sourceData: PartialButFor, + targetData: PartialButFor, + settings: Settings, +) => void; + +export function drawStraightEdgeLabel( context: CanvasRenderingContext2D, edgeData: PartialButFor, sourceData: PartialButFor, diff --git a/src/utils/node-collisions.ts b/src/utils/node-collisions.ts new file mode 100644 index 000000000..3ca70bd35 --- /dev/null +++ b/src/utils/node-collisions.ts @@ -0,0 +1,40 @@ +export type NodeCollisionDetectionFunction = ( + pointX: number, + pointY: number, + nodeX: number, + nodeY: number, + size: number, +) => boolean; + +/** + * This helper checks whether a point collides with a square node. All arguments + * must be coordinates and sizes on the stage, in pixels. + */ +export function checkSquareNodeCollision( + pointX: number, + pointY: number, + nodeX: number, + nodeY: number, + size: number, +): boolean { + return pointX > nodeX - size && pointX < nodeX + size && pointY > nodeY - size && pointY < nodeY + size; +} + +/** + * This helper checks whether a point collides with a disc node. All arguments + * must be coordinates and sizes on the stage, in pixels. + */ +export function checkDiscNodeCollision( + pointX: number, + pointY: number, + nodeX: number, + nodeY: number, + size: number, +): boolean { + return ( + // Check first the circumscribed square, because it's way cheaper, and + // should discriminate most cases: + checkSquareNodeCollision(pointX, pointY, nodeX, nodeY, size) && + Math.sqrt(Math.pow(pointX - nodeX, 2) + Math.pow(pointY - nodeY, 2)) < size + ); +} diff --git a/src/rendering/canvas/hover.ts b/src/utils/node-hover.ts similarity index 81% rename from src/rendering/canvas/hover.ts rename to src/utils/node-hover.ts index e59e0a4e8..90bc02ccc 100644 --- a/src/rendering/canvas/hover.ts +++ b/src/utils/node-hover.ts @@ -1,14 +1,12 @@ -/** - * Sigma.js Canvas Renderer Hover Component - * ========================================= - * - * Function used by the canvas renderer to display a single node's hovered - * state. - * @module - */ -import { Settings } from "../../settings"; -import { NodeDisplayData, PartialButFor } from "../../types"; -import drawLabel from "./label"; +import { Settings } from "../settings"; +import { NodeDisplayData, PartialButFor } from "../types"; +import { drawDiscNodeLabel } from "./node-labels"; + +export type NodeHoverDrawingFunction = ( + context: CanvasRenderingContext2D, + data: PartialButFor, + settings: Settings, +) => void; /** * Draw an hovered node. @@ -16,7 +14,7 @@ import drawLabel from "./label"; * - if the label box is bigger than node size => display a label box that contains the node with a shadow * - else node with shadow and the label box */ -export default function drawHover( +export function drawDiscNodeHover( context: CanvasRenderingContext2D, data: PartialButFor, settings: Settings, @@ -65,5 +63,5 @@ export default function drawHover( context.shadowBlur = 0; // And finally we draw the label - drawLabel(context, data, settings); + drawDiscNodeLabel(context, data, settings); } diff --git a/src/rendering/canvas/label.ts b/src/utils/node-labels.ts similarity index 64% rename from src/rendering/canvas/label.ts rename to src/utils/node-labels.ts index 7e0c75f5e..2a0ff3f5a 100644 --- a/src/rendering/canvas/label.ts +++ b/src/utils/node-labels.ts @@ -1,14 +1,13 @@ -/** - * Sigma.js Canvas Renderer Label Component - * ========================================= - * - * Function used by the canvas renderer to display a single node's label. - * @module - */ -import { Settings } from "../../settings"; -import { NodeDisplayData, PartialButFor } from "../../types"; +import { NodeDisplayData, PartialButFor } from "../types"; +import { Settings } from "../settings"; -export default function drawLabel( +export type NodeLabelDrawingFunction = ( + context: CanvasRenderingContext2D, + data: PartialButFor, + settings: Settings, +) => void; + +export function drawDiscNodeLabel( context: CanvasRenderingContext2D, data: PartialButFor, settings: Settings,