1 回答

TA貢獻(xiàn)1810條經(jīng)驗(yàn) 獲得超5個(gè)贊
DIV
我強(qiáng)烈建議使用單個(gè)庫(kù)來(lái)繪制整個(gè)圖像,而不僅僅是嘗試組合s 和圖像(這意味著要面對(duì)幾個(gè)對(duì)齊和縮放問(wèn)題)。
我的示例使用 JS 畫布庫(kù)(內(nèi)置在所有較新的瀏覽器中),它需要提供將圖像繪制到頁(yè)面中的 JavaScript 所需的所有原始數(shù)據(jù):在我的示例中,我使用了單個(gè) JSON?input
。
在開(kāi)始我的例子之前:
我不得不承認(rèn)我不明白黃色矩形的含義,我稱它們?yōu)?code>evidences;
我認(rèn)為在 graph3 中存在一個(gè)拼寫錯(cuò)誤:相似的結(jié)束邊緣位于 2700,而長(zhǎng)度為 2000,在我的示例中,我將長(zhǎng)度更改為 4000
我自由地從 graph1 和 graph3 添加了另一對(duì)類似的夫婦
const input = {
? graphs: [{
? ? ? name: "graph1",
? ? ? length: 10000,
? ? ? evidences: [{
? ? ? ? ? from: 100,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 1800,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 3000,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 6000,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 8000,
? ? ? ? ? length: 500
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 9300,
? ? ? ? ? length: 500
? ? ? ? },
? ? ? ],
? ? },
? ? {
? ? ? name: "graph2",
? ? ? length: 8500,
? ? ? evidences: [{
? ? ? ? ? from: 1100,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 2500,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 5000,
? ? ? ? ? length: 1000
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 7000,
? ? ? ? ? length: 500
? ? ? ? },
? ? ? ],
? ? },
? ? {
? ? ? name: "graph3",
? ? ? length: 4000,
? ? ? evidences: [{
? ? ? ? ? from: 1,
? ? ? ? ? length: 2700
? ? ? ? },
? ? ? ? {
? ? ? ? ? from: 3200,
? ? ? ? ? length: 500
? ? ? ? },
? ? ? ],
? ? },
? ],
? similar: [{
? ? ? first: 0,
? ? ? second: 1,
? ? ? from: [1800, 1100],
? ? ? length: 2700,
? ? ? color: "#8080ff",
? ? },
? ? {
? ? ? first: 1,
? ? ? second: 2,
? ? ? from: [1100, 1],
? ? ? length: 2700,
? ? ? color: "#8080ff",
? ? },
? ? {
? ? ? first: 0,
? ? ? second: 1,
? ? ? from: [8000, 7000],
? ? ? length: 500,
? ? ? color: "#8080ff",
? ? },
? ? {
? ? ? first: 0,
? ? ? second: 2,
? ? ? from: [9300, 3200],
? ? ? length: 500,
? ? ? color: "#ff8080",
? ? },
? ],
};
const imgScale = window.devicePixelRatio;
function main() {
? // init
? const nameWidth = 100;
? const lengthWidth = 70;
? const graphHight = 50;
? const canvas = document.getElementById("canvas");
? canvas.style.height = graphHight * input.graphs.length + "px";
? const {
? ? clientWidth,
? ? clientHeight
? } = canvas;
? const width = (canvas.width = clientWidth * imgScale);
? const height = (canvas.height = clientHeight * imgScale);
? const graphWidth = width - (nameWidth + lengthWidth) * imgScale;
? var ctx = canvas.getContext("2d");
? // white fill canvas
? ctx.fillStyle = "#ffffff";
? ctx.fillRect(0, 0, clientWidth, clientHeight);
? // draw each similar
? for (let i = 0; i < input.similar.length; ++i) {
? ? const {
? ? ? first,
? ? ? second,
? ? ? from,
? ? ? length,
? ? ? color
? ? } = input.similar[i];
? ? const middleFirst = graphHight * (first + 0.5) * imgScale;
? ? const middleSecond = graphHight * (second + 0.5) * imgScale;
? ? const fromScaleFirst =
? ? ? (from[0] * graphWidth) / input.graphs[first].length;
? ? const lengthScaleFirst =
? ? ? (length * graphWidth) / input.graphs[first].length;
? ? const fromScaleSecond =
? ? ? (from[1] * graphWidth) / input.graphs[second].length;
? ? const lengthScaleSecond =
? ? ? (length * graphWidth) / input.graphs[second].length;
? ? ctx.fillStyle = color;
? ? ctx.beginPath();
? ? ctx.moveTo(nameWidth * imgScale + fromScaleFirst, middleFirst);
? ? ctx.lineTo(
? ? ? nameWidth * imgScale + fromScaleFirst + lengthScaleFirst,
? ? ? middleFirst
? ? );
? ? ctx.lineTo(
? ? ? nameWidth * imgScale + fromScaleSecond + lengthScaleSecond,
? ? ? middleSecond
? ? );
? ? ctx.lineTo(nameWidth * imgScale + fromScaleSecond, middleSecond);
? ? ctx.closePath();
? ? ctx.fill();
? ? populatePolygons({
? ? ? points: [
? ? ? ? [nameWidth * imgScale + fromScaleFirst, middleFirst],
? ? ? ? [
? ? ? ? ? nameWidth * imgScale + fromScaleFirst + lengthScaleFirst,
? ? ? ? ? middleFirst,
? ? ? ? ],
? ? ? ? [
? ? ? ? ? nameWidth * imgScale + fromScaleSecond + lengthScaleSecond,
? ? ? ? ? middleSecond,
? ? ? ? ],
? ? ? ? [nameWidth * imgScale + fromScaleSecond, middleSecond],
? ? ? ],
? ? ? object: {
? ? ? ? type: "similar",
? ? ? ? first,
? ? ? ? second,
? ? ? ? from,
? ? ? ? length
? ? ? },
? ? });
? }
? // write each similar edge
? ctx.fillStyle = "#008000";
? ctx.font = "20px Arial";
? ctx.textBaseline = "middle";
? ctx.textAlign = "center";
? for (let i = 0; i < input.similar.length; ++i) {
? ? const {
? ? ? first,
? ? ? second,
? ? ? from,
? ? ? length,
? ? ? color
? ? } = input.similar[i];
? ? const middleFirst = graphHight * (first + 0.5) * imgScale;
? ? const middleSecond = graphHight * (second + 0.5) * imgScale;
? ? const fromScaleFirst =
? ? ? (from[0] * graphWidth) / input.graphs[first].length;
? ? const lengthScaleFirst =
? ? ? (length * graphWidth) / input.graphs[first].length;
? ? const fromScaleSecond =
? ? ? (from[1] * graphWidth) / input.graphs[second].length;
? ? const lengthScaleSecond =
? ? ? (length * graphWidth) / input.graphs[second].length;
? ? ctx.fillText(
? ? ? from[0],
? ? ? nameWidth * imgScale + fromScaleFirst,
? ? ? middleFirst - 20
? ? );
? ? ctx.fillText(
? ? ? from[0] + length,
? ? ? nameWidth * imgScale + fromScaleFirst + lengthScaleFirst,
? ? ? middleFirst - 20
? ? );
? ? ctx.fillText(
? ? ? from[1],
? ? ? nameWidth * imgScale + fromScaleSecond,
? ? ? middleSecond - 20
? ? );
? ? ctx.fillText(
? ? ? from[1] + length,
? ? ? nameWidth * imgScale + fromScaleSecond + lengthScaleSecond,
? ? ? middleSecond - 20
? ? );
? }
? //draw each graph
? ctx.strokeStyle = "#000000";
? for (let i = 0; i < input.graphs.length; ++i) {
? ? const graph = input.graphs[i];
? ? const middle = graphHight * (i + 0.5) * imgScale;
? ? ctx.beginPath();
? ? ctx.moveTo(nameWidth * imgScale, middle);
? ? ctx.lineTo(nameWidth * imgScale + graphWidth, middle);
? ? ctx.stroke();
? ? ctx.fillStyle = "#000000";
? ? ctx.textAlign = "left";
? ? ctx.fillText(graph.name, 10, middle);
? ? ctx.textAlign = "right";
? ? ctx.fillText("1", (nameWidth - 10) * imgScale, middle);
? ? ctx.fillText(graph.length, width - 10, middle);
? ? // draw each evidence
? ? ctx.fillStyle = "#ffff80";
? ? for (let l = 0; l < graph.evidences.length; ++l) {
? ? ? const {
? ? ? ? from,
? ? ? ? length
? ? ? } = graph.evidences[l];
? ? ? const fromScale = (from * graphWidth) / graph.length;
? ? ? const lengthScale = (length * graphWidth) / graph.length;
? ? ? ctx.fillRect(
? ? ? ? fromScale + nameWidth * imgScale,
? ? ? ? middle - 10,
? ? ? ? lengthScale,
? ? ? ? 20
? ? ? );
? ? ? ctx.beginPath();
? ? ? ctx.rect(
? ? ? ? fromScale + nameWidth * imgScale,
? ? ? ? middle - 10,
? ? ? ? lengthScale,
? ? ? ? 20
? ? ? );
? ? ? ctx.stroke();
? ? ? populatePolygons({
? ? ? ? points: [
? ? ? ? ? [fromScale + nameWidth * imgScale, middle - 10],
? ? ? ? ? [fromScale + nameWidth * imgScale + lengthScale, middle - 10],
? ? ? ? ? [fromScale + nameWidth * imgScale + lengthScale, middle + 10],
? ? ? ? ? [fromScale + nameWidth * imgScale, middle + 10],
? ? ? ? ],
? ? ? ? object: {
? ? ? ? ? type: "evidence",
? ? ? ? ? graph: i,
? ? ? ? ? evidence: l,
? ? ? ? },
? ? ? });
? ? }
? }
}
const polygons = [];
function populatePolygons(polygon) {
? polygons.push(polygon);
}
function inside(point, vs) {
? var x = point[0],
? ? y = point[1];
? var inside = false;
? for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
? ? var xi = vs[i][0],
? ? ? yi = vs[i][1];
? ? var xj = vs[j][0],
? ? ? yj = vs[j][1];
? ? var intersect =
? ? ? yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
? ? if (intersect) inside = !inside;
? }
? return inside;
}
function mouseEvent(kind, event) {
? const {
? ? offsetX,
? ? offsetY
? } = event;
? for (polygon in polygons) {
? ? const {
? ? ? object,
? ? ? points
? ? } = polygons[polygon];
? ? if (inside([offsetX * imgScale, offsetY * imgScale], points))
? ? ? interaction(kind, object);
? }
}
function interaction(kind, object) {
? const {
? ? type,
? ? graph,
? ? evidence,
? ? first,
? ? second,
? ? from,
? ? length
? } = object;
? if (type == "evidence")
? ? console.log(
? ? ? `${kind} on evidence nr ${evidence + 1} of graph nr ${graph + 1}`
? ? );
? else
? ? console.log(
? ? ? `${kind} on similar between graph nr ${first + 1} from ${
? ? ? ? ? ? from[0]
? ? ? ? ? } and graph nr ${second + 1} from ${from[1]} long ${length}`
? ? );
}
main();
<canvas id="canvas" style="width: 100%" onclick="mouseEvent('click', event)" onmousemove="mouseEvent('move', event)" />
這將為您提供一個(gè)也可以復(fù)制到剪貼板的圖像;嘗試:
左鍵單擊“運(yùn)行代碼片段”按鈕
右鍵單擊結(jié)果圖像
選擇“復(fù)制圖像”上下文菜單(Windows chrome)
粘貼到任何接受剪貼板圖像的程序中
編輯:
根據(jù)新的請(qǐng)求(用戶需要與圖像交互),使用單個(gè)庫(kù)使一切變得更加簡(jiǎn)單這一點(diǎn)并沒(méi)有改變。
使用很棒的多邊形點(diǎn)算法,我們也可以輕松實(shí)現(xiàn)這個(gè)更多目標(biāo)。
我添加了一個(gè)簡(jiǎn)單的控制臺(tái)日志作為概念驗(yàn)證,您可以隨意附加任何其他內(nèi)容。
不幸的是,console.log 幾乎占據(jù)了“運(yùn)行代碼片段”的所有空間,以獲得更好的體驗(yàn):
編輯這個(gè)答案
單擊編輯預(yù)覽中代碼段之外的“編輯上述代碼段”鏈接
按“運(yùn)行”按鈕
添加回答
舉報(bào)