-
-
Save Sjeiti/ea70db7ade56efd0b76fac176067145b to your computer and use it in GitHub Desktop.
Javascript solution for middle ellipsis (see: https://jsfiddle.net/Sjeiti/cxsqv50n/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<main> | |
<h1 data-middle-ellipsis>A Javascript solution to middle ellipsis</h1> | |
<div data-middle-ellipsis>The quick fox</div> | |
<div data-middle-ellipsis class="inline-block">The lazy dog</div> | |
<div data-middle-ellipsis>theQuickBrownFoxJumpsOverTheLazyDog</div> | |
<div data-middle-ellipsis class="bold">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis class="small">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis class="small bold">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis class="large">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis>The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis="70">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis="30">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis="1">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis="99">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis="-3">The quick brown fox jumps over the lazy dog</div> | |
<div data-middle-ellipsis="-3">The quick brown dog</div> | |
<div data-middle-ellipsis="0">The quick brown dog</div> | |
<div data-middle-ellipsis="-1">The quick brown dog</div> | |
<div data-middle-ellipsis="-99">The quick brown dog</div> | |
</main> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Attibute modifier to create middle ellipsis | |
* When the attribute value is left blank the ellipsis will be in the middle | |
* When positive the attribute value will be used as a percentage | |
* When negative the attribute value will be used as character index counted from the end | |
* @example | |
* <div data-middle-ellipsis>A Javascript solution to middle ellipsis</div> | |
* <div data-middle-ellipsis="20">A Javascript solution to middle ellipsis</div> | |
* <div data-middle-ellipsis="-3">A Javascript solution to middle ellipsis</div> | |
*/ | |
const attributeName = 'data-middle-ellipsis' | |
const attributeTextName = attributeName+'-text' | |
const attributeFontName = attributeName+'-font' | |
const clamp = (val,min=Number.NEGATIVE_INFINITY,max=Number.POSITIVE_INFINITY)=>Math.max(min,Math.min(max,val)) | |
const ellipsis = '…' | |
const map = new Map() | |
let timeoutId | |
testMiddleEllipsis() | |
window.addEventListener('resize', onResize, { capture: true, passive: true }) | |
function onResize(e){ | |
clearTimeout(timeoutId) | |
timeoutId = setTimeout(testMiddleEllipsis, 200) | |
} | |
function testMiddleEllipsis() { | |
Array.from(document.querySelectorAll(`[${attributeName}]`)).forEach(elm=>{ | |
// do not recalculate variables a second time | |
const mapped = map.get(elm) | |
let {text, textLength, from, multiplier, font, textWidth, elementWidth} = mapped||{} | |
// first time | |
if (!mapped) { | |
text = elm.textContent | |
textLength = text.length | |
from = parseFloat(elm.getAttribute(attributeName))||50 | |
multiplier = from>0&&from/100 | |
const computedStyle = window.getComputedStyle(elm, null) | |
font = `${computedStyle.getPropertyValue('font-weight')} ${computedStyle.getPropertyValue('font-size')} ${computedStyle.getPropertyValue('font-family')}` | |
textWidth = getTextWidth(text, font) | |
elementWidth = elm.offsetWidth | |
map.set(elm, {text, textLength, from, multiplier, font, textWidth, elementWidth}) | |
} | |
// | |
const {offsetWidth} = elm | |
const widthChanged = !mapped||elementWidth!==offsetWidth | |
mapped&&widthChanged&&(mapped.elementWidth=elementWidth=offsetWidth) | |
// | |
if (widthChanged&&textWidth>elementWidth) { | |
elm.setAttribute('title', text) | |
let smallerText = text | |
let smallerWidth = elementWidth | |
while(smallerText.length>3){ | |
let smallerTextLength = smallerText.length | |
const half = multiplier&& | |
clamp(multiplier*smallerTextLength<<0,1,smallerTextLength-2)|| | |
Math.max(smallerTextLength+from-1,1) | |
const half1 = smallerText.substr(0,half).replace(/\s*$/,'') | |
const half2 = smallerText.substr(half+1).replace(/^\s*/,'') | |
smallerText = half1+half2 | |
smallerWidth = getTextWidth(smallerText+ellipsis, font) | |
if (smallerWidth<elementWidth) { | |
elm.textContent = half1+ellipsis+half2 | |
break; | |
} | |
} | |
} | |
}) | |
} | |
/** | |
* Get the text width | |
* @param {string} text | |
* @param {string} font | |
*/ | |
function getTextWidth(text, font) { | |
let context = getTextWidth.context | |
if (!context) { | |
const canvas = document.createElement('canvas') | |
context = getTextWidth.context = canvas.getContext('2d') | |
} | |
context.font = font | |
const metrics = context.measureText(text) | |
return metrics.width | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$width: 130px; | |
html,body{ | |
width: 100%; | |
height: 100%; | |
line-height: 170%; | |
} | |
main { | |
width: 100%; | |
height: 100%; | |
font-family: Arial; | |
background: #fff linear-gradient(90deg | |
,transparent $width | |
,#f0f0f0 $width | |
,#f0f0f0 2*$width | |
,transparent 2*$width | |
); | |
} | |
[data-middle-ellipsis]{ | |
max-width: $width; | |
white-space: nowrap; | |
box-shadow: -1px 0 0 red inset; | |
} | |
.inline-block { display: inline-block; } | |
.bold { font-weight: bold; } | |
.small { font-size: 10px; } | |
.large { font-size: 32px; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment