import { getTypeMap } from '../common/units.js'; import rulersTemplate from './templates/rulersTemplate.js'; /** * */ class Rulers { /** * @type {Module} */ constructor (editor) { // Make [1,2,5] array this.rulerIntervals = []; for (let i = 0.1; i < 1e5; i *= 10) { this.rulerIntervals.push(i); this.rulerIntervals.push(2 * i); this.rulerIntervals.push(5 * i); } this.svgCanvas = editor.svgCanvas; this.editor = editor; // add rulers component to the DOM this.editor.$svgEditor.append(rulersTemplate.content.cloneNode(true)); const { $id } = this.svgCanvas; this.rulerX = $id('ruler_x'); this.rulerY = $id('ruler_y'); this.rulerCorner = $id('ruler_corner'); } display (on) { if (on) { this.rulerX.style.removeProperty('display'); this.rulerY.style.removeProperty('display'); this.rulerCorner.style.removeProperty('display'); } else { this.rulerX.style.display = 'none'; this.rulerY.style.display = 'none'; this.rulerCorner.style.display = 'none'; } } /** * @type {Module} */ manageScroll () { if (this.rulerX) this.rulerX.scrollLeft = this.editor.workarea.scrollLeft; if (this.rulerY) this.rulerY.scrollTop = this.editor.workarea.scrollTop; } /** * * @param {HTMLDivElement} [scanvas] * @param {Float} [zoom] * @returns {void} */ updateRulers (scanvas, zoom) { if (!zoom) { zoom = this.svgCanvas.getZoom(); } if (!scanvas) { scanvas = document.getElementById('svgcanvas'); } let d; let i; const limit = 30000; const contentElem = this.svgCanvas.getContentElem(); const units = getTypeMap(); const unit = units[this.editor.configObj.curConfig.baseUnit]; // 1 = 1px // draw x ruler then y ruler for (d = 0; d < 2; d++) { const isX = (d === 0); const dim = isX ? 'x' : 'y'; const lentype = isX ? 'width' : 'height'; const contentDim = Number(contentElem.getAttribute(dim)); const { $id } = this.svgCanvas; const $hcanvOrig = $id('ruler_' + dim).querySelector('canvas'); // Bit of a hack to fully clear the canvas in Safari & IE9 const $hcanv = $hcanvOrig.cloneNode(true); // eslint-disable-next-line no-unsanitized/property $hcanvOrig.replaceWith($hcanv); const hcanv = $hcanv; // Set the canvas size to the width of the container let rulerLen; if(lentype === 'width'){ rulerLen = parseFloat(getComputedStyle(scanvas, null).width.replace("px", "")); } else if(lentype === 'height'){ rulerLen = parseFloat(getComputedStyle(scanvas, null).height.replace("px", "")); } const totalLen = rulerLen; hcanv.parentNode.style[lentype] = totalLen + 'px'; let ctx = hcanv.getContext('2d'); let ctxArr; let num; let ctxArrNum; ctx.fillStyle = 'rgb(200,0,0)'; ctx.fillRect(0, 0, hcanv.width, hcanv.height); // Remove any existing canvasses const elements = Array.prototype.filter.call($hcanv.parentNode.children, function(child){ return child !== $hcanv; }); Array.from(elements).forEach(function(element) { element.remove(); }); // Create multiple canvases when necessary (due to browser limits) if (rulerLen >= limit) { ctxArrNum = Number.parseInt(rulerLen / limit) + 1; ctxArr = []; ctxArr[0] = ctx; let copy; for (i = 1; i < ctxArrNum; i++) { hcanv[lentype] = limit; copy = hcanv.cloneNode(true); hcanv.parentNode.append(copy); ctxArr[i] = copy.getContext('2d'); } copy[lentype] = rulerLen % limit; // set copy width to last rulerLen = limit; } hcanv[lentype] = rulerLen; const uMulti = unit * zoom; // Calculate the main number interval const rawM = 50 / uMulti; let multi = 1; for (i = 0; i < this.rulerIntervals.length; i++) { num = this.rulerIntervals[i]; multi = num; if (rawM <= num) { break; } } const bigInt = multi * uMulti; ctx.font = '9px sans-serif'; let rulerD = ((contentDim / uMulti) % multi) * uMulti; let labelPos = rulerD - bigInt; // draw big intervals let ctxNum = 0; while (rulerD < totalLen) { labelPos += bigInt; // const realD = rulerD - contentDim; // Currently unused const curD = Math.round(rulerD) + 0.5; if (isX) { ctx.moveTo(curD, 15); ctx.lineTo(curD, 0); } else { ctx.moveTo(15, curD); ctx.lineTo(0, curD); } num = (labelPos - contentDim) / uMulti; let label; if (multi >= 1) { label = Math.round(num); } else { const decs = String(multi).split('.')[1].length; label = num.toFixed(decs); } // Change 1000s to Ks if (label !== 0 && label !== 1000 && label % 1000 === 0) { label = (label / 1000) + 'K'; } if (isX) { ctx.fillText(label, rulerD + 2, 8); } else { // draw label vertically const str = String(label).split(''); for (i = 0; i < str.length; i++) { ctx.fillText(str[i], 1, (rulerD + 9) + i * 9); } } const part = bigInt / 10; // draw the small intervals for (i = 1; i < 10; i++) { let subD = Math.round(rulerD + part * i) + 0.5; if (ctxArr && subD > rulerLen) { ctxNum++; ctx.stroke(); if (ctxNum >= ctxArrNum) { i = 10; rulerD = totalLen; continue; } ctx = ctxArr[ctxNum]; rulerD -= limit; subD = Math.round(rulerD + part * i) + 0.5; } // odd lines are slighly longer const lineNum = (i % 2) ? 12 : 10; if (isX) { ctx.moveTo(subD, 15); ctx.lineTo(subD, lineNum); } else { ctx.moveTo(15, subD); ctx.lineTo(lineNum, subD); } } rulerD += bigInt; } ctx.strokeStyle = '#000'; ctx.stroke(); } } } export default Rulers;