UNPKG

inline-style-editor

Version:

Update CSS rules or add inline style to elements visualy

91 lines (82 loc) 3.4 kB
import { contours } from 'd3-contour'; function pointInBox(p, box) { return !(p.x < box.left || p.x > box.right || p.y > box.bottom || p.y < box.top) } function pointInBoxes(point, boxes) { for (const box of boxes){ if (pointInBox(point, box)) return true; } return false; } function defineRectangleClockWise({width, height, top = 0, left = 0}) { return `M${left} ${top} h${width} v${height} h-${width}z` } function defineRectangleAntiClockWise({width, height, top = 0, left = 0}) { return `M${left} ${top} v${height} h${width} v-${height}z` } function boxOverlap(box1, box2) { return (box1.right >= box2.left && box2.right >= box1.left) && (box1.bottom >= box2.top && box2.bottom >= box1.top) } function boxesHaveOverlap(boundingBoxes) { for (let i = 0; i < boundingBoxes.length - 1; ++i) { const ref = boundingBoxes[i]; for (let j = i + 1; j < boundingBoxes.length; ++j) { if (boxOverlap(ref, boundingBoxes[j])) return true; } } return false; } function computeContours(boundingBoxes, pageDimensions) { let _pathWithHoles = defineRectangleAntiClockWise({width: pageDimensions.width, height: pageDimensions.height}); if (boundingBoxes.length < 10 && !boxesHaveOverlap(boundingBoxes)) { for (const bbox of boundingBoxes) { _pathWithHoles = `${_pathWithHoles} ${defineRectangleClockWise(bbox)}`; } return _pathWithHoles; } const minX = Math.min(...boundingBoxes.map(rect => rect.left)); const minY = Math.min(...boundingBoxes.map(rect => rect.top)); const offsetBoxes = boundingBoxes.map(rect => { rect.left = rect.left - minX; rect.right = rect.right - minX; rect.top = rect.top - minY; rect.bottom = rect.bottom - minY; return rect; }); offsetBoxes.sort((a, b) => { if (a.left > b.left) return 1; if (a.left < b.left) return -1; return 0; }); const maxX = Math.ceil(Math.max(...offsetBoxes.map(rect => rect.right))); const maxY = Math.ceil(Math.max(...offsetBoxes.map(rect => rect.bottom))); const maxNbPixels = 20000; const downscaleFactor = (maxX * maxY) / maxNbPixels; const widthArrayX = Math.ceil(maxX / downscaleFactor); const widthArrayY = Math.ceil(maxY / downscaleFactor); const pixelsByStepX = (maxX) / widthArrayX; const pixelsByStepY = (maxY) / widthArrayY; const values = new Array(widthArrayX * widthArrayY); // one coordinate per pixel for (let j = 0, k = 0; j < widthArrayY; ++j) { for (let i = 0; i < widthArrayX; ++i, ++k) { values[k] = pointInBoxes({x: i * downscaleFactor, y: j * downscaleFactor}, offsetBoxes) ? 1 : 0; } } const computedContours = contours().size([widthArrayX, widthArrayY]).thresholds([1])(values)[0]; let holes = ''; for (let polygon of computedContours.coordinates) { for (let ring of polygon) { for (let i = 0; i < ring.length; ++i) { const point = ring[i]; const x = point[0] * pixelsByStepX + minX; const y = point[1] * pixelsByStepY + minY; if (!i) holes += `M${x} ${y}`; else holes += `L ${x} ${y}`; } holes += 'Z' } } return `${_pathWithHoles} ${holes}`; } export { computeContours };