javascript - viewBox 확대/축소와 무관하게 동일한 글꼴 크기 유지
저에게는 이 간단한 데모와 거의 완전히 다른 인터랙티브 SVG 다이어그램이 있습니다…
데모: http://jsfiddle.net/CphxH/6/
…다만 그것이 다음과 관련되는 한:
- 여러 개의
<text>요소를 가지고 있습니다, - 동적으로
viewBox를 조정하며, - 화면에 보이는 글자의 글꼴 크기가 viewBox가 얼마나 큰지와 상관없이 같았으면 합니다.
이상적으로는 vector-effect:non-scaling-stroke와 같은 기능(최소한 Webkit에서는)이 font-size에도 있으면 좋겠습니다. 그런 것이 존재하나요? 없다면, 가장 좋은 방법은 viewBox 크기를 계산하고, aspectRatio와 결합하여 더 큰 축을 결정한 다음, JS를 사용하여 font-size 속성의 CSS 규칙을 조작하는 것일까요?
답변 #1
아니요, viewBox를 변경할 때 텍스트 크기를 일정하게 유지하는 자동 방법은 없습니다. 말씀하신 것처럼 자바스크립트로 텍스트 크기를 조정해야 합니다.
답변 #2
여기 자바스크립트 기반 솔루션이 있습니다. 처음에 한 번 recordSVGFontSizes()를 호출하면서 SVG 요소와 StyleSheet를 전달합니다. 이 함수는 SVG의 뷰포트를 계산하고, 스타일시트를 통과하여 font-size를 언급하는 모든 규칙을 찾아 원래 글꼴 크기를 기록합니다.
그런 다음 viewBox가 변경되면 기록된 값을 normalizeSVGFontSizes()에 전달하세요. 그러면 뷰포트를 다시 계산하고 모든 글꼴 크기를 적절하게 업데이트합니다.
뷰포트 계산이 현재 Firefox에서는 작동하지 않기 때문에 이 스크립트는 그곳에서는 작동하지 않는다는 점에 유의하세요.
데모: http://jsfiddle.net/CphxH/8/
// Do this once at startup
var recording = recordSVGFontSizes( mySVG, document.styleSheets[0] );
// Do this each time the viewport changes
normalizeSVGFontSizes(recording);
function recordSVGFontSizes(svgElement,styleSheet){
var rules = [];
var viewport = calculateViewport(svgElement);
for (var i=styleSheet.cssRules.length;i--;){
var rule = styleSheet.cssRules[i];
if (rule.style.fontSize){
var parts = rule.style.fontSize.split(/(\D+)/);
rules.push({ rule:rule, units:parts[1], perpx:parts[0] / viewport.width });
}
}
return {rules:rules, svg:svgElement};
}
function normalizeSVGFontSizes(fontSizeRecording){
var viewport = calculateViewport(fontSizeRecording.svg);
for (var i=fontSizeRecording.rules.length;i--;){
var record = fontSizeRecording.rules[i];
record.rule.style.fontSize = record.perpx*viewport.width + record.units;
}
}
// Given an <svg> element, returns an object with the visible bounds
// expressed in local viewBox units, e.g.
// { x:-50, y:-50, width:100, height:100 }
function calculateViewport(svg){ // http://phrogz.net/JS/_ReuseLicense.txt
var outer = svg.getBoundingClientRect();
var aspect = svg.preserveAspectRatio.baseVal,
viewBox = svg.viewBox.baseVal,
width = viewBox && viewBox.width || outer.width,
height = viewBox && viewBox.height || outer.height,
x = viewBox ? viewBox.x : 0,
y = viewBox ? viewBox.y : 0;
if (!width || !height || !outer.width) return;
if (aspect.align==aspect.SVG_PRESERVEASPECTRATIO_NONE || !viewBox || !viewBox.height){
return {x:x,y:y,width:width,height:height};
}else{
var inRatio = viewBox.width / viewBox.height,
outRatio = outer.width / outer.height;
var meetFlag = aspect.meetOrSlice != aspect.SVG_MEETORSLICE_SLICE;
var fillAxis = outRatio>inRatio ? (meetFlag?'y':'x') : (meetFlag?'x':'y');
if (fillAxis=='x'){
height = width/outRatio;
var diff = viewBox.height - height;
switch (aspect.align){
case aspect.SVG_PRESERVEASPECTRATIO_UNKNOWN:
case aspect.SVG_PRESERVEASPECTRATIO_XMINYMID:
case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMID:
case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMID:
y += diff/2;
break;
case aspect.SVG_PRESERVEASPECTRATIO_XMINYMAX:
case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMAX:
case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMAX:
y += diff;
break;
}
}
else{
width = height*outRatio;
var diff = viewBox.width - width;
switch (aspect.align){
case aspect.SVG_PRESERVEASPECTRATIO_UNKNOWN:
case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMIN:
case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMID:
case aspect.SVG_PRESERVEASPECTRATIO_XMIDYMAX:
x += diff/2;
break;
case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMID:
case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMIN:
case aspect.SVG_PRESERVEASPECTRATIO_XMAXYMAX:
x += diff;
break;
}
}
return {x:x,y:y,width:width,height:height};
}
}
