cellmerged.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX files. Support reads and writes XLSX file generated by
  7. // Microsoft Excel™ 2007 and later. Support save file without losing original
  8. // charts of XLSX. This library needs Go version 1.10 or later.
  9. package excelize
  10. import (
  11. "fmt"
  12. "strings"
  13. )
  14. // MergeCell provides a function to merge cells by given coordinate area and
  15. // sheet name. For example create a merged cell of D3:E9 on Sheet1:
  16. //
  17. // err := f.MergeCell("Sheet1", "D3", "E9")
  18. //
  19. // If you create a merged cell that overlaps with another existing merged cell,
  20. // those merged cells that already exist will be removed.
  21. //
  22. // B1(x1,y1) D1(x2,y1)
  23. // +--------------------------------+
  24. // | |
  25. // | |
  26. // A4(x3,y3) | C4(x4,y3) |
  27. // +-----------------------------+ |
  28. // | | | |
  29. // | | | |
  30. // | |B5(x1,y2) | D5(x2,y2)|
  31. // | +--------------------------------+
  32. // | |
  33. // | |
  34. // |A8(x3,y4) C8(x4,y4)|
  35. // +-----------------------------+
  36. //
  37. func (f *File) MergeCell(sheet, hcell, vcell string) error {
  38. rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
  39. if err != nil {
  40. return err
  41. }
  42. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  43. if rect1[2] < rect1[0] {
  44. rect1[0], rect1[2] = rect1[2], rect1[0]
  45. }
  46. if rect1[3] < rect1[1] {
  47. rect1[1], rect1[3] = rect1[3], rect1[1]
  48. }
  49. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  50. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  51. xlsx, err := f.workSheetReader(sheet)
  52. if err != nil {
  53. return err
  54. }
  55. ref := hcell + ":" + vcell
  56. if xlsx.MergeCells != nil {
  57. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  58. cellData := xlsx.MergeCells.Cells[i]
  59. if cellData == nil {
  60. continue
  61. }
  62. cc := strings.Split(cellData.Ref, ":")
  63. if len(cc) != 2 {
  64. return fmt.Errorf("invalid area %q", cellData.Ref)
  65. }
  66. rect2, err := f.areaRefToCoordinates(cellData.Ref)
  67. if err != nil {
  68. return err
  69. }
  70. // Delete the merged cells of the overlapping area.
  71. if isOverlap(rect1, rect2) {
  72. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  73. i--
  74. if rect1[0] > rect2[0] {
  75. rect1[0], rect2[0] = rect2[0], rect1[0]
  76. }
  77. if rect1[2] < rect2[2] {
  78. rect1[2], rect2[2] = rect2[2], rect1[2]
  79. }
  80. if rect1[1] > rect2[1] {
  81. rect1[1], rect2[1] = rect2[1], rect1[1]
  82. }
  83. if rect1[3] < rect2[3] {
  84. rect1[3], rect2[3] = rect2[3], rect1[3]
  85. }
  86. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  87. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  88. ref = hcell + ":" + vcell
  89. }
  90. }
  91. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &xlsxMergeCell{Ref: ref})
  92. } else {
  93. xlsx.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref}}}
  94. }
  95. return err
  96. }
  97. // UnmergeCell provides a function to unmerge a given coordinate area.
  98. // For example unmerge area D3:E9 on Sheet1:
  99. //
  100. // err := f.UnmergeCell("Sheet1", "D3", "E9")
  101. //
  102. // Attention: overlapped areas will also be unmerged.
  103. func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
  104. xlsx, err := f.workSheetReader(sheet)
  105. if err != nil {
  106. return err
  107. }
  108. rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
  109. if err != nil {
  110. return err
  111. }
  112. if rect1[2] < rect1[0] {
  113. rect1[0], rect1[2] = rect1[2], rect1[0]
  114. }
  115. if rect1[3] < rect1[1] {
  116. rect1[1], rect1[3] = rect1[3], rect1[1]
  117. }
  118. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  119. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  120. // return nil since no MergeCells in the sheet
  121. if xlsx.MergeCells == nil {
  122. return nil
  123. }
  124. i := 0
  125. for _, cellData := range xlsx.MergeCells.Cells {
  126. if cellData == nil {
  127. continue
  128. }
  129. cc := strings.Split(cellData.Ref, ":")
  130. if len(cc) != 2 {
  131. return fmt.Errorf("invalid area %q", cellData.Ref)
  132. }
  133. rect2, err := f.areaRefToCoordinates(cellData.Ref)
  134. if err != nil {
  135. return err
  136. }
  137. if isOverlap(rect1, rect2) {
  138. continue
  139. }
  140. xlsx.MergeCells.Cells[i] = cellData
  141. i++
  142. }
  143. xlsx.MergeCells.Cells = xlsx.MergeCells.Cells[:i]
  144. return nil
  145. }
  146. // GetMergeCells provides a function to get all merged cells from a worksheet
  147. // currently.
  148. func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
  149. var mergeCells []MergeCell
  150. xlsx, err := f.workSheetReader(sheet)
  151. if err != nil {
  152. return mergeCells, err
  153. }
  154. if xlsx.MergeCells != nil {
  155. mergeCells = make([]MergeCell, 0, len(xlsx.MergeCells.Cells))
  156. for i := range xlsx.MergeCells.Cells {
  157. ref := xlsx.MergeCells.Cells[i].Ref
  158. axis := strings.Split(ref, ":")[0]
  159. val, _ := f.GetCellValue(sheet, axis)
  160. mergeCells = append(mergeCells, []string{ref, val})
  161. }
  162. }
  163. return mergeCells, err
  164. }
  165. // MergeCell define a merged cell data.
  166. // It consists of the following structure.
  167. // example: []string{"D4:E10", "cell value"}
  168. type MergeCell []string
  169. // GetCellValue returns merged cell value.
  170. func (m *MergeCell) GetCellValue() string {
  171. return (*m)[1]
  172. }
  173. // GetStartAxis returns the merge start axis.
  174. // example: "C2"
  175. func (m *MergeCell) GetStartAxis() string {
  176. axis := strings.Split((*m)[0], ":")
  177. return axis[0]
  178. }
  179. // GetEndAxis returns the merge end axis.
  180. // example: "D4"
  181. func (m *MergeCell) GetEndAxis() string {
  182. axis := strings.Split((*m)[0], ":")
  183. return axis[1]
  184. }