[]
        
(Showing Draft Content)

SpreadJS는 사용자가 차트에서 축(Axis)과 표시 단위를 구성하고 사용자 지정할 수 있도록 지원합니다.

축이란

축은 그림 영역의 가로 스케일(x축 또는 category axis)과 세로 스케일(y축 또는 value axis)을 기준으로 하는 차원의 개념을 의미합니다.

차트 축의 유형: 일반적으로 기본 2차원 차트에는 네 가지 유형의 축이 포함됩니다. 즉, 기본 범주 축(primary category axis), 기본 값 축(primary value axis), 보조 범주 축(secondary category axis), 보조 값 축(secondary value axis)입니다.

값 축에서의 표시 단위 구성하기

표시 단위는 값 축(기본 값 축과 보조 값 축 모두)에서만 구성할 수 있습니다. SpreadJS에서 차트를 사용할 때 축의 표시 단위를 구성하는 방법은 두 가지가 있습니다:

  1. 사용자는 표시 단위 값을 표시할 때, 미리 정의된 옵션 목록 중에서 선택할 수 있습니다. (None, Hundreds, Thousands, 10000, 100000, Millions, 100000000000, 10000000000, Billions, Trillions 등)

  2. 사용자는 빌트인 옵션에 없는 의미 있는 숫자 값을 사용하여 사용자 지정 표시 단위를 정의할 수 있습니다. 단, 사용자 지정 표시 단위는 반드시 양의 숫자여야 하며, 사용자 지정 문자열은 지원되지 않습니다.


다음 스크린샷은 기본 값 축에는 빌트인 표시 단위가, 보조 값 축에는 사용자 지정 표시 단위가 구성된 차트를 보여줍니다.

Ask ChatGPT




사용자는 클래스의 메서드를 사용하여 차트의 축을 가져오거나 설정할 수 있습니다. 차트를 사용할 때, 사용자는 축의 표시 단위를 자신의 특정 요구사항과 선호도에 따라 추가, 수정, 사용자 지정할 수 있습니다.

만약 차트에서 축의 표시 단위를 삭제하고자 한다면, 해당 축의 표시 단위 값을 null로 설정해야 합니다.

지원되는 차트 유형 – 값 축을 포함하는 모든 차트 유형은 축의 표시 단위 구성을 지원합니다. 따라서, 기본 값 축과 보조 값 축만 지원됩니다.

표시 단위 레이블 사용자 지정

축의 표시 단위를 구성할 때, 사용자는 표시 단위 레이블을 표시하거나 숨길지 선택할 수 있습니다.

또한, 표시 단위 레이블의 기본 외형을 수정하여 글꼴을 변경하거나, 글꼴 색상을 사용자 지정하거나, 글꼴 패밀리를 설정하는 것도 가능합니다.

참고: 차트에서 축의 표시 단위를 구성하고 사용자 지정할 때 다음의 제한 사항을 유의해야 합니다:

  • JSON I/O 작업 시, DisplayUnit의 모든 속성이 지원됩니다. 그러나 Excel I/O 작업 시, DisplayUnit에 설정된 스타일 정보는 Excel 파일의 XML에 저장되지 않기 때문에, 표시 단위 레이블의 스타일은 XML에서 손실됩니다.

  • 이 기능은 표시 단위 레이블의 텍스트 자체는 사용자 지정할 수 없습니다.

다음 코드 샘플은 차트에서 축과 표시 단위 레이블을 구성하는 방법을 보여줍니다.

Ask ChatGPT

$(document).ready(function () {
    // Spread 초기화
    var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'), { sheetCount: 1 });

    // activesheet 가져오기
    var activeSheet = spread.getActiveSheet();
    activeSheet.suspendPaint();
    // 차트를 위한 데이터 준비 
    activeSheet.setValue(0, 1, "Y-2015");
    activeSheet.setValue(0, 2, "Y-2016");
    activeSheet.setValue(0, 3, "Y-2017");
    activeSheet.setValue(0, 4, "Y-2018");
    activeSheet.setValue(0, 5, "Y-2019");
    activeSheet.setValue(1, 0, "Gradlco Corp. Ltd");
    activeSheet.setValue(2, 0, "Saagiate Corp. Ltd.");
    activeSheet.setColumnWidth(0, 120);
    for (var r = 1; r <= 2; r++) {
        for (var c = 1; c <= 5; c++) {
            activeSheet.setValue(r, c, parseInt(Math.random() * 5000));
        }
    }

    // columnClustered 차트 추가
    chart_columnClustered = activeSheet.charts.add('chart_columnClustered', GC.Spread.Sheets.Charts.ChartType.columnClustered, 50, 100, 500, 400);
    var series = chart_columnClustered.series();
    series.add({
        chartType: GC.Spread.Sheets.Charts.ChartType.columnClustered,
        axisGroup: GC.Spread.Sheets.Charts.AxisGroup.primary,
        name: "Sheet1!$A$2",
        xValues: "Sheet1!$B$1:$F$1",
        yValues: "Sheet1!$B$2:$D$2"
    });
    series.add({
        chartType: GC.Spread.Sheets.Charts.ChartType.line,
        axisGroup: GC.Spread.Sheets.Charts.AxisGroup.secondary,
        name: "Sheet1!$A$3",
        xValues: "Sheet1!$B$1:$F$1",
        yValues: "Sheet1!$B$3:$D$3"
    });
    var axes = chart_columnClustered.axes();

// 기본 범주 축(Primary Category Axis) 구성
axes.primaryCategory.style.color = 'green';
axes.primaryCategory.title.color = 'green';
axes.primaryCategory.title.text = 'Primary Category Axes';

// 기본 값 축(Primary Value Axis) 구성
axes.primaryValue.style.color = 'blue';
axes.primaryValue.title.color = 'blue';
axes.primaryValue.title.text = 'Primary Value Axes';
axes.primaryValue.title.fontSize = 16;

// 기본 값 축에 대한 빌트인 표시 단위(BuiltIn DisplayUnit) 구성
axes.primaryValue.displayUnit = {
    unit: GC.Spread.Sheets.Charts.DisplayUnit.thousands, // 빌트인 표시 단위는 thousands
    visible: true,
    style: {
        color: 'red',
        transparency: 0.1,
        fontFamily: 'arial',
        fontSize: 14
    }
};

// 보조 범주 축(Secondary Category Axis) 구성
axes.secondaryCategory.visible = true;
axes.secondaryCategory.style.color = 'green';
axes.secondaryCategory.title.color = 'green';
axes.secondaryCategory.title.text = 'Secondary Category Axes';
axes.secondaryCategory.title.fontSize = 16;

// 보조 값 축(Secondary Value Axis)에 대한 사용자 지정 표시 단위(Custom DisplayUnit) 구성
axes.secondaryValue.displayUnit = {
    unit: 500, // 사용자 지정 표시 단위는 500
    visible: true,
    style: {
        color: 'red',
        transparency: 0.1,
        fontFamily: 'Verdana',
        fontSize: 14
    }
};

// 보조 값 축 구성
axes.secondaryValue.style.color = 'blue';
axes.secondaryValue.title.color = 'blue';
axes.secondaryValue.format = 'General';
axes.secondaryValue.title.text = 'Secondary Value Axes';

// 구성한 축을 차트에 적용
chart_columnClustered.axes(axes);

// 차트 제목 구성;
    // Configure Chart Title
    var title = chart_columnClustered.title();
    title.text = "Annual Sales Record";
    title.fontFamily = "Cambria";
    title.fontSize = 28;
    title.color = "Red";
    chart_columnClustered.title(title);
    activeSheet.resumePaint();
});

카테고리 축에 날짜 구성하기

SpreadJS는 사용자가 카테고리 축을 날짜(시간 스케일) 축으로 구성하여 날짜를 구성할 수 있도록 지원합니다. 일, 월, 년 단위의 데이터를 카테고리 축에 플로팅하려면 다음과 같은 다양한 속성을 사용할 수 있습니다:

  • BaseUnit: Days, Months, Years와 같은 기준 단위 값을 나타냅니다.

  • MajorUnit: 두 개의 주요 눈금(Major Tick) 사이의 간격 숫자 값을 나타냅니다.

  • MajorUnitScale: 카테고리 축의 주요 단위 스케일(Days, Months, Years)을 나타냅니다.

  • MinorUnit: 두 개의 보조 눈금(Minor Tick) 사이의 간격 숫자 값을 나타냅니다.

  • MinorUnitScale: 카테고리 축의 보조 단위 스케일(Days, Months, Years)을 나타냅니다.

기본 단위(BaseUnit)의 간격 차이는 차트 크기로 수용 가능한 가장 작은 단위 간의 차이를 의미합니다. 하지만 이 간격은 MajorUnitMinorUnit 속성을 사용하여 눈금 사이의 간격 숫자 값을 지정함으로써 사용자 지정할 수 있습니다.


아래 스크린샷은 서로 다른 세 브라우저에서 특정 웹페이지의 평균 조회 시간을 월 단위로 표시한 차트를 보여줍니다. 이 차트의 카테고리 축은 날짜 축으로 구성되었으며, BaseUnit은 월(Months)이고, 두 주요 눈금 사이의 간격 숫자(MajorUnit)는 2로 설정되어 있습니다.



// Spread 초기화
var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'), { sheetCount: 1 });
// activesheet 가져오기
var activeSheet = spread.getActiveSheet();
// 배열 생성
var dataArray = [
    ["", new Date(2019, 1, 1), new Date(2019, 2, 1), new Date(2019, 3, 1), new Date(2019, 4, 1), new Date(2019, 5, 1), new Date(2019, 6, 1)],
    ["Chrome", 5.782, 6.263, 7.766, 8.389, 9.830, 11.260],
    ["FireFox", 4.284, 4.130, 3.951, 3.760, 3.631, 3.504],
    ["IE", 2.814, 2.491, 2.455, 1.652, 1.073, 0.834],
];
// 열 너비 설정
for (var i = 0; i < 8; i++) {
    activeSheet.setColumnWidth(i, 80.0, GC.Spread.Sheets.SheetArea.viewport);
}
// 배열 설정
activeSheet.setArray(0, 0, dataArray);
// 범위에 대한 날짜 서식 설정
activeSheet.getRange(0, 0, 1, 7).formatter("m/d/yyyy");
// 차트 추가
var chart = activeSheet.charts.add('ChartWithDateAxis', GC.Spread.Sheets.Charts.ChartType.line, 2, 85, 400, 400, 'A1:G4');
// 차트 제목 설정
chart.title({ text: "Chart With Date Axis" });
// 차트 축 속성 설정\
var axes = chart.axes();

// primaryCategory, 즉 DateAxis 속성 설정
axes.primaryCategory.baseUnit = GC.Spread.Sheets.Charts.TimeUnit.months;
axes.primaryCategory.majorUnit = 1;
// axes.primaryCategory.minorUnit = 1;
axes.primaryCategory.majorUnitScale = GC.Spread.Sheets.Charts.TimeUnit.months;
// axes.primaryCategory.minorUnitScale = GC.Spread.Sheets.Charts.TimeUnit.days;

chart.axes(axes);

참고: 날짜 축에서는 시간(hour), 분(minute), 초(second) 단위는 지원되지 않습니다.

또한, minorUnitScale의 값이 majorUnitScale보다 클 경우, minorUnitScale은 동작하지 않습니다.

축 교차점 설정하기

Excel과 마찬가지로, 차트의 가로축 교차 값을 사용자 지정하여 차트의 시각적 구성을 변경할 수 있습니다.

차트에서 교차 축은 데이터 포인트가 양수와 음수 사이에 걸쳐 있는 경우, 데이터를 명확하게 표현하는 데 유용합니다.

이를 지원하기 위해 AxisCrossPoint 열거형은 다음과 같은 세 가지 옵션을 제공합니다:

  • automatic – 축의 교차점을 자동으로 설정

  • maximum – 축을 최대값에서 교차하도록 설정

  • minimum – 축을 최소값에서 교차하도록 설정

사용자는 primaryCategoryprimaryValue 클래스의 crossPoint 속성을 사용하여 교차 위치를 조정할 수 있습니다.


예를 들어, 다음의 사용 사례를 살펴보겠습니다:

사용자가 2012년을 기준으로, 성장률이 2%를 초과하거나 미달한 경우의 이익 금액을 평가하고자 한다고 가정합니다.

이를 표현하기 위해, 우리는 거품 차트를 사용하며, 각 거품은 특정 연도의 성장률(growth)이익 금액(profit) 을 나타냅니다. 거품 위에 마우스를 올리면, 해당 연도의 성장률과 이익 금액이 데이터 레이블로 표시됩니다.

  • primaryCategory (Y축)의 crossPoint2012로 설정

  • primaryValue (또는 X축)의 crossPoint2로 설정

이러한 교차점 설정을 통해, 사용자는 차트의 4사분면에서 ‘성장률’과 ‘이익 금액’ 데이터를 명확하게 구분하고 이해할 수 있습니다.

  • 왼쪽 상단 및 하단 사분면: 2012년 이전의 이익 금액(성장률이 2%를 초과하거나 미달한 경우)

  • 오른쪽 상단 및 하단 사분면: 2012년 이후의 이익 금액(성장률이 2%를 초과하거나 미달한 경우)



다음 코드 샘플은 SpreadJS 차트에서 교차 축을 구성하는 방법을 보여줍니다.

Ask ChatGPT

$(document).ready(function () {
    // Spread 초기화
    var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'), { sheetCount: 1 });
    // sheet 가져오기
    var sheet = spread.getSheet(0);
    sheet.suspendPaint();
    // column 너비 설정
    sheet.setColumnWidth(0, 80);
    sheet.setColumnWidth(1, 90);
    sheet.setColumnWidth(2, 110);
    // 데이터 배열 설정 
    var dataArray = [
        ["Year", "Growth (%)", "Profit Amount ($)"],
        [2000, 4, 3123123],
        [2001, -2, 4123123],
        [2002, 1, 8456456],
        [2003, 3, 2345435],
        [2004, 7, 1768678],
        [2005, 5, 5453456],
        [2006, 5, 6676878],
        [2007, -4, 7434234],
        [2008, 3, 3834234],
        [2009, 2, 6756756],
        [2010, 5, 5672123],
        [2011, 9, 9743546],
        [2012, 6, 3464513],
        [2013, 4, 7431545],
        [2014, 7, 7456456],
        [2015, -1, 4567687],
        [2016, 6, 4870231],
        [2017, 3, 4353453],
        [2018, 7, 3459021],
        [2019, 8, 2390123],
        [2020, 5, 2302303],
    ];
     // 데이터 배열 설정 
    sheet.setArray(0, 0, dataArray);
    // 차트 추가 
var chart = sheet.charts.add('BubbleChart1', GC.Spread.Sheets.Charts.ChartType.bubble, 320, 30, 620, 400, "A2:C22");
// 차트에서 눈금선 숨기기
var gridLinesAxes = chart.axes();
gridLinesAxes.primaryCategory.majorGridLine.visible = false;
gridLinesAxes.primaryValue.majorGridLine.visible = false;
chart.axes(gridLinesAxes);
// 시리즈를 가져와 패턴이 적용된 배경색 설정
var series = chart.series().get();
var seriesItem = series[0];
seriesItem.backColor = {
    type: GC.Spread.Sheets.Charts.PatternType.dottedPercent40,
    foregroundColor: "blue",
    backgroundColor: "lime",
}
chart.series().set(0, seriesItem);
// 차트 영역(ChartArea) 구성
var chartArea = chart.chartArea();
chartArea.backColor = "#FDF2E9";
chartArea.fontSize = 16;
// 차트 영역의 테두리 스타일 설정
chartArea.border.width = 3;
chartArea.border.color = "darkblue";
chart.chartArea(chartArea);
// 차트 제목 설정
var title = chart.title();
title.fontSize = "22.00";
title.text = "Growth and Profit of Hindco Pvt. Ltd.";
chart.title(title);
// 차트의 범례 숨기기
var legend = chart.legend();
legend.visible = false;
chart.legend(legend);
// x축 및 y축의 교차점(crossPoint) 설정
var axes = chart.axes();
axes.primaryCategory.crossPoint = 2012; // y축
axes.primaryValue.crossPoint = 2; // x축
chart.axes(axes);
// 셀 스타일 설정
var style = new GC.Spread.Sheets.Style();
style.font = "bold 12px Arial";
style.foreColor = "white";
style.backColor = "#5B9BD5";
style.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
style.vAlign = GC.Spread.Sheets.VerticalAlign.center;
for (var i = 0; i < 3; i++)
    sheet.setStyle(0, i, style, GC.Spread.Sheets.SheetArea.viewport);
sheet.resumePaint();

});

참고: 날짜 축에서는 교차 축 기능이 일시적으로 지원되지 않습니다.

축 방향 설정

차트 축의 방향을 제어할 수 있으며, 역순으로 표시하도록 설정할 수도 있습니다.

아래 이미지는 기본 방향과 역방향으로 설정된 기본 값 축을 보여줍니다.



orientation 속성은 0(기본 순서) 또는 1(역순)으로 설정할 수 있습니다. 또는 AxisOrientation 열거형의 minMax(기본값), maxMin(역방향) 값으로도 설정할 수 있습니다.

다음 코드 샘플은 차트에서 기본 및 역방향 축 방향을 설정하는 방법을 보여줍니다.

var axesMin = minMaxChart.axes();
axesMin.primaryValue.scaling = {
    orientation: GC.Spread.Sheets.Charts.AxisOrientation.minMax
    // 또는
    //orientation: 0
};
minMaxChart.axes(axesMin);

var axesMax = maxMinChart.axes();
axesMax.primaryValue.scaling = {
    orientation: GC.Spread.Sheets.Charts.AxisOrientation.maxMin
    // 또는 
    //orientation: 1
};
maxMinChart.axes(axesMax);

제한 사항: 원형, 선버스트, 트리맵, 깔때기형 차트에서는 축 방향을 설정할 수 없습니다.

축 레이블 위치 설정

tickLabelPosition 속성을 사용하여 차트에서 축 데이터 레이블의 위치를 설정할 수 있습니다.

TickLabelPosition 열거형을 사용하여 다음 위치 중 하나로 설정할 수 있습니다:

  • High 또는 0: 차트의 위쪽 또는 오른쪽

  • Low 또는 1: 차트의 아래쪽 또는 왼쪽

  • Next to Axis 또는 2: 축 옆 (차트의 가장자리에 축이 위치하지 않은 경우, 기본값)

  • None 또는 3: 눈금 레이블 없음

아래 이미지는 기본 위치와 High 위치로 설정된 기본 범주 축의 데이터 레이블을 보여줍니다.



다음 코드 샘플은 차트에서 기본 및 상단 위치의 축 데이터 레이블을 설정하는 방법을 보여줍니다.

// 차트 축 속성 설정
var axesTickDefault = chart.axes();
// tickLabelPosition을 기본값 nextToAxis로 설정
axesTickDefault.primaryCategory.tickLabelPosition = GC.Spread.Sheets.Charts.TickLabelPosition.nextToAxis;
// 또는
// axesTickDefault.primaryCategory.tickLabelPosition = 2;
chart.axes(axesTickDefault);

var axesTickHigh = chart.axes();
// tickLabelPosition을 High로 설정
axesTickHigh.primaryCategory.tickLabelPosition = GC.Spread.Sheets.Charts.TickLabelPosition.high;
// 또는
// axesTickDefault.primaryCategory.tickLabelPosition = 0;
chart.axes(axesTickHigh);

축 레이블 각도 설정

labelAngle 속성은 차트에서 축 데이터 레이블의 회전 각도를 제어합니다.

이 숫자 속성은 -90도에서 90도 사이의 값을 허용하며, 다음과 같은 조건이 있습니다:

  • 기본값: undefined (회전 없음)

  • 최대값: 90 (시계 방향으로 90도 회전)

  • 최소값: -90 (반시계 방향으로 90도 회전)

아래 이미지는 기본 각도와 45도 각도로 설정된 기본 범주 축의 데이터 레이블을 보여줍니다.

image.e0afe5

다음 코드 샘플은 차트에서 데이터 레이블 각도를 90도로 설정하는 방법을 보여줍니다.

var dataArray = [
    ['Manufacturer', 'Kia', 'Hyundai', 'Toyota', 'Nissan', 'Honda', 'Volkswagen', 'BMW', 'Mercedes', 'Audi', 'Renault'],
    ['Sales', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
];
sheet.setArray(0, 0, dataArray);
var chart = sheet.charts.add('chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 450, 100, 400, 400, "A1:K2");
var axesTemp = chart.axes();
axesTemp.primaryCategory.labelAngle = 90;
chart.axes(axesTemp);

SpreadJS 디자이너에서 축 레이블 각도 설정

image.3a5152

축 레이블 간격 설정

차트 축의 레이블 간 간격은 연속된 레이블 사이의 간격을 제어합니다. 이 기능은 레이블의 밀도를 조절하여, 겹치거나 과밀해지는 것을 방지하고 데이터를 명확하게 표현할 수 있도록 도와줍니다.


Excel의 기능과 유사하게 기본값 또는 사용자 지정 값으로 간격 단위를 설정할 수 있습니다. GC.Spread.Sheets.Charts.IAxis 인터페이스의 tickLabelSpacing 속성을 사용하여 사용자 지정 간격 단위를 생성할 수 있습니다. tickLabelSpacing 속성의 기본값은 1이며, 차트에 모든 레이블을 표시합니다.


아래 이미지는 기본 레이블과 간격이 설정된 기본 범주 축 레이블을 보여줍니다.

Single level axis label intervals.b18fac


다음 코드 샘플은 차트에서 기본 범주 축 레이블 간의 간격을 설정하는 방법을 보여줍니다.

// 축 레이블 간 간격 설정
var dataArray = [
['Manufacturer', 'Kia', 'Hyundai', 'Toyota', 'Nissan', 'Honda', 'Volkswagen', 'BMW', 'Mercedes', 'Audi', 'Renault'],
['Sales', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
];
sheet.setArray(0, 0, dataArray);
var chart = sheet.charts.add('chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 450, 100, 400, 400, "A1:K2");
let axesTemp = chart.axes();
axesTemp.primaryCategory.tickLabelSpacing = 2;
chart.axes(axesTemp);

또한, 다단계 축 레이블이 있는 차트의 경우 tickLabelSpacing 속성은 마지막 단계의 카테고리 필드에 바인딩된 리프 노드(leaf nodes)에 적용됩니다.

리프 노드는 트리 구조의 마지막 노드를 의미합니다.

상위 수준의 축 레이블 표시 여부는 자식 레이블의 첫 번째 항목 상태에 따라 결정됩니다:

  • 첫 번째 자식 축 레이블이 표시되면, 해당 부모 축 레이블도 표시됩니다.

  • 첫 번째 자식 축 레이블이 숨겨지면, 해당 부모 축 레이블도 숨겨집니다.

아래 이미지는 다단계 축 레이블에서 기본 간격 및 간격 설정이 적용된 예시를 보여줍니다.

Multi level axis label intervals.9f1633


다음 코드 샘플은 차트에서 다단계 축 레이블 간 간격을 설정하는 방법을 보여줍니다.

// 다단계 축 레이블 간 간격 설정
var dataArray = [
['Country', 'Korea', 'Japan', 'Germany', 'France'],
['Manufacturer', 'Kia', 'Hyundai', 'Toyota', 'Nissan', 'Honda', 'Volkswagen', 'BMW', 'Mercedes', 'Audi', 'Renault'],
['Sales', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
];
sheet.setArray(0, 0, dataArray);
var chart = sheet.charts.add('chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 150, 100, 400, 400, "B1:K3");
let axesTemp = chart.axes();
axesTemp.primaryCategory.tickLabelSpacing = 3;
chart.axes(axesTemp);

제한 사항

  • 날짜 또는 숫자 축을 포함하는 차트에서는 tickLabelSpacing 속성 설정이 지원되지 않습니다.

  • tickLabelSpacing 속성은 선버스트, 트리맵, 폭포수, 깔대기형, 방사형 차트에서 지원되지 않습니다.

  • tickLabelSpacing 속성이 undefined로 설정된 상태에서 차트 크기를 줄이면 Excel은 자동으로 레이블 간격을 조절합니다.

    하지만 SpreadJS는 현재 이러한 정책을 사용하지 않습니다.